Skip to content

Commit b7ce547

Browse files
committed
Fill holes in composite curves, fixes IfcOpenShell#282
1 parent 6cd59aa commit b7ce547

2 files changed

Lines changed: 74 additions & 40 deletions

File tree

src/ifcgeom/IfcGeomFunctions.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -616,17 +616,18 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
616616
#endif
617617

618618
bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
619+
ShapeFix_ShapeTolerance FTol;
620+
FTol.SetTolerance(wire, getValue(GV_PRECISION), TopAbs_WIRE);
621+
619622
BRepBuilderAPI_MakeFace mf(wire, false);
620623
BRepBuilderAPI_FaceError er = mf.Error();
621-
if ( er == BRepBuilderAPI_NotPlanar ) {
622-
ShapeFix_ShapeTolerance FTol;
623-
FTol.SetTolerance(wire, 0.01, TopAbs_WIRE);
624-
mf.~BRepBuilderAPI_MakeFace();
625-
new (&mf) BRepBuilderAPI_MakeFace(wire);
626-
er = mf.Error();
627-
}
628-
if ( er != BRepBuilderAPI_FaceDone ) return false;
624+
625+
if (er != BRepBuilderAPI_FaceDone) {
626+
Logger::Error("Failed to create face.");
627+
return false;
628+
}
629629
face = mf.Face();
630+
630631
return true;
631632
}
632633

src/ifcgeom/IfcGeomWires.cpp

Lines changed: 65 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -166,41 +166,45 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
166166
}
167167

168168
BRepBuilderAPI_MakeWire w;
169-
TopoDS_Vertex v1, v2, last;
169+
TopoDS_Vertex wire_first_vertex, wire_last_vertex, edge_first_vertex, edge_last_vertex;
170170
IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments();
171+
172+
const double precision_sq_2 = 2 * getValue(GV_PRECISION) * getValue(GV_PRECISION);
171173

