Skip to content

Commit 028e8fb

Browse files
committed
Merge branch 'master' into v0.6.0
# Conflicts: # nix/build-all.py # src/ifcgeom/IfcGeomFunctions.cpp # src/ifcparse/IfcLogger.cpp
2 parents a3141b2 + 08557c2 commit 028e8fb

5 files changed

Lines changed: 142 additions & 13 deletions

File tree

src/ifcgeom/IfcGeom.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,23 @@ if ( it != cache.T.end() ) { e = it->second; return true; }
8080
#include INCLUDE_PARENT_DIR(IfcSchema)
8181

8282
namespace IfcGeom {
83+
class IFC_PARSE_API geometry_exception : public std::exception {
84+
protected:
85+
std::string message;
86+
public:
87+
geometry_exception(const std::string& m)
88+
: message(m) {}
89+
virtual ~geometry_exception() throw () {}
90+
virtual const char* what() const throw() {
91+
return message.c_str();
92+
}
93+
};
94+
95+
class IFC_PARSE_API too_many_faces_exception : public geometry_exception {
96+
public:
97+
too_many_faces_exception()
98+
: geometry_exception("Too many faces for operation") {}
99+
};
83100

84101
class IFC_GEOM_API MAKE_TYPE_NAME(Cache) {
85102
public:

src/ifcgeom/IfcGeomFaces.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,9 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcFace* l, TopoDS_Shape& face) {
341341
TopoDS_Iterator jt(face, false);
342342
for (; jt.More(); jt.Next()) {
343343
const TopoDS_Wire& w = TopoDS::Wire(jt.Value());
344-
if (wire_map.IsBound(w)) {
344+
// tfk: @todo if wire_map contains w, I would assume wire_senses also contains w,
345+
// this is not the case in github issue #405.
346+
if (wire_map.IsBound(w) && wire_senses.IsBound(w)) {
345347
const TopTools_ListOfShape& shapes = wire_map.Find(w);
346348
TopTools_ListIteratorOfListOfShape it(shapes);
347349
for (; it.More(); it.Next()) {

src/ifcgeom/IfcGeomFunctions.cpp

Lines changed: 112 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
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>
@@ -144,6 +147,7 @@
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
233237
bool 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

32533342
bool 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;

src/ifcgeom/IfcGeomWires.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,14 +494,18 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcPolyline* l, TopoDS_Wire& resu
494494
}
495495

496496
const double eps = getValue(GV_PRECISION) * 10;
497-
const bool closed_by_proximity = polygon.Length() >= 2 && polygon.First().Distance(polygon.Last()) < eps;
497+
const bool closed_by_proximity = polygon.Length() >= 3 && polygon.First().Distance(polygon.Last()) < eps;
498498
if (closed_by_proximity) {
499499
// tfk: note 1-based
500500
polygon.Remove(polygon.Length());
501501
}
502502

503503
// Remove points that are too close to one another
504504
remove_duplicate_points_from_loop(polygon, closed_by_proximity, eps);
505+
506+
if (polygon.Length() < 2) {
507+
return false;
508+
}
505509

506510
BRepBuilderAPI_MakePolygon w;
507511
for (int i = 1; i <= polygon.Length(); ++i) {

src/ifcparse/IfcLogger.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ namespace {
4545
}
4646
os << message << std::endl;
4747
if (instance) {
48-
os << instance->data().toString() << std::endl;
48+
std::string instance_string = instance->data().toString();
49+
if (instance_string.size() > 259) {
50+
instance_string = instance_string.substr(0, 256) + "...";
51+
}
52+
os << instance_string << std::endl;
4953
}
5054
}
5155

0 commit comments

Comments
 (0)