diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 917e66d192..baafc5c459 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -258,10 +258,14 @@ if(WITH_ROCKSDB) set(ROCKSDB_LIBRARIES "IFCOPENSHELL_RocksDB") target_compile_definitions(IFCOPENSHELL_RocksDB INTERFACE IFOPSH_WITH_ROCKSDB) set(SWIG_DEFINES ${SWIG_DEFINES} -DIFOPSH_WITH_ROCKSDB) - # Shared binaries for `rocksdb` only support limited API (only `c.h`), but we use `db.h` API. - # So rocksdb supported only as a static library. # See https://github.com/facebook/rocksdb/issues/981. - target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb) + if(TARGET RocksDB::rocksdb) + target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb) + elseif(TARGET RocksDB::rocksdb-shared) + target_link_libraries(IFCOPENSHELL_RocksDB INTERFACE RocksDB::rocksdb-shared) + else() + message(FATAL_ERROR "RocksDB found but neither RocksDB::rocksdb nor RocksDB::rocksdb-shared target exists") + endif() if(WITH_ZSTD) # @todo do we actually need the zstd include dir or rather just pass diff --git a/cmake/FindHDF5.cmake b/cmake/FindHDF5.cmake index 399b1c9f13..3230336a7d 100644 --- a/cmake/FindHDF5.cmake +++ b/cmake/FindHDF5.cmake @@ -88,7 +88,15 @@ if(NOT HDF5_INCLUDE_DIR OR NOT HDF5_LIBRARY_DIR) mark_as_advanced(HDF5_DIR) if(HDF5_DIR) message(STATUS "HDF5: found config at '${HDF5_DIR}'.") - set(HDF5_LIBRARIES hdf5_cpp-static) + if(TARGET hdf5_cpp-static) + set(HDF5_LIBRARIES hdf5_cpp-static) + elseif(TARGET hdf5_cpp-shared) + set(HDF5_LIBRARIES hdf5_cpp-shared) + elseif(TARGET hdf5::hdf5_cpp-shared) + set(HDF5_LIBRARIES hdf5::hdf5_cpp-shared) + else() + find_package(HDF5 REQUIRED COMPONENTS CXX) + endif() else() # If it failed, still try to find as a module. # E.g. on Ubuntu `libhdf5-dev` doesn't provie hdf5-config.cmake. diff --git a/src/bonsai/test/files/snap-target.ifc b/src/bonsai/test/files/snap-target.ifc new file mode 100644 index 0000000000..0b7132dece --- /dev/null +++ b/src/bonsai/test/files/snap-target.ifc @@ -0,0 +1,91 @@ +ISO-10303-21; +HEADER; +FILE_DESCRIPTION(('ViewDefinition[DesignTransferView]'),'2;1'); +FILE_NAME('snap-target.ifc','2026-06-05T17:45:10-03:00',(''),(''),'IfcOpenShell 0.0.0','Bonsai 0.8.6-alpha260605-24a241a','Nobody'); +FILE_SCHEMA(('IFC4')); +ENDSEC; +DATA; +#1=IFCPROJECT('2pZygwkcb1Au$5kgwmW6ZC',$,'My Project',$,$,$,$,(#10,#22),#5); +#2=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.); +#3=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); +#4=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); +#5=IFCUNITASSIGNMENT((#4,#2,#3)); +#6=IFCCARTESIANPOINT((0.,0.,0.)); +#7=IFCDIRECTION((0.,0.,1.)); +#8=IFCDIRECTION((1.,0.,0.)); +#9=IFCAXIS2PLACEMENT3D(#6,#7,#8); +#10=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Model',3,1.E-05,#9,$); +#11=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$); +#12=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Model',*,*,*,*,#10,$,.GRAPH_VIEW.,$); +#13=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Box','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$); +#14=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#10,$,.SECTION_VIEW.,$); +#15=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#10,$,.ELEVATION_VIEW.,$); +#16=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#10,$,.MODEL_VIEW.,$); +#17=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Model',*,*,*,*,#10,$,.PLAN_VIEW.,$); +#18=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Profile','Model',*,*,*,*,#10,$,.ELEVATION_VIEW.,$); +#19=IFCCARTESIANPOINT((0.,0.)); +#20=IFCDIRECTION((1.,0.)); +#21=IFCAXIS2PLACEMENT2D(#19,#20); +#22=IFCGEOMETRICREPRESENTATIONCONTEXT($,'Plan',2,1.E-05,#21,$); +#23=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Axis','Plan',*,*,*,*,#22,$,.GRAPH_VIEW.,$); +#24=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Body','Plan',*,*,*,*,#22,$,.PLAN_VIEW.,$); +#25=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#22,$,.PLAN_VIEW.,$); +#26=IFCGEOMETRICREPRESENTATIONSUBCONTEXT('Annotation','Plan',*,*,*,*,#22,$,.REFLECTED_PLAN_VIEW.,$); +#27=IFCSITE('1Lvnr1aSn2OP70jevISY_C',$,'My Site',$,$,#50,$,$,$,$,$,$,$,$); +#33=IFCBUILDING('1NaNtC8Wf6YPU7CZRG8Z8Q',$,'My Building',$,$,#56,$,$,$,$,$,$); +#39=IFCBUILDINGSTOREY('1k9kfaMOr2cvyNvxvoll27',$,'My Storey',$,$,#62,$,$,$,$); +#45=IFCRELAGGREGATES('1plJGwDIHDzwuc7i7gcQQD',$,$,$,#1,(#27)); +#46=IFCCARTESIANPOINT((0.,0.,0.)); +#47=IFCDIRECTION((0.,0.,1.)); +#48=IFCDIRECTION((1.,0.,0.)); +#49=IFCAXIS2PLACEMENT3D(#46,#47,#48); +#50=IFCLOCALPLACEMENT($,#49); +#51=IFCRELAGGREGATES('13KnzD8ZT8bAvAyOQAWiUj',$,$,$,#27,(#33)); +#52=IFCCARTESIANPOINT((0.,0.,0.)); +#53=IFCDIRECTION((0.,0.,1.)); +#54=IFCDIRECTION((1.,0.,0.)); +#55=IFCAXIS2PLACEMENT3D(#52,#53,#54); +#56=IFCLOCALPLACEMENT(#50,#55); +#57=IFCRELAGGREGATES('2Hf4WQLJvE4O43wq$0AZeu',$,$,$,#33,(#39)); +#58=IFCCARTESIANPOINT((0.,0.,0.)); +#59=IFCDIRECTION((0.,0.,1.)); +#60=IFCDIRECTION((1.,0.,0.)); +#61=IFCAXIS2PLACEMENT3D(#58,#59,#60); +#62=IFCLOCALPLACEMENT(#56,#61); +#63=IFCPROPERTYSINGLEVALUE('Symbol',$,IFCLABEL('setout-point'),$); +#64=IFCPROPERTYSET('27lmSbeAXC08EWkEq8XdUG',$,'EPset_Annotation',$,(#63)); +#65=IFCTYPEPRODUCT('0UrP0fLdD5OwzwD41aRKao',$,'SETOUT-POINT',$,'IfcAnnotation/SYMBOL',(#64),$,$); +#66=IFCCARTESIANPOINTLIST3D(((-8999.9990234375,-8999.9990234375,0.),(8999.9990234375,-8999.9990234375,0.),(-8999.9990234375,8999.9990234375,0.),(8999.9990234375,8999.9990234375,0.))); +#67=IFCINDEXEDPOLYGONALFACE((1,2,4,3)); +#68=IFCPOLYGONALFACESET(#66,$,(#67),$); +#69=IFCSHAPEREPRESENTATION(#11,'Body','Tessellation',(#68)); +#70=IFCBUILDINGELEMENTPROXY('3Avrn7zrPBiA7RUh91ENg9',$,'Plane',$,$,#142,#72,$,.COMPLEX.); +#71=IFCRELCONTAINEDINSPATIALSTRUCTURE('0ftVF1Vf1Dmg$p62mtpWVF',$,$,$,(#123,#70,#108),#39); +#72=IFCPRODUCTDEFINITIONSHAPE($,$,(#69)); +#108=IFCBUILDINGELEMENTPROXY('1lwURx5YX5WAXD5ExqQt31',$,'Plane',$,$,#122,#117,$,.COMPLEX.); +#114=IFCCARTESIANPOINTLIST3D(((-5999.99951171875,-2999.99975585938,0.),(5999.99951171875,-2999.99975585938,0.))); +#115=IFCINDEXEDPOLYCURVE(#114,(IFCLINEINDEX((1,2))),$); +#116=IFCSHAPEREPRESENTATION(#11,'Body','Curve3D',(#115)); +#117=IFCPRODUCTDEFINITIONSHAPE($,$,(#116)); +#118=IFCCARTESIANPOINT((0.,0.,0.)); +#119=IFCDIRECTION((0.,0.,1.)); +#120=IFCDIRECTION((1.,0.,0.)); +#121=IFCAXIS2PLACEMENT3D(#118,#119,#120); +#122=IFCLOCALPLACEMENT(#62,#121); +#123=IFCBUILDINGELEMENTPROXY('2X4YMFxHjANvnkl1Hzqjlq',$,'Plane',$,$,#137,#132,$,.COMPLEX.); +#129=IFCCARTESIANPOINTLIST3D(((3000.,-5999.99951171875,0.),(2999.99951171875,5999.99951171875,0.))); +#130=IFCINDEXEDPOLYCURVE(#129,(IFCLINEINDEX((1,2))),$); +#131=IFCSHAPEREPRESENTATION(#11,'Body','Curve3D',(#130)); +#132=IFCPRODUCTDEFINITIONSHAPE($,$,(#131)); +#133=IFCCARTESIANPOINT((0.,0.,0.)); +#134=IFCDIRECTION((0.,0.,1.)); +#135=IFCDIRECTION((1.,0.,0.)); +#136=IFCAXIS2PLACEMENT3D(#133,#134,#135); +#137=IFCLOCALPLACEMENT(#62,#136); +#138=IFCCARTESIANPOINT((0.,0.,0.)); +#139=IFCDIRECTION((0.,0.,1.)); +#140=IFCDIRECTION((1.,0.,0.)); +#141=IFCAXIS2PLACEMENT3D(#138,#139,#140); +#142=IFCLOCALPLACEMENT(#62,#141); +ENDSEC; +END-ISO-10303-21; diff --git a/src/bonsai/test/modal/test_modal.py b/src/bonsai/test/modal/test_modal.py index 27e290ae3f..07ce8b90ed 100644 --- a/src/bonsai/test/modal/test_modal.py +++ b/src/bonsai/test/modal/test_modal.py @@ -296,6 +296,63 @@ def test_snap_far_from_origin(window): yield from preset_event_simulate(window, "RET", "TAP", x, y) yield "FINISHED" +def test_snap_targets(window): + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", 0, 0) + area, region = get_area_and_region(window) + x = round(area.width * 0.44 + area.x) + y = round(area.height * 0.73 + area.y) + + yield from preset_event_simulate(window, "ESC", "TAP", x, y) + + options = [] + props = tool.Snap.get_snap_props() + try: + annotations = props.__annotations__ + except AttributeError: + annotations = type(props).__annotations__ + for prop in annotations.keys(): + if getattr(props, prop): + options.append((prop, props.rna_type.properties[prop].name)) + + for prop, name in options: + any(setattr(props, prop2, prop2 == prop) for prop2, _ in options) # set prop to true and others to false + measure_settings = tool.Project.get_measure_tool_settings() + measure_settings.measurement_type = "POLYLINE" + for obj in tool.Blender.get_selected_objects(): + obj.select_set(False) + with bpy.context.temp_override(area=area, region=region, space_data=area.spaces[0]): + bpy.ops.bim.measure_tool("INVOKE_DEFAULT", measure_type="POLYLINE") + snap_types = [] + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", x, y) + yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y) + snap_type = tool.Model.get_polyline_props().snap_mouse_point[0].snap_type + snap_types.append(snap_type) + + new_x = x + 200 + new_y = y - 55 + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y) + snap_type = tool.Model.get_polyline_props().snap_mouse_point[0].snap_type + snap_types.append(snap_type) + + new_x = x + 130 + new_y = y - 358 + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "MOUSEMOVE", "NOTHING", new_x, new_y) + yield from preset_event_simulate(window, "LEFTMOUSE", "TAP", x, y) + snap_type = tool.Model.get_polyline_props().snap_mouse_point[0].snap_type + snap_types.append(snap_type) + + yield from preset_event_simulate(window, "ESC", "TAP", x, y) + assert_msg = f"{name} should be in snap_types: {snap_types}" + assert name in snap_types + _assert_pass(assert_msg) + def test_draw_polyline_wall(window, x, y): yield from preset_event_simulate(window, "ESC", "TAP", x, y) area, region = get_area_and_region(window) @@ -358,6 +415,13 @@ def run_tests(): lambda w=window: test_snap_in_xray_mode(w), lambda w=window: test_snap_far_from_origin(w), ] + elif module_name == "snap-target": + filepath = f"./test/files/snap-target.ifc" + bpy.ops.bim.load_project(filepath=filepath) + window = _get_valid_window() + test_queue = [ + lambda w=window: test_snap_targets(w), + ] else: cleanup() diff --git a/src/ifcgeom/AbstractKernel.h b/src/ifcgeom/AbstractKernel.h index cd29246710..3e2be1b1f0 100644 --- a/src/ifcgeom/AbstractKernel.h +++ b/src/ifcgeom/AbstractKernel.h @@ -149,8 +149,12 @@ namespace { template <> struct dispatch_conversion { - static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, ifcopenshell::geometry::taxonomy::kinds, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) { - Logger::Error("No conversion for " + std::to_string(item->kind())); + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, ifcopenshell::geometry::taxonomy::kinds, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) { + std::string created_from; + if (item->instance) { + created_from = " (created from " + item->instance->declaration().name() + ")"; + } + Logger::Error("No support for " + ifcopenshell::geometry::taxonomy::kind_to_string(item->kind()) + created_from + " in kernel " + kernel->geometry_library()); return false; } }; @@ -169,8 +173,12 @@ namespace { template <> struct dispatch_with_upgrade { - static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) { - Logger::Error("No conversion with upgrade for " + std::to_string(item->kind())); + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::ptr& item, IfcGeom::ConversionResults&) { + std::string created_from; + if (item->instance) { + created_from = " (created from " + item->instance->declaration().name() + ")"; + } + Logger::Error("No support (after considering item upgrade) for " + ifcopenshell::geometry::taxonomy::kind_to_string(item->kind()) + created_from + " in kernel " + kernel->geometry_library()); return false; } }; diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index 0d7e179d7b..68542dd23c 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -35,13 +35,25 @@ namespace IfcGeom { class Transformation { private: ifcopenshell::geometry::Settings settings_; - ifcopenshell::geometry::taxonomy::matrix4::ptr matrix_; + ifcopenshell::geometry::taxonomy::matrix4::ptr matrix_, matrix_orig_units_; public: - Transformation(const ifcopenshell::geometry::Settings& settings, const ifcopenshell::geometry::taxonomy::matrix4::ptr& matrix) - : settings_(settings) - , matrix_(matrix) - {} + Transformation(const ifcopenshell::geometry::Settings& settings, const ifcopenshell::geometry::taxonomy::matrix4::ptr& matrix) + : settings_(settings), matrix_(matrix) + { + const bool convert = settings.get().get(); + auto unit_magnitude = settings.get().get(); + if (matrix_ && convert && unit_magnitude != 1.0) { + matrix_orig_units_ = ifcopenshell::geometry::taxonomy::make(*matrix); + // only multiple the translation components of the matrix with the unit magnitude, not the rotation/scaling components + matrix_orig_units_->components().col(3).head<3>() /= unit_magnitude; + } else { + matrix_orig_units_ = nullptr; + } + } const ifcopenshell::geometry::taxonomy::matrix4::ptr& data() const { + if (matrix_orig_units_) { + return matrix_orig_units_; + } if (matrix_) { return matrix_; } diff --git a/src/ifcgeom/kernels/cgal/nef_to_halfspace_tree.h b/src/ifcgeom/kernels/cgal/nef_to_halfspace_tree.h index fa410a84f9..368e49a2d2 100644 --- a/src/ifcgeom/kernels/cgal/nef_to_halfspace_tree.h +++ b/src/ifcgeom/kernels/cgal/nef_to_halfspace_tree.h @@ -116,6 +116,16 @@ template using plane_map = std::map>; // using plane_map = std::unordered_map>; +// Lexicographic comparator for CGAL Point_d (operator< is deleted in CGAL 6.x) +struct Point_d_4d_Less { + using Point_d = CGAL::Epick_d>::Point_d; + bool operator()(const Point_d& a, const Point_d& b) const { + return std::lexicographical_compare( + a.cartesian_begin(), a.cartesian_end(), + b.cartesian_begin(), b.cartesian_end()); + } +}; + // Snap halfspace planes // search_radius: max cartesian distance in plane equation parameters as 4d points in space template @@ -131,8 +141,8 @@ plane_map snap_halfspaces(const std::list>& planes plane_map result; - std::map> neighbours; - std::map>> originals; + std::map, Point_d_4d_Less> neighbours; + std::map>, Point_d_4d_Less> originals; std::vector planes_as_point; for (auto& p : planes) { @@ -205,7 +215,7 @@ plane_map snap_halfspaces_2(const std::list>& plan plane_map result; std::vector planes_as_point; - std::map> normalized_to_original; + std::map, Point_d_4d_Less> normalized_to_original; for (auto& p : planes_fixed) { // @todo can we skip normalization (simply divide by largest component perhaps) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index 46e0f06731..aa5ae456a4 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp index e8b672906e..85125f092c 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp @@ -136,17 +136,39 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const IfcUtil::IfcBaseEntity* for (auto entity_part : parts) { bool is_manifold = util::is_manifold(entity_part); + if (!is_manifold) { + // force sewing, edge identity might have been mudied by FixAdvFace.FixOrientation.MSG5 to fix interior loop winding order + TopTools_ListOfShape list; + IfcGeom::util::shape_to_face_list(entity_part, list); + IfcGeom::util::create_solid_from_faces(list, entity_part, settings_.get().get(), true); + is_manifold = util::is_manifold(entity_part); + if (is_manifold) { + Logger::Warning("Successfully sewed non-manifold first operand"); + } + } + if (!is_manifold) { if (settings_.get().get()) { BOPAlgo_MakerVolume mv; mv.AddArgument(entity_part); mv.SetAvoidInternalShapes(true); + // mv.SetFuzzyValue(settings_.get().get()); + std::optional failure; try { mv.Perform(); - entity_part = mv.Shape(); - Logger::Warning("Sucessfully detected exterior volume to non-manifold first operand"); + auto entity_part_2 = mv.Shape(); + if (IfcGeom::util::count(entity_part_2, TopAbs_FACE) == 0) { + failure = "Empty result (no faces) for BOPAlgo_MakerVolume; original was " + std::to_string(IfcGeom::util::count(entity_part, TopAbs_FACE)); + } else { + is_manifold = util::is_manifold(entity_part_2); + Logger::Warning(std::string("Sucessfully detected exterior volume to non-manifold first operand; shape is now ") + (is_manifold ? std::string("manifold") : std::string("non-manifold"))); + entity_part = entity_part_2; + } } catch (const Standard_Failure& e) { - Logger::Warning("MakeVolume failed: " + std::string(e.GetMessageString()), entity); + failure.emplace(e.GetMessageString()); + } + if (failure) { + Logger::Warning("MakeVolume failed: " + *failure, entity); } } else { Logger::Warning("Non-manifold first operand, use --make-volume to try and make manifold"); diff --git a/src/ifcgeom/kernels/opencascade/clash_utils.cpp b/src/ifcgeom/kernels/opencascade/clash_utils.cpp index d6050bf87c..cfc7687b73 100644 --- a/src/ifcgeom/kernels/opencascade/clash_utils.cpp +++ b/src/ifcgeom/kernels/opencascade/clash_utils.cpp @@ -1,5 +1,7 @@ #include "clash_utils.h" #include +#include +#include #define GU_CULLING_EPSILON_RAY_TRIANGLE FLT_EPSILON*FLT_EPSILON #define PX_MAX_F32 3.4028234663852885981170418348452e+38F diff --git a/src/ifcgeom/kernels/opencascade/faceset_helper.cpp b/src/ifcgeom/kernels/opencascade/faceset_helper.cpp index 2fd74cdf2d..54d4bfb8d7 100644 --- a/src/ifcgeom/kernels/opencascade/faceset_helper.cpp +++ b/src/ifcgeom/kernels/opencascade/faceset_helper.cpp @@ -154,7 +154,13 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper( typedef std::array edge_t; typedef std::set edge_set_t; - std::set edge_sets; + // When a single face fills an interior loop, their edge_sets (canonicalized edges) will be identical. + // We can differentiate in this scenario in two ways: + // - std::map retain the edge order from the bool passed to the loop_() lambda + // - std::pair with pair::first populated from external (FaceBound / OuterBound) + // The second has been found more reliable for typical models, because inner bound winding can be wrong. + // The can be made more resilient by first checking correct population of external and falling back to approach 1. + std::set> edge_sets; for (auto& loop : loops) { std::vector > segments; @@ -165,12 +171,12 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper( segments.push_back(std::make_pair(C, D)); }); - if (edge_sets.find(segment_set) != edge_sets.end()) { + if (edge_sets.find({loop->external.get_value_or(false), segment_set}) != edge_sets.end()) { duplicate_faces++; duplicates_.insert(loop->identity()); continue; } - edge_sets.insert(segment_set); + edge_sets.insert({loop->external.get_value_or(false), segment_set}); if (segments.size() >= 3) { for (auto& p : segments) { diff --git a/src/ifcgeom/mapping/mapping.h b/src/ifcgeom/mapping/mapping.h index 054e0a7efc..a9fe31999b 100644 --- a/src/ifcgeom/mapping/mapping.h +++ b/src/ifcgeom/mapping/mapping.h @@ -7,6 +7,7 @@ #include "../../ifcparse/IfcLogger.h" #include +#include #define INCLUDE_SCHEMA(x) STRINGIFY(../../ifcparse/x.h) #include INCLUDE_SCHEMA(IfcSchema) diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index c1162eebb0..a1d0c89ad4 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -17,6 +17,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #ifndef TAXONOMY_USE_UNIQUE_PTR #ifndef TAXONOMY_USE_NAKED_PTR @@ -1625,19 +1632,19 @@ typedef item const* ptr; // @todo Sad... now that we have templated collection members, // we can't generally use collection_base anymore as a cast target. if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else if (auto s = std::dynamic_pointer_cast(i)) { - visit(s, fn); + ifcopenshell::geometry::visit(s, fn); } else { fn(i); diff --git a/src/ifcparse/IfcBaseClass.h b/src/ifcparse/IfcBaseClass.h index 5cab8289c3..d03e7b284e 100644 --- a/src/ifcparse/IfcBaseClass.h +++ b/src/ifcparse/IfcBaseClass.h @@ -27,6 +27,7 @@ #include "utils.h" #include +#include #include class aggregate_of_instance; diff --git a/src/ifcparse/IfcCharacterDecoder.cpp b/src/ifcparse/IfcCharacterDecoder.cpp index 71685dcedc..c036aa676d 100644 --- a/src/ifcparse/IfcCharacterDecoder.cpp +++ b/src/ifcparse/IfcCharacterDecoder.cpp @@ -201,7 +201,7 @@ namespace { if (character >= 0x20 && character <= 0x7e) { stream.put((char)character); } else { - stream << "\\u" << character; + stream << "\\u" << static_cast(character); } }); return stream.str(); diff --git a/src/ifcparse/IfcEntityInstanceData.h b/src/ifcparse/IfcEntityInstanceData.h index 04e7dcb0ad..f51345a25e 100644 --- a/src/ifcparse/IfcEntityInstanceData.h +++ b/src/ifcparse/IfcEntityInstanceData.h @@ -36,6 +36,9 @@ #endif +#include +#include + #include #include #include diff --git a/src/ifcparse/IfcFile.cpp b/src/ifcparse/IfcFile.cpp index 9e26b24442..a1cd77e437 100644 --- a/src/ifcparse/IfcFile.cpp +++ b/src/ifcparse/IfcFile.cpp @@ -4,9 +4,12 @@ #ifdef IFOPSH_WITH_ROCKSDB #include #include +#include #endif #include +#include +#include #include #include @@ -410,10 +413,8 @@ IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(s } namespace { - rocksdb::DB* init_db(const std::string& filepath, bool readonly) { - rocksdb::DB* db = nullptr; + std::unique_ptr init_db(const std::string& filepath, bool readonly) { #ifdef IFOPSH_WITH_ROCKSDB - rocksdb::Options options; // options.disable_auto_compactions = true; options.create_if_missing = true; @@ -445,16 +446,31 @@ namespace { options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(tbo)); rocksdb::Status status; + std::unique_ptr db; if (readonly) { +#if ROCKSDB_MAJOR > 9 || (ROCKSDB_MAJOR == 9 && ROCKSDB_MINOR >= 11) status = rocksdb::DB::OpenForReadOnly(options, filepath, &db); +#else + rocksdb::DB* raw = nullptr; + status = rocksdb::DB::OpenForReadOnly(options, filepath, &raw); + db.reset(raw); +#endif } else { +#if ROCKSDB_MAJOR > 9 || (ROCKSDB_MAJOR == 9 && ROCKSDB_MINOR >= 11) status = rocksdb::DB::Open(options, filepath, &db); +#else + rocksdb::DB* raw = nullptr; + status = rocksdb::DB::Open(options, filepath, &raw); + db.reset(raw); +#endif } if (!status.ok()) { return nullptr; } -#endif // IFOPSH_WITH_ROCKSDB# return db; +#else + return nullptr; +#endif } } @@ -463,12 +479,12 @@ IfcParse::impl::rocks_db_file_storage::rocks_db_file_storage(const std::string& : file(ffile) , db(init_db(filepath, readonly)) // @todo streaming serializer does not populate the byguid map - , byguid_internal_(db, "g|") + , byguid_internal_(db.get(), "g|") , byguid_(&byguid_internal_, [this](size_t v) { return assert_existance(v, entityinstance_ref); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); }) - , instance_ids_(db, "i|") + , instance_ids_(db.get(), "i|") , instance_by_name_(&instance_ids_, [this](size_t v) { return assert_existance(v, entityinstance_ref); }) - , bytype_(db, "t|") - , byref_excl_(db, "v|") + , bytype_(db.get(), "t|") + , byref_excl_(db.get(), "v|") // @todo by_identity is probably not correct here, this mapping is Name -> Identity, so Fn should have access to full pair? // , byidentity_(&byid_, [this](size_t v) { return assert_existance(v, by_identity); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); }) { @@ -491,7 +507,6 @@ IfcParse::impl::rocks_db_file_storage::~rocks_db_file_storage() assert(s.ok()); db->Close(); - delete db; #endif } diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 96685a88ee..1092bb5e4f 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef IFOPSH_WITH_ROCKSDB #include diff --git a/src/ifcparse/IfcSchema.h b/src/ifcparse/IfcSchema.h index 349a81532d..dce8a43348 100644 --- a/src/ifcparse/IfcSchema.h +++ b/src/ifcparse/IfcSchema.h @@ -25,7 +25,9 @@ #include #include #include +#include #include +#include #include #include diff --git a/src/ifcparse/aggregate_of_instance.h b/src/ifcparse/aggregate_of_instance.h index bcce94ce6e..f7e78552b3 100644 --- a/src/ifcparse/aggregate_of_instance.h +++ b/src/ifcparse/aggregate_of_instance.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace IfcParse { class declaration; diff --git a/src/ifcparse/rocksdb_map_adapter.h b/src/ifcparse/rocksdb_map_adapter.h index da2346789f..25d830463b 100644 --- a/src/ifcparse/rocksdb_map_adapter.h +++ b/src/ifcparse/rocksdb_map_adapter.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include template struct is_std_tuple : std::false_type {}; diff --git a/src/ifcparse/storage.h b/src/ifcparse/storage.h index 60378c982e..39e5139040 100644 --- a/src/ifcparse/storage.h +++ b/src/ifcparse/storage.h @@ -25,10 +25,13 @@ namespace rocksdb { #include #include +#include +#include #include #include #include #include +#include #ifndef SWIG @@ -306,7 +309,7 @@ namespace IfcParse { class IFC_PARSE_API rocks_db_file_storage { public: - rocksdb::DB* db; + std::unique_ptr db; rocksdb::WriteOptions wopts; rocksdb::ReadOptions ropts; IfcParse::IfcFile* file; diff --git a/src/ifcparse/variantarray.h b/src/ifcparse/variantarray.h index 16e2659564..1b00774bf7 100644 --- a/src/ifcparse/variantarray.h +++ b/src/ifcparse/variantarray.h @@ -33,6 +33,10 @@ variant - which is the maximum size of its constituents - is reduced. #include #include #include +#include +#include +#include +#include #include "IfcException.h" diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index 3627106f42..55ebb1d52c 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -23,6 +23,8 @@ #include "../ifcparse/utils.h" +#include + #ifdef WITH_PROJ #include #endif diff --git a/src/serializers/HdfSerializer.cpp b/src/serializers/HdfSerializer.cpp index 2fceb0eec0..092413abae 100644 --- a/src/serializers/HdfSerializer.cpp +++ b/src/serializers/HdfSerializer.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef USE_BINARY #define write_shape write_binary diff --git a/src/serializers/RocksDbSerializer.cpp b/src/serializers/RocksDbSerializer.cpp index f5e95e7a3b..2a6221b670 100644 --- a/src/serializers/RocksDbSerializer.cpp +++ b/src/serializers/RocksDbSerializer.cpp @@ -4,6 +4,9 @@ #include +#include +#include + #include "../ifcparse/IfcLogger.h" RocksDbSerializer::RocksDbSerializer(IfcParse::IfcFile* file, const std::string& rocksdb_filename)