From 139b83ea0c35de9c13fedbf27484744a1744fc6b Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 10 Dec 2024 21:30:43 +0100 Subject: [PATCH] Re-enable remove_duplicate_points_from_loop --- src/ifcgeom/mapping/IfcPolyLoop.cpp | 26 +++++--------------------- src/ifcgeom/mapping/IfcPolyline.cpp | 18 ++++++++++++++---- src/ifcgeom/profile_helper.cpp | 26 ++++++++++++++++++++++++++ src/ifcgeom/profile_helper.h | 2 ++ 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/src/ifcgeom/mapping/IfcPolyLoop.cpp b/src/ifcgeom/mapping/IfcPolyLoop.cpp index 34f7ad1aa3..1149bd64bd 100644 --- a/src/ifcgeom/mapping/IfcPolyLoop.cpp +++ b/src/ifcgeom/mapping/IfcPolyLoop.cpp @@ -42,7 +42,11 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolyLoop* inst) { // @todo Remove points that are too close to one another const double eps = settings_.get().get(); - // util::remove_duplicate_points_from_loop(polygon, true, eps); + auto previous_size = polygon.size(); + remove_duplicate_points_from_loop(polygon, true, eps); + if (polygon.size() != previous_size) { + Logger::Warning("Removed " + std::to_string(previous_size - polygon.size()) + " (near) duplicate points from:", inst); + } int count = polygon.size(); if (original_count - count != 0) { @@ -59,24 +63,4 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolyLoop* inst) { polygon.push_back(polygon.front()); return polygon_from_points(polygon); - - // @todo make sure wire intersection check happens - - /* - BRepBuilderAPI_MakePolygon w; - for (int i = 1; i <= polygon.Length(); ++i) { - w.Add(polygon.Value(i)); - } - w.Close(); - - result = w.Wire(); - - TopTools_ListOfShape results; - if (getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(result, results, {getValue(GV_NO_WIRE_INTERSECTION_CHECK) < 0., getValue(GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., getValue(GV_PRECISION)})) { - Logger::Error("Self-intersections with " + boost::lexical_cast(results.Extent()) + " cycles detected", l); - util::select_largest(results, result); - } - - return true; - */ } diff --git a/src/ifcgeom/mapping/IfcPolyline.cpp b/src/ifcgeom/mapping/IfcPolyline.cpp index 220a0cd936..a55a6d3d7d 100644 --- a/src/ifcgeom/mapping/IfcPolyline.cpp +++ b/src/ifcgeom/mapping/IfcPolyline.cpp @@ -33,19 +33,29 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolyline* inst) { return taxonomy::cast(map(p)); }); - const bool closed_by_proximity = polygon.size() >= 3 && (*polygon.front()->components_ - *polygon.back()->components_).norm() < settings_.get().get(); + auto eps = this->settings_.get().get(); + + const bool closed_by_proximity = polygon.size() >= 3 && (polygon.front()->ccomponents() - polygon.back()->ccomponents()).norm() < eps; if (closed_by_proximity) { polygon.resize(polygon.size() - 1); - polygon.push_back(polygon.front()); } - // @todo Remove points that are too close to one another - // util::remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); + // Remove points that are too close to one another + auto previous_size = polygon.size(); + remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); + if (polygon.size() != previous_size) { + Logger::Warning("Removed " + std::to_string(previous_size - polygon.size()) + " (near) duplicate points from:", inst); + } if (polygon.size() < 2) { // We somehow need to signal we fail this curve on purpose not to trigger an error. + Logger::Warning("Invalid polyline with " + std::to_string(polygon.size()) + " points:", inst); return nullptr; } + if (closed_by_proximity) { + polygon.push_back(polygon.front()); + } + return polygon_from_points(polygon); } diff --git a/src/ifcgeom/profile_helper.cpp b/src/ifcgeom/profile_helper.cpp index 5c14259f65..eaa04e96e0 100644 --- a/src/ifcgeom/profile_helper.cpp +++ b/src/ifcgeom/profile_helper.cpp @@ -54,6 +54,32 @@ taxonomy::loop::ptr ifcopenshell::geometry::fillet_loop(taxonomy::loop::ptr loop return loop; } +void ifcopenshell::geometry::remove_duplicate_points_from_loop(std::vector& polygon, bool closed, double tol) { + tol *= tol; + + for (;;) { + bool removed = false; + int n = polygon.size() - (closed ? 0 : 1); + for (size_t i = 0; i < n; ++i) { + // wrap around to the first point in case of a closed loop + auto j = (i + 1) % polygon.size(); + double dist = (polygon[i]->ccomponents() - polygon[j]->ccomponents()).squaredNorm(); + if (dist < tol) { + // do not remove the first or last point to + // maintain connectivity with other wires + if ((closed && j == 0) || (!closed && j == (n - 1))) { + polygon.erase(polygon.begin() + i); + } else { + polygon.erase(polygon.begin() + j); + } + removed = true; + break; + } + } + if (!removed) break; + } +} + taxonomy::loop::ptr ifcopenshell::geometry::polygon_from_points(const std::vector& ps, bool external) { auto loop = taxonomy::make(); loop->external = external; diff --git a/src/ifcgeom/profile_helper.h b/src/ifcgeom/profile_helper.h index aa4d6a100f..4f11519def 100644 --- a/src/ifcgeom/profile_helper.h +++ b/src/ifcgeom/profile_helper.h @@ -28,6 +28,8 @@ namespace ifcopenshell { taxonomy::loop::ptr profile_helper(const taxonomy::matrix4::ptr& m4, const std::vector& points); taxonomy::loop::ptr fillet_loop(taxonomy::loop::ptr lp, double radius); + + void remove_duplicate_points_from_loop(std::vector& polygon, bool closed, double tol); } }