4444#include < gp_Pln.hxx>
4545#include < gp_Circ.hxx>
4646
47+ #include < boost/range/irange.hpp>
48+ #include < boost/range/algorithm_ext/push_back.hpp>
49+
4750#include < TColgp_Array1OfPnt.hxx>
4851#include < TColgp_Array1OfPnt2d.hxx>
4952#include < TColStd_Array1OfReal.hxx>
144147#include " ../ifcparse/IfcSIPrefix.h"
145148#include " ../ifcparse/IfcFile.h"
146149#include " ../ifcgeom/IfcGeom.h"
150+ #include " ../ifcgeom/IfcGeomTree.h"
147151
148152#if OCC_VERSION_HEX < 0x60900
149153#ifdef _MSC_VER
@@ -233,12 +237,23 @@ bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, T
233237bool IfcGeom::Kernel::create_solid_from_faces (const TopTools_ListOfShape& face_list, TopoDS_Shape& shape) {
234238 bool valid_shell = false ;
235239
240+
241+ int max_faces = getValue (GV_MAX_FACES_TO_SEW);
242+ if (max_faces == -1 ) {
243+ max_faces = 1000 ;
244+ }
245+
246+ if (face_list.Extent () > max_faces) {
247+ throw too_many_faces_exception ();
248+ }
249+
236250 TopTools_ListIteratorOfListOfShape face_iterator;
237251
238252 BRepOffsetAPI_Sewing builder;
239253 builder.SetTolerance (getValue (GV_PRECISION));
240254 builder.SetMaxTolerance (getValue (GV_PRECISION));
241255 builder.SetMinTolerance (getValue (GV_PRECISION));
256+
242257 for (face_iterator.Initialize (face_list); face_iterator.More (); face_iterator.Next ()) {
243258 builder.Add (face_iterator.Value ());
244259 }
@@ -1368,6 +1383,7 @@ IfcGeom::BRepElement<P, PP>* IfcGeom::Kernel::create_brep_for_representation_and
13681383 }
13691384
13701385 IfcGeom::IfcRepresentationShapeItems opened_shapes;
1386+ bool caught_error = false ;
13711387 try {
13721388#if OCC_VERSION_HEX < 0x60900
13731389 const bool faster_booleans = settings.get (IteratorSettings::FASTER_BOOLEANS);
@@ -1387,9 +1403,17 @@ IfcGeom::BRepElement<P, PP>* IfcGeom::Kernel::create_brep_for_representation_and
13871403 } else {
13881404 convert_openings (product,openings,shapes,trsf,opened_shapes);
13891405 }
1406+ } catch (const std::exception& e) {
1407+ Logger::Message (Logger::LOG_ERROR, std::string (" Error processing openings for: " ) + e.what () + " :" , product);
1408+ caught_error = true ;
13901409 } catch (...) {
13911410 Logger::Message (Logger::LOG_ERROR," Error processing openings for:" ,product);
13921411 }
1412+
1413+ if (caught_error && opened_shapes.size () < shapes.size ()) {
1414+ opened_shapes = shapes;
1415+ }
1416+
13931417 if (settings.get (IteratorSettings::USE_WORLD_COORDS)) {
13941418 for ( IfcGeom::IfcRepresentationShapeItems::iterator it = opened_shapes.begin (); it != opened_shapes.end (); ++ it ) {
13951419 it->prepend (trsf);
@@ -2852,10 +2876,7 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
28522876 }
28532877
28542878 int n = count (wire, TopAbs_EDGE);
2855- if (n < 3 || n > 128 ) {
2856- if (n > 128 ) {
2857- Logger::Notice (" Too many segments for detection of self-intersections" );
2858- }
2879+ if (n < 3 ) {
28592880 wires.Append (wire);
28602881 return false ;
28612882 }
@@ -2865,22 +2886,62 @@ bool IfcGeom::Kernel::wire_intersections(const TopoDS_Wire& wire, TopTools_ListO
28652886
28662887 // ... to be sure to get consecutive edges
28672888 BRepTools_WireExplorer exp (wire);
2889+ IfcGeom::impl::tree<int > tree;
2890+
2891+ int edge_idx = 0 ;
28682892 for (; exp.More (); exp.Next ()) {
28692893 wd->Add (exp.Current ());
2894+ if (n > 64 ) {
2895+ // tfk: indices in tree are 0-based vd 1-based in wiredata
2896+ tree.add (edge_idx++, exp.Current ());
2897+ }
2898+ }
2899+
2900+ if (wd->NbEdges () != n) {
2901+ // If the number of edges differs, BRepTools_WireExplorer did not
2902+ // reach every edge, probably due to loops exactly at vertex locations.
2903+ // This is not supported by this algorithm which only elimates loops
2904+ // due to edge crossings.
2905+
2906+ throw geometry_exception (" Invalid loop" );
28702907 }
28712908
28722909 bool intersected = false ;
28732910
28742911 // tfk: Extrema on infinite curves proved to be more robust.
28752912 // TopoDS_Face face = BRepBuilderAPI_MakeFace(wire, true).Face();
28762913 // ShapeAnalysis_Wire saw(wd, face, getValue(GV_PRECISION));
2877-
2914+
2915+ const double eps = getValue (GV_PRECISION) * 10 .;
2916+
28782917 for (int i = 2 ; i < n; ++i) {
2879- for (int j = 0 ; j < i - 1 ; ++j) {
2880- if (i == n - 1 && j == 0 ) continue ;
28812918
2919+ std::vector<int > js;
2920+ if (n > 64 ) {
2921+ Bnd_Box b;
2922+ BRepBndLib::Add (wd->Edge (i + 1 ), b);
2923+ b.Enlarge (eps);
2924+ js = tree.select_box (b, false );
2925+ } else {
2926+ boost::push_back (js, boost::irange (0 , i - 1 ));
2927+ }
2928+
2929+ for (std::vector<int >::const_iterator it = js.begin (); it != js.end (); ++it) {
2930+ int j = *it;
2931+
2932+ if (n > 64 ) {
2933+ if (j > i) {
2934+ continue ;
2935+ }
2936+ if ((std::max)(i, j) - (std::min)(i, j) <= 1 ) {
2937+ continue ;
2938+ }
2939+ }
2940+
2941+ // Only check non-consecutive edges
2942+ if (i == n - 1 && j == 0 ) continue ;
2943+
28822944 bool unbounded_intersects;
2883- const double eps = getValue (GV_PRECISION) * 10 .;
28842945
28852946 double u11, u12, u21, u22, U1, U2;
28862947 GeomAPI_ExtremaCurveCurve ecc (
@@ -3041,6 +3102,10 @@ bool IfcGeom::Kernel::fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b
30413102 Bnd_Box bb;
30423103 BRepBndLib::Add (a, bb);
30433104
3105+ if (bb.IsVoid ()) {
3106+ return false ;
3107+ }
3108+
30443109 double xs[2 ], ys[2 ], zs[2 ];
30453110 bb.Get (xs[0 ], ys[0 ], zs[0 ], xs[1 ], ys[1 ], zs[1 ]);
30463111
@@ -3226,7 +3291,7 @@ namespace {
32263291 TopoDS_Vertex v1, v2;
32273292 TopExp::Vertices (e, v1, v2);
32283293
3229- if (v.IsEqual (v1) || v.IsEqual (v2)) {
3294+ if (v.IsSame (v1) || v.IsSame (v2)) {
32303295 continue ;
32313296 }
32323297
@@ -3248,6 +3313,30 @@ namespace {
32483313 return M;
32493314 }
32503315
3316+ bool is_manifold (const TopoDS_Shape& a) {
3317+ TopTools_IndexedDataMapOfShapeListOfShape map;
3318+ TopExp::MapShapesAndAncestors (a, TopAbs_EDGE, TopAbs_FACE, map);
3319+
3320+ for (int i = 1 ; i <= map.Extent (); ++i) {
3321+ if (map.FindFromIndex (i).Extent () != 2 ) {
3322+ return false ;
3323+ }
3324+ }
3325+
3326+ return true ;
3327+ }
3328+
3329+ bool is_manifold (const TopTools_ListOfShape& l) {
3330+ TopTools_ListOfShape r;
3331+ TopTools_ListIteratorOfListOfShape it (l);
3332+ for (; it.More (); it.Next ()) {
3333+ if (!is_manifold (it.Value ())) {
3334+ return false ;
3335+ }
3336+ }
3337+ return true ;
3338+ }
3339+
32513340}
32523341
32533342bool IfcGeom::Kernel::boolean_operation (const TopoDS_Shape& a, const TopTools_ListOfShape& b, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) {
@@ -3307,7 +3396,20 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopTools_Li
33073396 success = BRepCheck_Analyzer (r).IsValid () != 0 ;
33083397
33093398 if (success) {
3310- result = r;
3399+
3400+ success = !is_manifold (a) || is_manifold (r);
3401+
3402+ if (success) {
3403+
3404+ // when there are edges or vertex-edge distances close to the used fuzziness, the
3405+ // output is not trusted and the operation is attempted with a higher fuzziness.
3406+ double min_len_check = (std::min)(min_edge_length (r), min_vertex_edge_distance (r, getValue (GV_PRECISION)));
3407+ success = min_len_check > fuzziness * 10 .;
3408+
3409+ if (success) {
3410+ result = r;
3411+ }
3412+ }
33113413 }
33123414 }
33133415 delete builder;
0 commit comments