@@ -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
255271bool 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