From e77216d41ce03f4aee005d5ea099ac6cadbd05d8 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 | 25 ++++++++- src/ifcgeom/IfcGeomShapes.cpp | 22 ++++++-- src/ifcgeom/IfcGeomWires.cpp | 94 ++++++++++++++++++++------------ 4 files changed, 103 insertions(+), 41 deletions(-) diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index 610ed7aafc..d1081477ca 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" @@ -106,7 +107,7 @@ namespace IfcGeom { double GetValue(GeomValue var); bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape); IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr 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 d0aba46590..42efc4cfff 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -792,4 +792,27 @@ bool IfcGeom::flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& sha return !result.IsNull(); } - \ No newline at end of file + +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 f56b7ac45f..4e3ab6a9f9 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -393,7 +393,11 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE)); for( IfcSchema::IfcFace::list::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 { @@ -401,9 +405,11 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha } } 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; @@ -416,6 +422,8 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha } catch (...) {} } } catch(...) {} + } else { + Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity); } } if (!valid_shell) { @@ -424,7 +432,11 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha builder.MakeCompound(compound); for( IfcSchema::IfcFace::list::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 d76599a3fc..0e3ca1a3e0 100644 --- a/src/ifcgeom/IfcGeomWires.cpp +++ b/src/ifcgeom/IfcGeomWires.cpp @@ -47,15 +47,18 @@ #include #include #include + #include #include #include #include -#include +#include #include #include #include +#include +#include #include #include @@ -63,23 +66,21 @@ #include #include #include +#include +#include -#include -#include -#include -#include #include +#include +#include +#include +#include + +#include #include #include #include -#include - -#include - -#include - #include "../ifcgeom/IfcGeom.h" bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) { @@ -274,13 +275,20 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) { bool IfcGeom::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) { IfcSchema::IfcCartesianPoint::list::ptr points = l->Points(); - BRepBuilderAPI_MakeWire w; - gp_Pnt P1;gp_Pnt P2; - for( IfcSchema::IfcCartesianPoint::list::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(IfcSchema::IfcCartesianPoint::list::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(); @@ -290,24 +298,42 @@ bool IfcGeom::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) { bool IfcGeom::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) { IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon(); - BRepBuilderAPI_MakeWire w; - gp_Pnt P1;gp_Pnt P2;gp_Pnt F; - int count = 0; - for( IfcSchema::IfcCartesianPoint::list::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(IfcSchema::IfcCartesianPoint::list::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; }