From 33625c6422193990eaf59044745f7cdd9c6cb30f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Mon, 28 Jul 2014 20:03:53 +0000 Subject: [PATCH] More robust processing of IfcPolyline and IfcPolyLoop --- src/ifcgeom/IfcGeom.h | 3 +- src/ifcgeom/IfcGeomFunctions.cpp | 24 +++++++++++ src/ifcgeom/IfcGeomShapes.cpp | 22 +++++++--- src/ifcgeom/IfcGeomWires.cpp | 71 +++++++++++++++++++++----------- 4 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 0bfb4be70a..405164636f 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -36,6 +36,7 @@ #include #include #include +#include #include "../ifcparse/IfcParse.h" #include "../ifcparse/IfcUtil.h" @@ -103,7 +104,7 @@ namespace IfcGeom { void SetValue(GeomValue var, double value); double GetValue(GeomValue var); Ifc2x3::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntities es); - + void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.); namespace Cache { diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 81173a3c07..3027772031 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -574,4 +574,28 @@ Ifc2x3::IfcProductDefinitionShape* IfcGeom::tesselate(TopoDS_Shape& shape, doubl es->push(shapedef); return shapedef; +} + +void IfcGeom::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) { + if (tol <= 0.) tol = GetValue(GV_POINT_EQUALITY_TOLERANCE); + tol *= tol; + + while (true) { + bool removed = false; + int n = polygon.Length() - (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.Length()) + 1; + double dist = polygon.Value(i).SquareDistance(polygon.Value(j)); + 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.Remove(i); + else polygon.Remove(j); + removed = true; + break; + } + } + if (!removed) break; + } } \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index a972db296a..fd358617ce 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -221,7 +221,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE)); for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) { TopoDS_Face face; - if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) { + bool converted_face = false; + try { + converted_face = IfcGeom::convert_face(*it,face); + } catch (...) {} + if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) { builder.Add(face); facesAdded = true; } else { @@ -229,9 +233,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh } } if ( ! facesAdded ) return false; - builder.Perform(); - shape = builder.SewedShape(); - valid_shell = BRepCheck_Analyzer(shape).IsValid(); + try { + builder.Perform(); + shape = builder.SewedShape(); + valid_shell = BRepCheck_Analyzer(shape).IsValid(); + } catch(...) {} if (valid_shell) { try { ShapeFix_Solid solid; @@ -244,6 +250,8 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh } catch (...) {} } } catch(...) {} + } else { + Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity); } } if (!valid_shell) { @@ -252,7 +260,11 @@ bool IfcGeom::convert(const Ifc2x3::IfcConnectedFaceSet::ptr l, TopoDS_Shape& sh builder.MakeCompound(compound); for( Ifc2x3::IfcFace::it it = faces->begin(); it != faces->end(); ++ it ) { TopoDS_Face face; - if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) { + bool converted_face = false; + try { + converted_face = IfcGeom::convert_face(*it,face); + } catch (...) {} + if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) { builder.Add(compound,face); facesAdded = true; } else { diff --git a/src/ifcgeom/IfcGeomWires.cpp b/src/ifcgeom/IfcGeomWires.cpp index ceb6aa76f6..77814c7948 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/IfcGeomWires.cpp @@ -262,13 +262,20 @@ bool IfcGeom::convert(const Ifc2x3::IfcTrimmedCurve::ptr l, TopoDS_Wire& wire) { bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) { Ifc2x3::IfcCartesianPoint::list points = l->Points(); - BRepBuilderAPI_MakeWire w; - gp_Pnt P1;gp_Pnt P2; - for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) { - IfcGeom::convert(*it,P2); - if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) - w.Add(BRepBuilderAPI_MakeEdge(P1,P2)); - P1 = P2; + // Parse and store the points in a sequence + TColgp_SequenceOfPnt polygon; + for(Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it) { + gp_Pnt pnt; + IfcGeom::convert(*it, pnt); + polygon.Append(pnt); + } + + // Remove points that are too close to one another + remove_redundant_points_from_loop(polygon, false); + + BRepBuilderAPI_MakePolygon w; + for (int i = 1; i <= polygon.Length(); ++i) { + w.Add(polygon.Value(i)); } result = w.Wire(); @@ -277,23 +284,41 @@ bool IfcGeom::convert(const Ifc2x3::IfcPolyline::ptr l, TopoDS_Wire& result) { bool IfcGeom::convert(const Ifc2x3::IfcPolyLoop::ptr l, TopoDS_Wire& result) { Ifc2x3::IfcCartesianPoint::list points = l->Polygon(); - BRepBuilderAPI_MakeWire w; - gp_Pnt P1;gp_Pnt P2;gp_Pnt F; - int count = 0; - for( Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it ) { - IfcGeom::convert(*it,P2); - if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) { - w.Add(BRepBuilderAPI_MakeEdge(P1,P2)); - count ++; - } else if ( ! count ) F = P2; - P1 = P2; + // Parse and store the points in a sequence + TColgp_SequenceOfPnt polygon; + for(Ifc2x3::IfcCartesianPoint::it it = points->begin(); it != points->end(); ++ it) { + gp_Pnt pnt; + IfcGeom::convert(*it, pnt); + polygon.Append(pnt); } - if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) { - w.Add(BRepBuilderAPI_MakeEdge(P1,F)); - count ++; - } - if ( count < 3 ) return false; - result = w.Wire(); + // A loop should consist of at least three vertices + int original_count = polygon.Length(); + if (original_count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } + + // Remove points that are too close to one another + remove_redundant_points_from_loop(polygon, true); + + int count = polygon.Length(); + if (original_count - count != 0) { + std::stringstream ss; ss << (original_count - count) << " edges removed for:"; + Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity); + } + + if (count < 3) { + Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity); + return false; + } + + BRepBuilderAPI_MakePolygon w; + for (int i = 1; i <= polygon.Length(); ++i) { + w.Add(polygon.Value(i)); + } + w.Close(); + + result = w.Wire(); return true; } \ No newline at end of file