Skip to content

Commit e77216d

Browse files
committed
More robust processing of IfcPolyline and IfcPolyLoop
1 parent cf2e82e commit e77216d

4 files changed

Lines changed: 101 additions & 39 deletions

File tree

src/ifcgeom/IfcGeom.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <TopoDS_Face.hxx>
3737
#include <Geom_Curve.hxx>
3838
#include <gp_Pln.hxx>
39+
#include <TColgp_SequenceOfPnt.hxx>
3940

4041
#include "../ifcparse/IfcParse.h"
4142
#include "../ifcparse/IfcUtil.h"
@@ -106,7 +107,7 @@ namespace IfcGeom {
106107
double GetValue(GeomValue var);
107108
bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape);
108109
IfcSchema::IfcProductDefinitionShape* tesselate(TopoDS_Shape& shape, double deflection, IfcEntityList::ptr es);
109-
110+
void remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol=-1.);
110111

111112

112113
namespace Cache {

src/ifcgeom/IfcGeomFunctions.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,4 +792,27 @@ bool IfcGeom::flatten_shape_list(const IfcGeom::IfcRepresentationShapeItems& sha
792792

793793
return !result.IsNull();
794794
}
795-
795+
796+
void IfcGeom::remove_redundant_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol) {
797+
if (tol <= 0.) tol = GetValue(GV_POINT_EQUALITY_TOLERANCE);
798+
tol *= tol;
799+
800+
while (true) {
801+
bool removed = false;
802+
int n = polygon.Length() - (closed ? 0 : 1);
803+
for (int i = 1; i <= n; ++i) {
804+
// wrap around to the first point in case of a closed loop
805+
int j = (i % polygon.Length()) + 1;
806+
double dist = polygon.Value(i).SquareDistance(polygon.Value(j));
807+
if (dist < tol) {
808+
// do not remove the first or last point to
809+
// maintain connectivity with other wires
810+
if ((closed && j == 1) || (!closed && j == n)) polygon.Remove(i);
811+
else polygon.Remove(j);
812+
removed = true;
813+
break;
814+
}
815+
}
816+
if (!removed) break;
817+
}
818+
}

