Use multiple argument boolean operands for IfcOpeningElement subtractions

This commit is contained in:
aothms
2016-01-25 13:30:33 +01:00
parent 4be7da1a43
commit 801c7da40f
2 changed files with 110 additions and 14 deletions
+11
View File
@@ -44,6 +44,7 @@
#include "../ifcconvert/SvgSerializer.h"
#include <IGESControl_Controller.hxx>
#include <Standard_Version.hxx>
static std::string DEFAULT_EXTENSION = "obj";
@@ -123,11 +124,17 @@ int main(int argc, char** argv) {
"This is a potentially time consuming operation, but guarantees a "
"consistent orientation of surface normals, even if the faces are not "
"properly oriented in the IFC file.")
#if OCC_VERSION_HEX < 0x60900
// In Open CASCADE version prior to 6.9.0 boolean operations with multiple
// arguments where not introduced yet and a work-around was implemented to
// subtract multiple openings as a single compound. This hack is obsolete
// for newer versions of Open CASCADE.
("merge-boolean-operands",
"Specifies whether to merge all IfcOpeningElement operands into a single "
"operand before applying the subtraction operation. This may "
"introduce a performance improvement at the risk of failing, in "
"which case the subtraction is applied one-by-one.")
#endif
("disable-opening-subtractions",
"Specifies whether to disable the boolean subtraction of "
"IfcOpeningElement Representations from their RelatingElements.")
@@ -179,7 +186,9 @@ int main(int argc, char** argv) {
const bool use_world_coords = vmap.count("use-world-coords") != 0;
const bool convert_back_units = vmap.count("convert-back-units") != 0;
const bool sew_shells = vmap.count("sew-shells") != 0;
#if OCC_VERSION_HEX < 0x60900
const bool merge_boolean_operands = vmap.count("merge-boolean-operands") != 0;
#endif
const bool disable_opening_subtractions = vmap.count("disable-opening-subtractions") != 0;
bool include_entities = vmap.count("include") != 0;
const bool include_plan = vmap.count("plan") != 0;
@@ -257,7 +266,9 @@ int main(int argc, char** argv) {
settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices);
settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, sew_shells);
settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units);
#if OCC_VERSION_HEX < 0x60900
settings.set(IfcGeom::IteratorSettings::FASTER_BOOLEANS, merge_boolean_operands);
#endif
settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions);
settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan);
settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model);
+99 -14
View File
@@ -105,6 +105,10 @@
#include "../ifcparse/IfcSIPrefix.h"
#include "../ifcgeom/IfcGeom.h"
#if OCC_VERSION_HEX < 0x60900
#pragma message("warning: You are linking against Open CASCADE version " OCC_VERSION_COMPLETE ". Version 6.9.0 introduces various improvements with relation to boolean operations. You are advised to upgrade.")
#endif
bool IfcGeom::Kernel::create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& shape) {
BRepOffsetAPI_Sewing builder;
builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE));
@@ -323,6 +327,7 @@ bool IfcGeom::Kernel::convert_openings(const IfcSchema::IfcProduct* entity, cons
return true;
}
#if OCC_VERSION_HEX < 0x60900
bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
@@ -382,19 +387,7 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
}
#if OCC_VERSION_HEX < 0x60900
BRepAlgoAPI_Cut brep_cut(entity_shape,opening_compound);
#else
BRepAlgoAPI_Cut brep_cut;
TopTools_ListOfShape s1s;
s1s.Append(entity_shape);
TopTools_ListOfShape s2s;
s2s.Append(opening_compound);
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
brep_cut.SetArguments(s1s);
brep_cut.SetTools(s2s);
brep_cut.Build();
#endif
bool is_valid = false;
if ( brep_cut.IsDone() ) {
@@ -417,6 +410,93 @@ bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity,
}
return true;
}
#else
bool IfcGeom::Kernel::convert_openings_fast(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings,
const IfcGeom::IfcRepresentationShapeItems& entity_shapes, const gp_Trsf& entity_trsf, IfcGeom::IfcRepresentationShapeItems& cut_shapes) {
TopTools_ListOfShape opening_shapelist;
for ( IfcSchema::IfcRelVoidsElement::list::it it = openings->begin(); it != openings->end(); ++ it ) {
IfcSchema::IfcRelVoidsElement* v = *it;
IfcSchema::IfcFeatureElementSubtraction* fes = v->RelatedOpeningElement();
if ( fes->is(IfcSchema::Type::IfcOpeningElement) ) {
if (!fes->hasRepresentation()) continue;
// Convert the IfcRepresentation of the IfcOpeningElement
gp_Trsf opening_trsf;
if (fes->hasObjectPlacement()) {
try {
convert(fes->ObjectPlacement(),opening_trsf);
} catch (...) {}
}
// Move the opening into the coordinate system of the IfcProduct
opening_trsf.PreMultiply(entity_trsf.Inverted());
IfcSchema::IfcProductRepresentation* prodrep = fes->Representation();
IfcSchema::IfcRepresentation::list::ptr reps = prodrep->Representations();
IfcGeom::IfcRepresentationShapeItems opening_shapes;
for ( IfcSchema::IfcRepresentation::list::it it2 = reps->begin(); it2 != reps->end(); ++ it2 ) {
convert_shapes(*it2,opening_shapes);
}
for ( unsigned int i = 0; i < opening_shapes.size(); ++ i ) {
gp_GTrsf gtrsf = opening_shapes[i].Placement();
gtrsf.PreMultiply(opening_trsf);
const TopoDS_Shape& opening_shape = gtrsf.Form() == gp_Other
? BRepBuilderAPI_GTransform(opening_shapes[i].Shape(),gtrsf,true).Shape()
: (opening_shapes[i].Shape()).Moved(gtrsf.Trsf());
opening_shapelist.Append(opening_shape);
}
}
}
// Iterate over the shapes of the IfcProduct
for ( IfcGeom::IfcRepresentationShapeItems::const_iterator it3 = entity_shapes.begin(); it3 != entity_shapes.end(); ++ it3 ) {
TopoDS_Shape entity_shape_solid;
const TopoDS_Shape& entity_shape_unlocated = ensure_fit_for_subtraction(it3->Shape(),entity_shape_solid);
const gp_GTrsf& entity_shape_gtrsf = it3->Placement();
TopoDS_Shape entity_shape;
if ( entity_shape_gtrsf.Form() == gp_Other ) {
Logger::Message(Logger::LOG_WARNING,"Applying non uniform transformation to:",entity->entity);
entity_shape = BRepBuilderAPI_GTransform(entity_shape_unlocated,entity_shape_gtrsf,true).Shape();
} else {
entity_shape = entity_shape_unlocated.Moved(entity_shape_gtrsf.Trsf());
}
BRepAlgoAPI_Cut brep_cut;
TopTools_ListOfShape s1s;
s1s.Append(entity_shape);
brep_cut.SetFuzzyValue(getValue(GV_PRECISION));
brep_cut.SetArguments(s1s);
brep_cut.SetTools(opening_shapelist);
brep_cut.Build();
bool is_valid = false;
if ( brep_cut.IsDone() ) {
TopoDS_Shape brep_cut_result = brep_cut;
BRepCheck_Analyzer analyser(brep_cut_result);
is_valid = analyser.IsValid() != 0;
if ( is_valid ) {
cut_shapes.push_back(IfcGeom::IfcRepresentationShapeItem(brep_cut_result, &it3->Style()));
}
}
if ( !is_valid ) {
// Apparently processing the boolean operation failed or resulted in an invalid result
// in which case the original shape without the subtractions is returned instead
// we try convert the openings in the original way, one by one.
Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity);
return false;
}
}
return true;
}
#endif
bool IfcGeom::Kernel::convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face) {
BRepBuilderAPI_MakeFace mf(wire, false);
@@ -919,7 +999,7 @@ void IfcGeom::Kernel::remove_collinear_points_from_loop(TColgp_SequenceOfPnt& po
to_remove[i-1] = true;
}
}
for (int i = to_remove.size() - 1; i >= 0; --i) {
for (int i = (int) to_remove.size() - 1; i >= 0; --i) {
if (to_remove[i]) {
polygon.Remove(i+1);
}
@@ -1020,7 +1100,12 @@ IfcGeom::BRepElement<P>* IfcGeom::Kernel::create_brep_for_representation_and_pro
if ( !settings.disable_opening_subtractions() && openings && openings->size() ) {
IfcGeom::IfcRepresentationShapeItems opened_shapes;
try {
if ( settings.faster_booleans() ) {
#if OCC_VERSION_HEX < 0x60900
const bool faster_booleans = settings.faster_booleans();
#else
const bool faster_booleans = true;
#endif
if (faster_booleans) {
bool succes = convert_openings_fast(product,openings,shapes,trsf,opened_shapes);
if ( ! succes ) {
opened_shapes.clear();