Move sweep directrix closer to origin #7408

This commit is contained in:
Thomas Krijnen
2025-11-30 09:56:19 +01:00
parent 8d617c87c8
commit bd57cc8735
2 changed files with 76 additions and 34 deletions
@@ -84,6 +84,50 @@ namespace {
}
bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, TopoDS_Shape& result) {
using namespace ifcopenshell::geometry;
bool applied_temporary_offset = false;
Eigen::Vector3d mean;
auto curve = scs->curve;
// Apply temporary offset if the geometry is far away from origin
// Re: https://github.com/IfcOpenShell/IfcOpenShell/issues/7408
// The norm2 that used as a treshold is actually really small though
// is this a coincedence that it solves the problem in this one test case?
if (curve->kind() == taxonomy::LOOP && std::dynamic_pointer_cast<taxonomy::loop>(curve)->is_polyhedron()) {
Eigen::Vector3d sum = Eigen::Vector3d::Zero();
size_t count = 0;
visit_2<taxonomy::point3, taxonomy::loop>(std::dynamic_pointer_cast<taxonomy::loop>(curve), [&](const taxonomy::point3::ptr& p) {
const Eigen::Vector3d& coords = p->ccomponents();
sum += coords;
++count;
});
mean = (count > 0) ? (sum / static_cast<double>(count)).eval() : Eigen::Vector3d::Zero().eval();
if (mean.norm() > 1.e2) {
curve = taxonomy::loop::ptr((taxonomy::loop*)scs->curve->clone_());
applied_temporary_offset = true;
std::set<taxonomy::point3::ptr> unique_points;
for (auto& e : std::dynamic_pointer_cast<taxonomy::loop>(curve)->children) {
auto* a = boost::get<taxonomy::point3::ptr>(&e->start);
auto* b = boost::get<taxonomy::point3::ptr>(&e->end);
if (a) {
unique_points.insert(*a);
}
if (b) {
unique_points.insert(*b);
}
}
for (auto& p : unique_points) {
p->components() -= mean;
}
}
}
auto w = convert_curve(scs->curve);
if (w.which() != 2) {
Logger::Error("Unsupported directrix");
@@ -207,13 +251,13 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
for (int i = 0; i < 2; ++i) {
for (TopExp_Explorer exp(face, TopAbs_WIRE); exp.More(); exp.Next()) {
const auto& section = TopoDS::Wire(exp.Current());
if (section.IsSame(outer) != i == 0) {
if (section.IsSame(outer) != (i == 0)) {
continue;
}
BRepOffsetAPI_MakePipeShell builder(wire);
builder.Add(section);
builder.SetTransitionMode(contains_circular_segments(wire) && wire_is_c1_continuous(wire, 1.e-2) ? BRepBuilderAPI_Transformed : BRepBuilderAPI_RightCorner);
builder.SetTransitionMode(contains_circular_segments(wire) && wire_is_c1_continuous(wire, 1.e-2) ? BRepBuilderAPI_Transformed : BRepBuilderAPI_RightCorner);
if (directrix_on_plane) {
builder.SetMode(pln.Axis().Direction());
} else if (!is_plane) {
@@ -238,8 +282,8 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
mf1.reset(new BRepBuilderAPI_MakeFace(f1));
}
for (TopExp_Explorer exp(builder.Shape(), TopAbs_FACE); exp.More(); exp.Next()) {
BB.Add(comp, exp.Current());
for (TopExp_Explorer exp2(builder.Shape(), TopAbs_FACE); exp2.More(); exp2.Next()) {
BB.Add(comp, exp2.Current());
}
}
}
@@ -254,6 +298,12 @@ bool OpenCascadeKernel::convert(const taxonomy::sweep_along_curve::ptr scs, Topo
result = BRepBuilderAPI_MakeSolid(comp).Solid();
if (applied_temporary_offset) {
gp_Trsf trsf;
trsf.SetTranslation(gp_Vec(-mean.x(), -mean.y(), -mean.z()));
result.Move(trsf);
}
return true;
}
+22 -30
View File
@@ -1649,42 +1649,34 @@ typedef item const* ptr;
}
template <typename T, typename U, typename Fn>
void visit_2(const typename U::ptr& c, const Fn& fn) {
void visit_2(const typename U::ptr& collection, const Fn& fn) {
static_assert(std::is_same<T, taxonomy::point3>::value, "@todo Only implemented for point3");
for (auto& i : c->children) {
for (auto& child : collection->children) {
// @todo Sad... now that we have templated collection members,
// we can't generally use collection_base anymore as a cast target.
if (auto s = taxonomy::dcast<taxonomy::collection>(i)) {
visit_2<T, taxonomy::collection>(s, fn);
}
else if (auto s = taxonomy::dcast<taxonomy::loop>(i)) {
visit_2<T, taxonomy::loop>(s, fn);
}
else if (auto s = taxonomy::dcast<taxonomy::face>(i)) {
visit_2<T, taxonomy::face>(s, fn);
}
else if (auto s = taxonomy::dcast<taxonomy::shell>(i)) {
visit_2<T, taxonomy::shell>(s, fn);
}
else if (auto s = taxonomy::dcast<taxonomy::solid>(i)) {
visit_2<T, taxonomy::solid>(s, fn);
}
else if (auto s = taxonomy::dcast<taxonomy::loft>(i)) {
visit_2<T, taxonomy::loft>(s, fn);
}
else if (auto s = taxonomy::dcast<taxonomy::boolean_result>(i)) {
visit_2<T, taxonomy::boolean_result>(s, fn);
}
else if (auto pt = taxonomy::dcast<taxonomy::point3>(i)) {
if (auto col = std::dynamic_pointer_cast<taxonomy::collection>(child)) {
visit_2<T, taxonomy::collection>(col, fn);
} else if (auto loop = std::dynamic_pointer_cast<taxonomy::loop>(child)) {
visit_2<T, taxonomy::loop>(loop, fn);
} else if (auto face = std::dynamic_pointer_cast<taxonomy::face>(child)) {
visit_2<T, taxonomy::face>(face, fn);
} else if (auto shell = std::dynamic_pointer_cast<taxonomy::shell>(child)) {
visit_2<T, taxonomy::shell>(shell, fn);
} else if (auto solid = std::dynamic_pointer_cast<taxonomy::solid>(child)) {
visit_2<T, taxonomy::solid>(solid, fn);
} else if (auto loft = std::dynamic_pointer_cast<taxonomy::loft>(child)) {
visit_2<T, taxonomy::loft>(loft, fn);
} else if (auto bl = std::dynamic_pointer_cast<taxonomy::boolean_result>(child)) {
visit_2<T, taxonomy::boolean_result>(bl, fn);
} else if (auto pt = std::dynamic_pointer_cast<taxonomy::point3>(child)) {
fn(pt);
}
else if (auto l = taxonomy::dcast<taxonomy::edge>(i)) {
} else if (auto ed = std::dynamic_pointer_cast<taxonomy::edge>(child)) {
// @todo maybe make edge a collection then as well?
if (l->start.which() == 1) {
fn(boost::get<taxonomy::point3::ptr>(l->start));
if (ed->start.which() == 1) {
fn(boost::get<taxonomy::point3::ptr>(ed->start));
}
if (l->end.which() == 1) {
fn(boost::get<taxonomy::point3::ptr>(l->end));
if (ed->end.which() == 1) {
fn(boost::get<taxonomy::point3::ptr>(ed->end));
}
}
}