diff --git a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp index 99d1ee1d17..a73027edda 100644 --- a/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp +++ b/src/ifcgeom/kernel_agnostic/AbstractKernel.cpp @@ -31,7 +31,12 @@ namespace { } bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::item* item, ifcopenshell::geometry::ConversionResults& results) { - return dispatch_conversion<0>::dispatch(this, item, results); + try { + return dispatch_conversion<0>::dispatch(this, item, results); + } catch (std::exception& e) { + Logger::Error(e, item->instance); + return false; + } } ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, IfcParse::IfcFile* file) { diff --git a/src/ifcgeom/schema/mapping.cpp b/src/ifcgeom/schema/mapping.cpp index 33919e8b90..ae2645c4bc 100644 --- a/src/ifcgeom/schema/mapping.cpp +++ b/src/ifcgeom/schema/mapping.cpp @@ -1009,6 +1009,20 @@ namespace { boost::optional radius; profile_point* previous, *next; }; + + taxonomy::loop* polygon_from_points(const std::vector& ps) { + auto loop = new taxonomy::loop(); + auto previous = ps.back(); + for (auto& p : ps) { + auto e = new taxonomy::edge; + e->start = previous; + e->end = p; + previous = p; + loop->children.push_back(e); + } + return loop; + } + taxonomy::loop* profile_helper(mapping* self, const IfcSchema::IfcParameterizedProfileDef* inst, const std::vector& points) { /* TopoDS_Vertex* vertices = new TopoDS_Vertex[numVerts]; @@ -1070,17 +1084,7 @@ namespace { } }); - auto loop = new taxonomy::loop(); - auto previous = ps.back(); - for (auto& p : ps) { - auto e = new taxonomy::edge; - e->start = previous; - e->end = p; - previous = p; - loop->children.push_back(e); - } - - return loop; + return polygon_from_points(ps); } } @@ -1113,4 +1117,56 @@ taxonomy::item* mapping::map_impl(const IfcSchema::IfcArbitraryClosedProfileDef* } else { return nullptr; } -} \ No newline at end of file +} + +namespace { + void remove_duplicate_points_from_loop(std::vector& polygon, bool closed, double tol) { + for (;;) { + bool removed = false; + int n = polygon.size() - (closed ? 0 : 1); + for (int i = 1; i <= n; ++i) { + // wrap around to the first point in case of a closed loop + int j = (i % polygon.size()) + 1; + double dist = (polygon.at(i - 1).components - polygon.at(j - 1).components).squaredNorm(); + if (dist < tol) { + // do not remove the first or last point to + // maintain connectivity with other wires + if ((closed && j == 1) || (!closed && j == n)) polygon.erase(polygon.begin() + i - 1); + else polygon.erase(polygon.begin() + j - 1); + removed = true; + break; + } + } + if (!removed) break; + } + } +} + +taxonomy::item* mapping::map_impl(const IfcSchema::IfcPolyline* inst) { + IfcSchema::IfcCartesianPoint::list::ptr points = inst->Points(); + + // @todo + const double precision_ = 1.e-5; + + // Parse and store the points in a sequence + std::vector polygon; + polygon.reserve(points->size()); + std::transform(points->begin(), points->end(), std::back_inserter(polygon), [this](const IfcSchema::IfcCartesianPoint* p) { + return as(map(p)); + }); + + const double eps = precision_ * 10; + const bool closed_by_proximity = polygon.size() >= 3 && (polygon.front().components - polygon.back().components).norm() < eps; + if (closed_by_proximity) { + polygon.resize(polygon.size() - 1); + } + + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps); + + if (polygon.size() < 2) { + return false; + } + + return polygon_from_points(polygon); +} diff --git a/src/ifcgeom/schema/mapping.i b/src/ifcgeom/schema/mapping.i index d588e3360a..cada9d4ef1 100644 --- a/src/ifcgeom/schema/mapping.i +++ b/src/ifcgeom/schema/mapping.i @@ -100,7 +100,7 @@ BIND(IfcFace); // BIND(IfcOrientedEdge); // BIND(IfcEdge); // BIND(IfcEdgeLoop); -// BIND(IfcPolyline); +BIND(IfcPolyline); BIND(IfcPolyLoop); // BIND(IfcCompositeCurve); // BIND(IfcTrimmedCurve);