Skip to content

Commit 700cc77

Browse files
committed
- Add an alternative method to process openings that is potentially faster. Use IfcGeomObjects::FASTER_BOOLEANS to enable.
- Begin working on verbosity levels
1 parent 82289bf commit 700cc77

6 files changed

Lines changed: 117 additions & 11 deletions

File tree

src/ifcgeom/IfcGeom.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ namespace IfcGeom {
6565
bool convert_curve(const IfcUtil::IfcBaseClass* L, Handle(Geom_Curve)& result);
6666
bool convert_face(const IfcUtil::IfcBaseClass* L, TopoDS_Face& result);
6767
bool convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
68+
bool convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings, const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes);
6869
bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid);
6970
bool is_compound(const TopoDS_Shape& shape);
7071
bool is_convex(const TopoDS_Wire& wire);

src/ifcgeom/IfcGeomFunctions.cpp

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,14 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
179179
? BRepBuilderAPI_GTransform(opening_shape_unlocated,opening_shape_gtrsf,true).Shape()
180180
: opening_shape_unlocated.Moved(opening_shape_gtrsf.Trsf());
181181

182-
const double opening_volume = shape_volume(opening_shape);
183-
if ( opening_volume <= ALMOST_ZERO )
184-
Ifc::LogMessage("Warning","Empty opening for:",entity->entity);
185-
186-
const double original_shape_volume = shape_volume(entity_shape);
187-
182+
double opening_volume, original_shape_volume;
183+
if ( Ifc::Verbosity > 1 ) {
184+
opening_volume = shape_volume(opening_shape);
185+
if ( opening_volume <= ALMOST_ZERO )
186+
Ifc::LogMessage("Warning","Empty opening for:",entity->entity);
187+
original_shape_volume = shape_volume(entity_shape);
188+
}
189+
188190
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_shape);
189191

190192
if ( brep_cut.IsDone() ) {
@@ -194,11 +196,12 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
194196
bool is_valid = analyser.IsValid() != 0;
195197
if ( is_valid ) {
196198
entity_shape = brep_cut;
197-
const double volume_after_subtraction = shape_volume(entity_shape);
199+
if ( Ifc::Verbosity > 1 ) {
200+
const double volume_after_subtraction = shape_volume(entity_shape);
198201

199-
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
200-
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity);
201-
202+
if ( ALMOST_THE_SAME(original_shape_volume,volume_after_subtraction) )
203+
Ifc::LogMessage("Warning","Subtraction yields unchanged volume:",entity->entity);
204+
}
202205
} else {
203206
Ifc::LogMessage("Error","Invalid result from subtraction:",entity->entity);
204207
}
@@ -217,6 +220,87 @@ bool IfcGeom::convert_openings(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x
217220

218221
return true;
219222
}
223+
224+
bool IfcGeom::convert_openings_fast(const Ifc2x3::IfcProduct::ptr entity, const Ifc2x3::IfcRelVoidsElement::list& openings,
225+
const ShapeList& entity_shapes, const gp_Trsf& entity_trsf, ShapeList& cut_shapes) {
226+
227+
// Create a compound of all opening shapes in order to speed up the boolean operations
228+
TopoDS_Compound opening_compound;
229+
BRep_Builder builder;
230+
builder.MakeCompound(opening_compound);
231+
232+
for ( Ifc2x3::IfcRelVoidsElement::it it = openings->begin(); it != openings->end(); ++ it ) {
233+
Ifc2x3::IfcRelVoidsElement::ptr v = *it;
234+
Ifc2x3::IfcFeatureElementSubtraction::ptr fes = v->RelatedOpeningElement();
235+
if ( fes->is(Ifc2x3::Type::IfcOpeningElement) ) {
236+
237+
// Convert the IfcRepresentation of the IfcOpeningElement
238+
gp_Trsf opening_trsf;
239+
IfcGeom::convert(fes->ObjectPlacement(),opening_trsf);
240+
241+
// Move the opening into the coordinate system of the IfcProduct
242+
opening_trsf.PreMultiply(entity_trsf.Inverted());
243+
244+
Ifc2x3::IfcProductRepresentation::ptr prodrep = fes->Representation();
245+
Ifc2x3::IfcRepresentation::list reps = prodrep->Representations();
246+
247+
IfcGeom::ShapeList opening_shapes;
248+
249+
for ( Ifc2x3::IfcRepresentation::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
250+
IfcGeom::convert_shapes(*it2,opening_shapes);
251+
}
252+
253+
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
254+
gp_GTrsf& gtrsf = *opening_shapes[i].first;
255+
gtrsf.PreMultiply(opening_trsf);
256+
const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other
257+
? BRepBuilderAPI_GTransform(*opening_shapes[i].second,gtrsf,true).Shape()
258+
: (*opening_shapes[i].second).Moved(gtrsf.Trsf());
259+
builder.Add(opening_compound,opening_shape);
260+
}
261+
262+
for ( IfcGeom::ShapeList::const_iterator it5 = opening_shapes.begin(); it5 != opening_shapes.end(); ++ it5 ) {
263+
delete it5->first;
264+
}
265+
}
266+
}
267+
268+
// Iterate over the shapes of the IfcProduct
269+
for ( IfcGeom::ShapeList::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
270+
TopoDS_Shape entity_shape_solid;
271+
const TopoDS_Shape& entity_shape_unlocated = IfcGeom::ensure_fit_for_subtraction(*(it3->second),entity_shape_solid);
272+
const gp_GTrsf& entity_shape_gtrsf = *(it3->first);
273+
TopoDS_Shape entity_shape;
274+
if ( entity_shape_gtrsf.Form() == gp_Other ) {
275+
Ifc::LogMessage("Warning","Applying non uniform transformation to:",entity->entity);
276+
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
277+
} else {
278+
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
279+
}
280+
281+
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound);
282+
bool is_valid = false;
283+
if ( brep_cut.IsDone() ) {
284+
TopoDS_Shape brep_cut_result = brep_cut;
285+
286+
BRepCheck_Analyzer analyser(brep_cut_result);
287+
is_valid = analyser.IsValid() != 0;
288+
if ( is_valid ) {
289+
cut_shapes.push_back(IfcGeom::LocationShape(new gp_GTrsf(),new TopoDS_Shape(brep_cut_result)));
290+
}
291+
}
292+
if ( !is_valid ) {
293+
// Apparently processing the boolean operation failed or resulted in an invalid result
294+
// in which case the original shape without the subtractions is returned instead
295+
// we try convert the openings in the original way, one by one.
296+
Ifc::LogMessage("Warning","Subtracting combined openings compound failed:",entity->entity);
297+
return false;
298+
}
299+
300+
}
301+
return true;
302+
}
303+
220304
bool IfcGeom::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
221305
BRepBuilderAPI_MakeFace mf(wire, false);
222306
BRepBuilderAPI_FaceError er = mf.Error();