src/ifcgeom/IfcGeomShapes.cpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,17 +393,23 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha
393393
builder.SetMinTolerance(GetValue(GV_POINT_EQUALITY_TOLERANCE));
394394
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
395395
TopoDS_Face face;
396-
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
396+
bool converted_face = false;
397+
try {
398+
converted_face = IfcGeom::convert_face(*it,face);
399+
} catch (...) {}
400+
if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
397401
builder.Add(face);
398402
facesAdded = true;
399403
} else {
400404
Logger::Message(Logger::LOG_WARNING,"Invalid face:",(*it)->entity);
401405
}
402406
}
403407
if ( ! facesAdded ) return false;
404-
builder.Perform();
405-
shape = builder.SewedShape();
406-
valid_shell = BRepCheck_Analyzer(shape).IsValid();
408+
try {
409+
builder.Perform();
410+
shape = builder.SewedShape();
411+
valid_shell = BRepCheck_Analyzer(shape).IsValid();
412+
} catch(...) {}
407413
if (valid_shell) {
408414
try {
409415
ShapeFix_Solid solid;
@@ -416,6 +422,8 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha
416422
} catch (...) {}
417423
}
418424
} catch(...) {}
425+
} else {
426+
Logger::Message(Logger::LOG_WARNING,"Failed to sew faceset:",l->entity);
419427
}
420428
}
421429
if (!valid_shell) {
@@ -424,7 +432,11 @@ bool IfcGeom::convert(const IfcSchema::IfcConnectedFaceSet* l, TopoDS_Shape& sha
424432
builder.MakeCompound(compound);
425433
for( IfcSchema::IfcFace::list::it it = faces->begin(); it != faces->end(); ++ it ) {
426434
TopoDS_Face face;
427-
if ( IfcGeom::convert_face(*it,face) && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
435+
bool converted_face = false;
436+
try {
437+
converted_face = IfcGeom::convert_face(*it,face);
438+
} catch (...) {}
439+
if ( converted_face && face_area(face) > GetValue(GV_MINIMAL_FACE_AREA) ) {
428440
builder.Add(compound,face);
429441
facesAdded = true;
430442
} else {

src/ifcgeom/IfcGeomWires.cpp

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -47,39 +47,40 @@
4747
#include <TColgp_Array1OfPnt2d.hxx>
4848
#include <TColStd_Array1OfReal.hxx>
4949
#include <TColStd_Array1OfInteger.hxx>
50+
5051
#include <Geom_Line.hxx>
5152
#include <Geom_Circle.hxx>
5253
#include <Geom_Ellipse.hxx>
5354
#include <Geom_TrimmedCurve.hxx>
5455

55-
#include <BRepOffsetAPI_Sewing.hxx>
56+
#include <BRepBuilderAPI_MakeVertex.hxx>
5657
#include <BRepBuilderAPI_MakeFace.hxx>
5758
#include <BRepBuilderAPI_MakeEdge.hxx>
5859
#include <BRepBuilderAPI_MakeWire.hxx>
60+
#include <BRepBuilderAPI_MakeShell.hxx>
61+
#include <BRepBuilderAPI_MakeSolid.hxx>
5962
#include <BRepBuilderAPI_MakePolygon.hxx>
6063
#include <BRepBuilderAPI_MakeVertex.hxx>
6164

6265
#include <TopoDS.hxx>
6366
#include <TopoDS_Wire.hxx>
6467
#include <TopoDS_Face.hxx>
6568
#include <TopExp_Explorer.hxx>
69+
#include <TopLoc_Location.hxx>
70+
#include <TopTools_ListOfShape.hxx>
6671

72+
#include <BRepAlgoAPI_Cut.hxx>
73+
#include <BRepOffsetAPI_Sewing.hxx>
6774
#include <BRepPrimAPI_MakePrism.hxx>
68-
#include <BRepBuilderAPI_MakeShell.hxx>
69-
#include <BRepBuilderAPI_MakeSolid.hxx>
7075
#include <BRepPrimAPI_MakeHalfSpace.hxx>
71-
#include <BRepAlgoAPI_Cut.hxx>
76+
#include <BRepFilletAPI_MakeFillet2d.hxx>
77+
78+
#include <BRep_Tool.hxx>
7279

7380
#include <ShapeFix_Shape.hxx>
7481
#include <ShapeFix_ShapeTolerance.hxx>
7582
#include <ShapeFix_Solid.hxx>
7683

77-
#include <BRepFilletAPI_MakeFillet2d.hxx>
78-
79-
#include <TopLoc_Location.hxx>
80-
81-
#include <BRep_Tool.hxx>
82-
8384
#include "../ifcgeom/IfcGeom.h"
8485

8586
bool IfcGeom::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire& wire) {
@@ -274,13 +275,20 @@ bool IfcGeom::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
274275
bool IfcGeom::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) {
275276
IfcSchema::IfcCartesianPoint::list::ptr points = l->Points();
276277

277-
BRepBuilderAPI_MakeWire w;
278-
gp_Pnt P1;gp_Pnt P2;
279-
for( IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it ) {
280-
IfcGeom::convert(*it,P2);
281-
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) )
282-
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
283-
P1 = P2;
278+
// Parse and store the points in a sequence
279+
TColgp_SequenceOfPnt polygon;
280+
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
281+
gp_Pnt pnt;
282+
IfcGeom::convert(*it, pnt);
283+
polygon.Append(pnt);
284+
}
285+
286+
// Remove points that are too close to one another
287+
remove_redundant_points_from_loop(polygon, false);
288+
289+
BRepBuilderAPI_MakePolygon w;
290+
for (int i = 1; i <= polygon.Length(); ++i) {
291+
w.Add(polygon.Value(i));
284292
}
285293

286294
result = w.Wire();
@@ -290,24 +298,42 @@ bool IfcGeom::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& result) {
290298
bool IfcGeom::convert(const IfcSchema::IfcPolyLoop* l, TopoDS_Wire& result) {
291299
IfcSchema::IfcCartesianPoint::list::ptr points = l->Polygon();
292300

293-
BRepBuilderAPI_MakeWire w;
294-
gp_Pnt P1;gp_Pnt P2;gp_Pnt F;
295-
int count = 0;
296-
for( IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it ) {
297-
IfcGeom::convert(*it,P2);
298-
if ( it != points->begin() && ( !P1.IsEqual(P2,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) ) {
299-
w.Add(BRepBuilderAPI_MakeEdge(P1,P2));
300-
count ++;
301-
} else if ( ! count ) F = P2;
302-
P1 = P2;
301+
// Parse and store the points in a sequence
302+
TColgp_SequenceOfPnt polygon;
303+
for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) {
304+
gp_Pnt pnt;
305+
IfcGeom::convert(*it, pnt);
306+
polygon.Append(pnt);
307+
}
308+
309+
// A loop should consist of at least three vertices
310+
int original_count = polygon.Length();
311+
if (original_count < 3) {
312+
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
313+
return false;
303314
}
304-
if ( !P1.IsEqual(F,GetValue(GV_POINT_EQUALITY_TOLERANCE)) ) {
305-
w.Add(BRepBuilderAPI_MakeEdge(P1,F));
306-
count ++;
315+
316+
// Remove points that are too close to one another
317+
remove_redundant_points_from_loop(polygon, true);
318+
319+
int count = polygon.Length();
320+
if (original_count - count != 0) {
321+
std::stringstream ss; ss << (original_count - count) << " edges removed for:";
322+
Logger::Message(Logger::LOG_WARNING, ss.str(), l->entity);
307323
}
308-
if ( count < 3 ) return false;
309324

310-
result = w.Wire();
325+
if (count < 3) {
326+
Logger::Message(Logger::LOG_ERROR, "Not enough edges for:", l->entity);
327+
return false;
328+
}
329+
330+
BRepBuilderAPI_MakePolygon w;
331+
for (int i = 1; i <= polygon.Length(); ++i) {
332+
w.Add(polygon.Value(i));
333+
}
334+
w.Close();
335+
336+
result = w.Wire();
311337
return true;
312338
}
313339

0 commit comments

Comments
 (0)