172-
for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) {
174+
for(IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++it) {
173175

174176
IfcSchema::IfcCurve* curve = (*it)->ParentCurve();
175-
TopoDS_Wire wire2;
177+
TopoDS_Wire segment;
176178

177-
if ( !convert_wire(curve, wire2) ) {
179+
if (!convert_wire(curve, segment)) {
178180
Logger::Message(Logger::LOG_ERROR, "Failed to convert curve:", curve->entity);
179181
continue;
180182
}
181183

182-
if ( ! (*it)->SameSense() ) wire2.Reverse();
184+
if (!(*it)->SameSense()) {
185+
segment.Reverse();
186+
}
183187

184188
ShapeFix_ShapeTolerance FTol;
185-
FTol.SetTolerance(wire2, getValue(GV_PRECISION), TopAbs_WIRE);
189+
FTol.SetTolerance(segment, getValue(GV_PRECISION), TopAbs_WIRE);
186190

187-
/*
188-
// Create a line segment between distant vertices?
189-
if ( it != segments->begin() ) {
190-
TopExp_Explorer exp (wire2,TopAbs_VERTEX);
191-
const TopoDS_Vertex& first_vertex = TopoDS::Vertex(exp.Current());
192-
gp_Pnt first = BRep_Tool::Pnt(first_vertex);
193-
gp_Pnt last = BRep_Tool::Pnt(last_vertex);
194-
Standard_Real distance = first.Distance(last);
195-
if ( distance > ALMOST_ZERO ) {
196-
w.Add( BRepBuilderAPI_MakeEdge( last_vertex, first_vertex ) );
191+
TopExp::Vertices(segment, edge_first_vertex, edge_last_vertex);
192+
193+
if (it == segments->begin()) {
194+
wire_first_vertex = edge_first_vertex;
195+
} else {
196+
gp_Pnt first = BRep_Tool::Pnt(edge_first_vertex);
197+
gp_Pnt last = BRep_Tool::Pnt(wire_last_vertex);
198+
199+
Standard_Real distance = first.SquareDistance(last);
200+
if (distance > precision_sq_2) {
201+
w.Add(BRepBuilderAPI_MakeEdge(wire_last_vertex, edge_first_vertex));
202+
203+
Logger::Message(Logger::LOG_ERROR, "Closed gap on:", l->entity);
197204
}
198205
}
199-
*/
200206

201-
TopExp::Vertices(wire2, v1, v2);
202-
203-
w.Add(wire2);
207+
w.Add(segment);
204208

205209
if ( w.Error() != BRepBuilderAPI_WireDone ) {
206210
if (w.Error() == BRepBuilderAPI_NonManifoldWire) {
@@ -215,24 +219,24 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
215219
int precision = 4;
216220
double d = 0.;
217221

218-
if (!last.IsNull()) {
219-
p1 = BRep_Tool::Pnt(last);
222+
if (!wire_last_vertex.IsNull()) {
223+
p1 = BRep_Tool::Pnt(wire_last_vertex);
220224
}
221-
if (!v1.IsNull()) {
222-
p2 = BRep_Tool::Pnt(v1);
225+
if (!edge_first_vertex.IsNull()) {
226+
p2 = BRep_Tool::Pnt(edge_first_vertex);
223227
}
224-
if (!last.IsNull() && !v1.IsNull()) {
228+
if (!wire_last_vertex.IsNull() && !edge_first_vertex.IsNull()) {
225229
d = p1.Distance(p2);
226230
precision = ceil(-log10(d)) + 3;
227231
}
228232

229-
if (!last.IsNull()) {
233+
if (!wire_last_vertex.IsNull()) {
230234
std::stringstream ss;
231235
ss << std::setprecision(precision) << "Last vertex at (" << p1.X() << " " << p1.Y() << " " << p1.Z() << ")";
232236
Logger::Message(Logger::LOG_NOTICE, ss.str());
233237
}
234238

235-
if (!v1.IsNull()) {
239+
if (!edge_first_vertex.IsNull()) {
236240
std::stringstream ss;
237241
ss << std::setprecision(precision) << "Segment starts at (" << p2.X() << " " << p2.Y() << " " << p2.Z() << ")";
238242
if (d > 0.) {
@@ -246,26 +250,42 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcCompositeCurve* l, TopoDS_Wire
246250
return false;
247251
}
248252

249-
last = v2;
253+
wire_last_vertex = edge_last_vertex;
254+
}
255+
256+
gp_Pnt first = BRep_Tool::Pnt(edge_last_vertex);
257+
gp_Pnt last = BRep_Tool::Pnt(wire_first_vertex);
258+
259+
Standard_Real distance = first.SquareDistance(last);
260+
if (distance > precision_sq_2) {
261+
w.Add(BRepBuilderAPI_MakeEdge(edge_last_vertex, wire_first_vertex));
262+
263+
Logger::Message(Logger::LOG_ERROR, "Closed gap on:", l->entity);
250264
}
265+
251266
wire = w.Wire();
267+
252268
return true;
253269
}
254270

255271
bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire& wire) {
256272
IfcSchema::IfcCurve* basis_curve = l->BasisCurve();
257273
bool isConic = basis_curve->is(IfcSchema::Type::IfcConic);
258274
double parameterFactor = isConic ? getValue(GV_PLANEANGLE_UNIT) : getValue(GV_LENGTH_UNIT);
275+
259276
Handle(Geom_Curve) curve;
260277
if ( !convert_curve(basis_curve,curve) ) return false;
278+
261279
bool trim_cartesian = l->MasterRepresentation() != IfcSchema::IfcTrimmingPreference::IfcTrimmingPreference_PARAMETER;
262280
IfcEntityList::ptr trims1 = l->Trim1();
263281
IfcEntityList::ptr trims2 = l->Trim2();
282+
264283
unsigned sense_agreement = l->SenseAgreement() ? 0 : 1;
265284
double flts[2];
266285
gp_Pnt pnts[2];
267286
bool has_flts[2] = {false,false};
268287
bool has_pnts[2] = {false,false};
288+
269289
BRepBuilderAPI_MakeWire w;
270290
for ( IfcEntityList::it it = trims1->begin(); it != trims1->end(); it ++ ) {
271291
IfcUtil::IfcBaseClass* i = *it;
@@ -278,6 +298,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
278298
has_flts[sense_agreement] = true;
279299
}
280300
}
301+
281302
for ( IfcEntityList::it it = trims2->begin(); it != trims2->end(); it ++ ) {
282303
IfcUtil::IfcBaseClass* i = *it;
283304
if ( i->is(IfcSchema::Type::IfcCartesianPoint) ) {
@@ -289,18 +310,19 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
289310
has_flts[1-sense_agreement] = true;
290311
}
291312
}
313+
292314
trim_cartesian &= has_pnts[0] && has_pnts[1];
293315
bool trim_cartesian_failed = !trim_cartesian;
294316
if ( trim_cartesian ) {
295-
if ( pnts[0].Distance(pnts[1]) < getValue(GV_WIRE_CREATION_TOLERANCE) ) {
317+
if ( pnts[0].Distance(pnts[1]) < 2 * getValue(GV_PRECISION) ) {
296318
Logger::Message(Logger::LOG_WARNING,"Skipping segment with length below tolerance level:",l->entity);
297319
return false;
298320
}
299321
ShapeFix_ShapeTolerance FTol;
300322
TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(pnts[0]);
301323
TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(pnts[1]);
302-
FTol.SetTolerance(v1, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
303-
FTol.SetTolerance(v2, getValue(GV_WIRE_CREATION_TOLERANCE), TopAbs_VERTEX);
324+
FTol.SetTolerance(v1, getValue(GV_PRECISION), TopAbs_VERTEX);
325+
FTol.SetTolerance(v2, getValue(GV_PRECISION), TopAbs_VERTEX);
304326
BRepBuilderAPI_MakeEdge e (curve,v1,v2);
305327
if ( ! e.IsDone() ) {
306328
BRepBuilderAPI_EdgeError err = e.Error();
@@ -312,6 +334,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
312334
w.Add(e.Edge());
313335
}
314336
}
337+
315338
if ( (!trim_cartesian || trim_cartesian_failed) && (has_flts[0] && has_flts[1]) ) {
316339
// The Geom_Line is constructed from a gp_Pnt and gp_Dir, whereas the IfcLine
317340
// is defined by an IfcCartesianPoint and an IfcVector with Magnitude. Because
@@ -341,8 +364,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcTrimmedCurve* l, TopoDS_Wire&
341364
} else if ( trim_cartesian_failed && (has_pnts[0] && has_pnts[1]) ) {
342365
w.Add(BRepBuilderAPI_MakeEdge(pnts[0],pnts[1]));
343366
}
344-
if ( w.IsDone() ) {
367+
368+
if (w.IsDone()) {
345369
wire = w.Wire();
370+
371+
// When SenseAgreement == .F. the vertices above have been reversed to
372+
// comply with the direction of conical curves. The ordering of the
373+
// vertices then still needs to be reversed in order to have begin and
374+
// end vertex consistent with IFC.
375+
if (sense_agreement != 0) { // .F.
376+
wire.Reverse();
377+
}
378+
346379
return true;
347380
} else {
348381
return false;

0 commit comments

Comments
 (0)