mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Apply skew in infra lofts #6386
This commit is contained in:
@@ -63,31 +63,37 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
auto relative_dist_along = (dist_along - *profile_index) / (*(profile_index + 1) - *profile_index);
|
||||
const auto& profile_a = cross_sections[std::distance(longitudes.begin(), profile_index)].section_geometry;
|
||||
const auto& offset_a = cross_sections[std::distance(longitudes.begin(), profile_index)].offset;
|
||||
const auto& rotation_a = cross_sections[std::distance(longitudes.begin(), profile_index)].rotation;
|
||||
|
||||
taxonomy::geom_item::ptr interpolated = nullptr;
|
||||
|
||||
// Only interpolate if:
|
||||
// - there is a profile ahead of us, and
|
||||
// - we're not exactly at the location of the current profile or whether there is an offset involved.
|
||||
// - we're not exactly at the location of the current profile or whether there is an offset involved
|
||||
bool should_interpolate =
|
||||
(profile_index + 1 < longitudes.end()) &&
|
||||
(relative_dist_along >= 1.e-9 || offset_a.cwiseAbs().maxCoeff() > 0.);
|
||||
(relative_dist_along >= 1.e-9 || offset_a.cwiseAbs().maxCoeff() > 0. || rotation_a);
|
||||
|
||||
boost::optional<Eigen::Matrix3d> interpolated_rotation;
|
||||
|
||||
if (should_interpolate) {
|
||||
taxonomy::geom_item::ptr profile_b;
|
||||
Eigen::Vector3d offset_b;
|
||||
boost::optional<Eigen::Matrix3d> rotation_b;
|
||||
if ((profile_index + 1 < longitudes.end())) {
|
||||
profile_b = cross_sections[std::distance(longitudes.begin(), profile_index) + 1].section_geometry;
|
||||
offset_b = cross_sections[std::distance(longitudes.begin(), profile_index) + 1].offset;
|
||||
rotation_b = cross_sections[std::distance(longitudes.begin(), profile_index) + 1].rotation;
|
||||
} else {
|
||||
profile_b = profile_a;
|
||||
offset_b = offset_a;
|
||||
rotation_b = rotation_a;
|
||||
}
|
||||
|
||||
// Only interpolate if the profiles are different or either of the offsets is non-zero
|
||||
bool should_interpolate2 =
|
||||
(profile_a->instance != profile_b->instance) ||
|
||||
(offset_a.cwiseAbs().maxCoeff() > 0. || offset_b.cwiseAbs().maxCoeff() > 0.);
|
||||
(offset_a.cwiseAbs().maxCoeff() > 0. || offset_b.cwiseAbs().maxCoeff() > 0. || rotation_b);
|
||||
|
||||
if (should_interpolate2) {
|
||||
|
||||
@@ -130,6 +136,13 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
}
|
||||
|
||||
auto interpolated_offset = lerp(offset_a, offset_b, relative_dist_along);
|
||||
if (rotation_a && rotation_b) {
|
||||
// @todo we don't support an overridden rotation on only one of the placements
|
||||
// in which case we would need to lerp with the rotation component below in m4b.
|
||||
interpolated_rotation = lerp(*rotation_a, *rotation_b, relative_dist_along);
|
||||
} else {
|
||||
Logger::Error("Direction vectors on cross section placements only supported when used consistently");
|
||||
}
|
||||
taxonomy::loop::ptr w1, w2;
|
||||
taxonomy::edge::ptr e1, e2;
|
||||
for (auto tmp_ : boost::combine(loops_a, loops_b)) {
|
||||
@@ -149,6 +162,7 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
auto& p2 = boost::get<taxonomy::point3::ptr>(e2->start);
|
||||
|
||||
auto p3 = (lerp(p1->ccomponents(), p2->ccomponents(), relative_dist_along) + interpolated_offset).eval();
|
||||
// auto p4 = (interpolated_rotation * p3).eval();
|
||||
points.push_back(taxonomy::make<taxonomy::point3>(p3));
|
||||
}
|
||||
if (!points.empty()) {
|
||||
@@ -173,9 +187,16 @@ taxonomy::loft::ptr ifcopenshell::geometry::make_loft(const Settings& settings_,
|
||||
}*/
|
||||
|
||||
Eigen::Matrix4d m4b = Eigen::Matrix4d::Identity();
|
||||
m4b.col(0).head<3>() = m4.col(1).head<3>().normalized();
|
||||
m4b.col(1).head<3>() = m4.col(2).head<3>().normalized();
|
||||
m4b.col(2).head<3>() = m4.col(0).head<3>().normalized();
|
||||
if (interpolated_rotation) {
|
||||
// direction vectors on the linear placement overwrite the placement otherwise inferred from the tangent
|
||||
m4b.col(0).head<3>() = interpolated_rotation->col(1);
|
||||
m4b.col(1).head<3>() = interpolated_rotation->col(2);
|
||||
m4b.col(2).head<3>() = interpolated_rotation->col(0);
|
||||
} else {
|
||||
m4b.col(0).head<3>() = m4.col(1).head<3>().normalized();
|
||||
m4b.col(1).head<3>() = m4.col(2).head<3>().normalized();
|
||||
m4b.col(2).head<3>() = m4.col(0).head<3>().normalized();
|
||||
}
|
||||
m4b.col(3).head<3>() = m4.col(3).head<3>();
|
||||
|
||||
if (interpolated) {
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace ifcopenshell {
|
||||
double dist_along;
|
||||
taxonomy::geom_item::ptr section_geometry;
|
||||
Eigen::Vector3d offset;
|
||||
boost::optional<Eigen::Matrix3d> rotation;
|
||||
|
||||
bool operator <(const cross_section& other) const {
|
||||
return dist_along < other.dist_along;
|
||||
|
||||
@@ -49,6 +49,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal* in
|
||||
// The longitudes determine the range of the sweep and the offsets are interpolated in between
|
||||
// sweep segments.
|
||||
std::vector<Eigen::Vector3d> profile_offsets;
|
||||
std::vector<boost::optional<Eigen::Matrix3d>> profile_rotations;
|
||||
std::vector<double> longitudes;
|
||||
|
||||
for (auto& cs : *css) {
|
||||
@@ -69,6 +70,19 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal* in
|
||||
);
|
||||
|
||||
profile_offsets.push_back(po);
|
||||
|
||||
boost::optional<Eigen::Matrix3d> rot;
|
||||
if (csp->Axis() && csp->RefDirection()) {
|
||||
rot = taxonomy::matrix4(
|
||||
Eigen::Vector3d(0, 0, 0),
|
||||
taxonomy::cast<taxonomy::direction3>(map(csp->Axis()))->ccomponents(),
|
||||
taxonomy::cast<taxonomy::direction3>(map(csp->RefDirection()))->ccomponents()).ccomponents().block<3,3>(0,0);
|
||||
} else if (csp->Axis()) {
|
||||
rot = taxonomy::matrix4(
|
||||
Eigen::Vector3d(0, 0, 0),
|
||||
taxonomy::cast<taxonomy::direction3>(map(csp->Axis()))->ccomponents()).ccomponents().block<3, 3>(0, 0);
|
||||
}
|
||||
profile_rotations.push_back(rot);
|
||||
}
|
||||
if (faces.size() != profile_offsets.size()) {
|
||||
Logger::Warning("Expected CrossSections and CrossSectionPositions to be equal length, but got " + std::to_string(faces.size()) + " and " + std::to_string(profile_offsets.size()) + " respectively", inst);
|
||||
@@ -80,7 +94,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSolidHorizontal* in
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < faces.size(); ++i) {
|
||||
cross_sections.push_back({ longitudes[i], faces[i], profile_offsets[i] });
|
||||
cross_sections.push_back({ longitudes[i], faces[i], profile_offsets[i], profile_rotations[i]});
|
||||
}
|
||||
#else
|
||||
return nullptr;
|
||||
|
||||
@@ -49,6 +49,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSurface* inst) {
|
||||
// The longitudes determine the range of the sweep and the offsets are interpolated in between
|
||||
// sweep segments.
|
||||
std::vector<Eigen::Vector3d> profile_offsets;
|
||||
std::vector<boost::optional<Eigen::Matrix3d>> profile_rotations;
|
||||
std::vector<double> longitudes;
|
||||
|
||||
for (auto& cs : *css) {
|
||||
@@ -69,6 +70,19 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSurface* inst) {
|
||||
);
|
||||
|
||||
profile_offsets.push_back(po);
|
||||
|
||||
boost::optional<Eigen::Matrix3d> rot;
|
||||
if (csp->Axis() && csp->RefDirection()) {
|
||||
rot = taxonomy::matrix4(
|
||||
Eigen::Vector3d(0, 0, 0),
|
||||
taxonomy::cast<taxonomy::direction3>(map(csp->Axis()))->ccomponents(),
|
||||
taxonomy::cast<taxonomy::direction3>(map(csp->RefDirection()))->ccomponents()).ccomponents().block<3, 3>(0, 0);
|
||||
} else if (csp->Axis()) {
|
||||
rot = taxonomy::matrix4(
|
||||
Eigen::Vector3d(0, 0, 0),
|
||||
taxonomy::cast<taxonomy::direction3>(map(csp->Axis()))->ccomponents()).ccomponents().block<3, 3>(0, 0);
|
||||
}
|
||||
profile_rotations.push_back(rot);
|
||||
}
|
||||
#else
|
||||
return nullptr;
|
||||
@@ -83,7 +97,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSectionedSurface* inst) {
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < faces.size(); ++i) {
|
||||
cross_sections.push_back({ longitudes[i], faces[i], profile_offsets[i] });
|
||||
cross_sections.push_back({ longitudes[i], faces[i], profile_offsets[i], profile_rotations[i] });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user