src/ifcgeom/IfcGeomObjects.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
// Welds vertices that belong to different faces
4949
bool weld_vertices = true;
5050
bool convert_back_units = false;
51+
bool use_faster_booleans = false;
5152

5253
int IfcGeomObjects::IfcMesh::addvert(const gp_XYZ& p) {
5354
const float X = convert_back_units ? (float) (p.X() / Ifc::LengthUnit) : (float)p.X();
@@ -386,7 +387,19 @@ IfcGeomObjects::IfcGeomObject* _get() {
386387
if ( openings && openings->Size() ) {
387388
IfcGeom::ShapeList opened_shapes;
388389
try {
389-
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
390+
if ( use_faster_booleans ) {
391+
bool succes = IfcGeom::convert_openings_fast(ifc_product,openings,shapes,trsf,opened_shapes);
392+
if ( ! succes ) {
393+
for ( IfcGeom::ShapeList::const_iterator it = opened_shapes.begin(); it != opened_shapes.end(); ++ it ) {
394+
delete it->first;
395+
delete it->second;
396+
}
397+
opened_shapes.clear();
398+
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
399+
}
400+
} else {
401+
IfcGeom::convert_openings(ifc_product,openings,shapes,trsf,opened_shapes);
402+
}
390403
} catch(...) {
391404
Ifc::LogMessage("Error","Error processing openings for:",ifc_product->entity);
392405
}
@@ -521,6 +534,9 @@ void IfcGeomObjects::Settings(int setting, bool value) {
521534
case USE_BREP_DATA:
522535
use_brep_data = value;
523536
break;
537+
case FASTER_BOOLEANS:
538+
use_faster_booleans = value;
539+
break;
524540
case SEW_SHELLS:
525541
Ifc::SewShells = value;
526542
break;

src/ifcgeom/IfcGeomObjects.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ namespace IfcGeomObjects {
9191
// Specifies whether to sew IfcConnectedFaceSets (open and closed shells) to
9292
// TopoDS_Shells or whether to keep them as a loose collection of faces.
9393
const int SEW_SHELLS = 5;
94+
// Specifies whether to compose IfcOpeningElements into a single compound
95+
// in order to speed up the processing of opening subtractions.
96+
const int FASTER_BOOLEANS = 6;
9497

9598
// End of settings enumeration.
9699

src/ifcparse/IfcParse.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,3 +868,4 @@ MapEntityByGuid Ifc::byguid;
868868
MapEntitiesByRef Ifc::byref;
869869
MapOffsetById Ifc::offsets;
870870
std::stringstream Ifc::log_stream;
871+
int Ifc::Verbosity = 2;

src/ifcparse/IfcParse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ class Ifc {
272272
static double LengthUnit;
273273
static double PlaneAngleUnit;
274274
static int CircleSegments;
275+
static int Verbosity;
275276
};
276277

277278
double UnitPrefixToValue( Ifc2x3::IfcSIPrefix::IfcSIPrefix v );

0 commit comments

Comments
 (0)