diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index a8765b06ea..3a11f45b71 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -218,6 +218,7 @@ int main(int argc, char** argv) { ("help,h", "display usage information") ("version", "display version information") ("verbose,v", po::value(&vcounter)->zero_tokens(), "more verbose log messages. Use twice (-vv) for debugging level.") + ("debug,d", "write boolean operands to file in current directory for debugging purposes") ("quiet,q", "less status and progress output") #ifdef WITH_HDF5 ("cache", "cache geometry creation. Use --cache-file to specify cache file path.") @@ -793,6 +794,7 @@ int main(int argc, char** argv) { settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, !include_model); settings.set(IfcGeom::IteratorSettings::APPLY_LAYERSETS, enable_layerset_slicing); settings.set(IfcGeom::IteratorSettings::LAYERSET_FIRST, layerset_first); + settings.set(IfcGeom::IteratorSettings::DEBUG_BOOLEAN, vmap.count("debug")); settings.set(IfcGeom::IteratorSettings::NO_NORMALS, no_normals); settings.set(IfcGeom::IteratorSettings::GENERATE_UVS, generate_uvs); settings.set(IfcGeom::IteratorSettings::EDGE_ARROWS, edge_arrows); diff --git a/src/ifcgeom/IfcGeom.h b/src/ifcgeom/IfcGeom.h index aabf995317..67670f2feb 100644 --- a/src/ifcgeom/IfcGeom.h +++ b/src/ifcgeom/IfcGeom.h @@ -273,6 +273,9 @@ private: double no_wire_intersection_check; double no_wire_intersection_tolerance; double precision_factor; + double boolean_debug_setting; + + size_t operation_counter_ = 0; // For stopping PlacementRelTo recursion in convert(const IfcSchema::IfcObjectPlacement* l, gp_Trsf& trsf) const IfcParse::declaration* placement_rel_to_type_; diff --git a/src/ifcgeom/IfcGeomFunctions.cpp b/src/ifcgeom/IfcGeomFunctions.cpp index 3a4681710a..edad0f673e 100644 --- a/src/ifcgeom/IfcGeomFunctions.cpp +++ b/src/ifcgeom/IfcGeomFunctions.cpp @@ -165,6 +165,7 @@ #include "../ifcgeom/IfcGeomTree.h" #include +#include #if OCC_VERSION_HEX < 0x60900 #ifdef _MSC_VER @@ -1487,6 +1488,9 @@ void IfcGeom::Kernel::setValue(GeomValue var, double value) { case GV_NO_WIRE_INTERSECTION_TOLERANCE: no_wire_intersection_tolerance = value; break; + case GV_DEBUG_BOOLEAN: + boolean_debug_setting = value; + break; default: throw std::runtime_error("Invalid setting"); } @@ -1522,6 +1526,8 @@ double IfcGeom::Kernel::getValue(GeomValue var) const { return precision_factor; case GV_NO_WIRE_INTERSECTION_TOLERANCE: return no_wire_intersection_tolerance; + case GV_DEBUG_BOOLEAN: + return boolean_debug_setting; } throw std::runtime_error("Invalid setting"); } @@ -4260,6 +4266,15 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a, const TopoDS_Shap bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a_, const TopTools_ListOfShape& b__, BOPAlgo_Operation op, TopoDS_Shape& result, double fuzziness) { + const bool debug = getValue(GV_DEBUG_BOOLEAN) > 0.; + std::string debug_identifier; + if (debug) { + std::stringstream ss; + ss << "bool-" << std::this_thread::get_id() << "-" << (operation_counter_++); + debug_identifier = ss.str(); + Logger::Notice("Boolean debug identifier: " + debug_identifier); + } + if (fuzziness < 0.) { fuzziness = getValue(GV_PRECISION) / 10.; } @@ -4314,8 +4329,22 @@ bool IfcGeom::Kernel::boolean_operation(const TopoDS_Shape& a_, const TopTools_L const double fuzz = (std::min)(min_length_orig / 3., fuzziness); + Logger::Notice("Used fuzziness: " + std::to_string(fuzz)); + TopTools_ListOfShape s1s; s1s.Append(copy_operand(a)); + + if (debug) { + TopTools_ListOfShape* lists[2] = { &s1s, &b }; + static std::string operand_names[2] = { "a", "b" }; + for (int i = 0; i < 2; ++i) { + TopTools_ListIteratorOfListOfShape it(*lists[i]); + for (int j = 0; it.More(); it.Next(), ++j) { + std::string fn = debug_identifier + "-" + operand_names[i] + "-" + std::to_string(j) + ".brep"; + BRepTools::Write(it.Value(), fn.c_str()); + } + } + } #if OCC_VERSION_HEX >= 0x70000 builder->SetNonDestructive(true); #endif diff --git a/src/ifcgeom/IfcGeomIteratorImplementation.h b/src/ifcgeom/IfcGeomIteratorImplementation.h index 1f396a6866..fae39da274 100644 --- a/src/ifcgeom/IfcGeomIteratorImplementation.h +++ b/src/ifcgeom/IfcGeomIteratorImplementation.h @@ -1167,6 +1167,12 @@ namespace IfcGeom { : -1.0 ); + kernel.setValue(IfcGeom::Kernel::GV_DEBUG_BOOLEAN, + settings.get(IteratorSettings::DEBUG_BOOLEAN) + ? +1.0 + : -1.0 + ); + if (settings.get(IteratorSettings::BUILDING_LOCAL_PLACEMENT)) { if (settings.get(IteratorSettings::SITE_LOCAL_PLACEMENT)) { Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement"); diff --git a/src/ifcgeom/IfcGeomIteratorSettings.h b/src/ifcgeom/IfcGeomIteratorSettings.h index c60c6539af..a525986cb5 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.h +++ b/src/ifcgeom/IfcGeomIteratorSettings.h @@ -111,8 +111,10 @@ namespace IfcGeom /// Strictly use the tolerance from the IFC model. Typically this value is /// increased 10-fold to have more reliable boolean subtraction results. STRICT_TOLERANCE = 1 << 22, + /// Write boolean operands to file in current directory for debugging purposes + DEBUG_BOOLEAN = 1 << 23, /// Number of different setting flags. - NUM_SETTINGS = 23, + NUM_SETTINGS = 24, }; IteratorSettings() diff --git a/src/ifcgeom_schema_agnostic/Kernel.h b/src/ifcgeom_schema_agnostic/Kernel.h index 6d2b478f98..f13178e6ef 100644 --- a/src/ifcgeom_schema_agnostic/Kernel.h +++ b/src/ifcgeom_schema_agnostic/Kernel.h @@ -76,6 +76,7 @@ namespace IfcGeom { GV_NO_WIRE_INTERSECTION_CHECK, GV_PRECISION_FACTOR, GV_NO_WIRE_INTERSECTION_TOLERANCE, + GV_DEBUG_BOOLEAN }; Kernel(IfcParse::IfcFile* file_ = 0);