From 65e874c67f07acdde3d8e08fd7aa33cf141f4d5d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Wed, 15 Nov 2023 10:32:20 +0100 Subject: [PATCH] Drastic settings refactoring --- src/ifcconvert/IfcConvert.cpp | 245 ++------- src/ifcconvert/validate_space_boundaries.cpp | 14 +- .../validate_storey_containment.cpp | 17 +- src/ifcconvert/validate_wall_connectivity.cpp | 18 +- src/ifcconvert/validation_utils.h | 14 +- src/ifcgeom/AbstractKernel.cpp | 6 +- src/ifcgeom/AbstractKernel.h | 10 +- src/ifcgeom/ConversionResult.cpp | 2 +- src/ifcgeom/ConversionResult.h | 7 +- src/ifcgeom/ConversionSettings.cpp | 30 ++ src/ifcgeom/ConversionSettings.h | 498 +++++++++++++++--- src/ifcgeom/Converter.cpp | 24 +- src/ifcgeom/Converter.h | 16 +- src/ifcgeom/GeometrySerializer.h | 119 +++-- src/ifcgeom/IfcGeomElement.h | 8 +- src/ifcgeom/IfcGeomFilter.h | 4 +- src/ifcgeom/IfcGeomIteratorSettings.cpp | 3 + src/ifcgeom/IfcGeomRepresentation.cpp | 25 +- src/ifcgeom/IfcGeomRepresentation.h | 30 +- src/ifcgeom/Iterator.h | 69 ++- src/ifcgeom/IteratorSettings.h | 4 + src/ifcgeom/abstract_mapping.cpp | 2 +- src/ifcgeom/abstract_mapping.h | 12 +- .../kernels/cgal/CgalConversionResult.cpp | 4 +- .../kernels/cgal/CgalConversionResult.h | 4 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 2 +- src/ifcgeom/kernels/cgal/CgalKernel.h | 4 +- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 16 +- .../OpenCascadeConversionResult.cpp | 14 +- .../opencascade/OpenCascadeConversionResult.h | 2 +- .../kernels/opencascade/OpenCascadeKernel.cpp | 12 +- .../kernels/opencascade/OpenCascadeKernel.h | 45 +- .../kernels/opencascade/boolean_result.cpp | 12 +- src/ifcgeom/kernels/opencascade/extrusion.cpp | 2 +- .../kernels/opencascade/faceset_helper.cpp | 28 +- src/ifcgeom/kernels/opencascade/shell.cpp | 2 +- src/ifcgeom/mapping/IfcCShapeProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcCircle.cpp | 2 +- src/ifcgeom/mapping/IfcCompositeCurve.cpp | 2 +- src/ifcgeom/mapping/IfcCurveSegment.cpp | 2 +- src/ifcgeom/mapping/IfcEllipse.cpp | 2 +- src/ifcgeom/mapping/IfcEllipseProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcExtrudedAreaSolid.cpp | 2 +- .../mapping/IfcExtrudedAreaSolidTapered.cpp | 2 +- src/ifcgeom/mapping/IfcIShapeProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcLShapeProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcPolyLoop.cpp | 2 +- src/ifcgeom/mapping/IfcPolyline.cpp | 2 +- .../mapping/IfcRectangleHollowProfileDef.cpp | 2 +- .../mapping/IfcRectangleProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcRepresentation.cpp | 3 +- .../mapping/IfcRoundedRectangleProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcSweptDiskSolid.cpp | 2 +- src/ifcgeom/mapping/IfcTShapeProfileDef.cpp | 2 +- .../mapping/IfcTrapeziumProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcTrimmedCurve.cpp | 4 +- src/ifcgeom/mapping/IfcUShapeProfileDef.cpp | 2 +- src/ifcgeom/mapping/IfcZShapeProfileDef.cpp | 2 +- src/ifcgeom/mapping/mapping.cpp | 95 +--- src/ifcgeom/mapping/mapping.h | 5 +- src/ifcgeomserver/IfcGeomServer.cpp | 15 +- .../ifcopenshell/geom/main.py | 65 ++- src/ifcwrap/IfcGeomWrapper.i | 108 ++-- src/ifcwrap/IfcPython.i | 5 + src/ifcwrap/utils/type_conversion.i | 16 + src/ifcwrap/utils/typemaps_out.i | 5 + src/serializers/ColladaSerializer.cpp | 6 +- src/serializers/ColladaSerializer.h | 6 +- src/serializers/GltfSerializer.cpp | 4 +- src/serializers/GltfSerializer.h | 2 +- src/serializers/HdfSerializer.cpp | 28 +- src/serializers/HdfSerializer.h | 4 +- src/serializers/IgesSerializer.h | 4 +- src/serializers/OpenCascadeBasedSerializer.h | 4 +- src/serializers/StepSerializer.h | 4 +- src/serializers/SvgSerializer.cpp | 15 +- src/serializers/SvgSerializer.h | 4 +- src/serializers/WavefrontObjSerializer.cpp | 10 +- src/serializers/WavefrontObjSerializer.h | 2 +- .../schema_dependent/XmlSerializer.h | 2 +- 80 files changed, 1057 insertions(+), 723 deletions(-) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 7525395d72..98c59d77b6 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -217,7 +217,6 @@ int main(int argc, char** argv) { typedef char char_t; #endif - double deflection_tolerance, angular_tolerance, force_space_transparency; inclusion_filter include_filter; inclusion_traverse_filter include_traverse_filter; exclusion_filter exclude_filter; @@ -276,6 +275,8 @@ int main(int argc, char** argv) { // none, convex-decomposition, minkowski-triangles or halfspace-snapping std::string exterior_only_algo; + + ifcopenshell::geometry::Settings geometry_settings; po::options_description geom_options("Geometry options"); geom_options.add_options() @@ -283,32 +284,6 @@ int main(int argc, char** argv) { "Geometry kernel to use (opencascade, cgal, cgal-simple).") ("threads,j", po::value(&num_threads)->default_value(1), "Number of parallel processing threads for geometry interpretation.") - ("plan", - "Specifies whether to include curves in the output result. Typically " - "these are representations of type Plan or Axis. Excluded by default.") - ("model", - "Specifies whether to include surfaces and solids in the output result. " - "Typically these are representations of type Body or Facetation. " - "Included by default.") - ("weld-vertices", - "Specifies whether vertices are welded, meaning that the coordinates " - "vector will only contain unique xyz-triplets. This results in a " - "manifold mesh which is useful for modelling applications, but might " - "result in unwanted shading artefacts in rendering applications.") - ("use-world-coords", - "Specifies whether to apply the local placements of building elements " - "directly to the coordinates of the representation mesh rather than " - "to represent the local placement in the 4x3 matrix, which will in that " - "case be the identity matrix.") - ("convert-back-units", - "Specifies whether to convert back geometrical output back to the " - "unit of measure in which it is defined in the IFC file. Default is " - "to use meters.") - ("orient-shells", - "Specifies whether to orient the faces of IfcConnectedFaceSets. " - "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.") ("center-model", "Centers the elements by applying the center point of all placements as an offset." "Can take several minutes on large models.") @@ -318,30 +293,6 @@ int main(int argc, char** argv) { "Applies an arbitrary offset of form 'x;y;z' to all placements.") ("model-rotation", po::value(&rotation_str), "Applies an arbitrary quaternion rotation of form 'x;y;z;w' to all placements.") -#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.") - ("disable-boolean-results", - "Specifies whether to disable the boolean operation within representations " - "such as clippings by means of IfcBooleanResult and subtypes") - ("no-2d-boolean", - "Do not attempt to process boolean subtractions in 2D.") - ("enable-layerset-slicing", - "Specifies whether to enable the slicing of products according " - "to their associated IfcMaterialLayerSet.") - ("layerset-first", "Assigns the first layer material of the layerset " - "to the complete product.") ("include", po::value(&include_filter)->multitoken(), "Specifies that the instances that match a specific filtering criteria are to be included in the geometrical output:\n" "1) 'entities': the following list of types should be included. SVG output defaults " @@ -368,32 +319,15 @@ int main(int argc, char** argv) { "are '--include=arg GlobalId ...' and 'include arg GlobalId ...'. Spaces and tabs can be used as delimiters." "Multiple filters of same type with different values can be inserted on their own lines. " "See --include, --include+, --exclude, and --exclude+ for more details.") - ("no-normals", - "Disables computation of normals. Saves time and file size and is useful " - "in instances where you're going to recompute normals for the exported " - "model in other modelling application in any case.") - ("deflection-tolerance", po::value(&deflection_tolerance)->default_value(1e-3), - "Sets the deflection tolerance of the mesher, 1e-3 by default if not specified.") - ("force-space-transparency", po::value(&force_space_transparency), - "Overrides transparency of spaces in geometry output.") - ("angular-tolerance", po::value(&angular_tolerance)->default_value(0.5), - "Sets the angular tolerance of the mesher in radians 0.5 by default if not specified.") - ("generate-uvs", - "Generates UVs (texture coordinates) by using simple box projection. Requires normals. " - "Not guaranteed to work properly if used with --weld-vertices.") ("default-material-file", new po::typed_value(&default_material_filename), "Specifies a material file that describes the material object types will have" "if an object does not have any specified material in the IFC file.") - ("validate", "Checks whether geometrical output conforms to the included explicit quantities.") - ("no-wire-intersection-check", "Skip wire intersection check.") - ("no-wire-intersection-tolerance", "Set wire intersection tolerance to 0.") ("exterior-only", po::value(&exterior_only_algo)->default_value("none")->implicit_value("minkowski-triangles"), "Export only the exterior shell of the building found by geometric analysis. convex-decomposition, minkowski-triangles or halfspace-snapping") - ("strict-tolerance", "Use exact tolerance from model. Default is a 10 " - "times increase for more permissive edge curves and fewer artifacts after " - "boolean operations at the expense of geometric detail " - "due to vertex collapsing and wire intersection fuzziness."); + ; + + geometry_settings.define_options(geom_options); std::string bounds; #ifdef HAVE_ICU @@ -409,6 +343,8 @@ int main(int argc, char** argv) { SvgSerializer::storey_height_display_types svg_storey_height_display = SvgSerializer::SH_NONE; #endif + ifcopenshell::geometry::SerializerSettings serializer_settings; + po::options_description serializer_options("Serialization options"); serializer_options.add_options() #ifdef HAVE_ICU @@ -454,41 +390,14 @@ int main(int argc, char** argv) { ("section-height", po::value(§ion_height), "Specifies the cut section height for SVG 2D geometry.") ("section-height-from-storeys", "Derives section height from storey elevation. Use --section-height to override default offset of 1.2") - ("use-element-names", - "Use entity instance IfcRoot.Name instead of unique IDs for naming elements upon serialization. " - "Applicable for OBJ, DAE, STP, and SVG output.") - ("use-element-guids", - "Use entity instance IfcRoot.GlobalId instead of unique IDs for naming elements upon serialization. " - "Applicable for OBJ, DAE, STP, and SVG output.") - ("use-element-numeric-ids", "Use the numeric step identifier (entity instance name) for naming elements upon serialization. " - "Applicable for OBJ, DAE, STP, and SVG output.") - ("use-material-names", - "Use material names instead of unique IDs for naming materials upon serialization. " - "Applicable for OBJ and DAE output.") - ("use-element-types", - "Use element types instead of unique IDs for naming elements upon serialization. " - "Applicable for DAE output.") - ("use-element-hierarchy", - "Order the elements using their IfcBuildingStorey parent. " - "Applicable for DAE output.") - ("site-local-placement", - "Place elements locally in the IfcSite coordinate system, instead of placing " - "them in the IFC global coords. Applicable for OBJ, DAE, and STP output.") - ("y-up", "Change the 'up' axis to positive Y, default is Z UP, Applicable for OBJ output.") - ("building-local-placement", - "Similar to --site-local-placement, but placing elements in locally in the parent IfcBuilding coord system") - ("precision", po::value(&precision)->default_value(SerializerSettings::DEFAULT_PRECISION), - "Sets the precision to be used to format floating-point values, 15 by default. " - "Use a negative value to use the system's default precision (should be 6 typically). " - "Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used, " - " and any other value means that 6 or 7 decimals are used.") ("print-space-names", "Prints IfcSpace LongName and Name in the geometry output. Applicable for SVG output") ("print-space-areas", "Prints calculated IfcSpace areas in square meters. Applicable for SVG output") ("space-name-transform", po::value(), "Additional transform to the space labels in SVG") - ("edge-arrows", "Adds arrow heads to edge segments to signify edge direction") ; + serializer_settings.define_options(serializer_options); + po::options_description cmdline_options; cmdline_options.add(generic_options).add(fileio_options).add(geom_options).add(ifc_options).add(serializer_options); @@ -523,39 +432,11 @@ int main(int argc, char** argv) { const bool no_progress = vmap.count("no-progress") != 0; const bool quiet = vmap.count("quiet") != 0; const bool stderr_progress = vmap.count("stderr-progress") != 0; - const bool weld_vertices = vmap.count("weld-vertices") != 0; - const bool use_world_coords = vmap.count("use-world-coords") != 0; - const bool convert_back_units = vmap.count("convert-back-units") != 0; - const bool orient_shells = vmap.count("orient-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; - const bool disable_boolean_results = vmap.count("disable-boolean-results") != 0; - const bool include_plan = vmap.count("plan") != 0; - const bool include_model = vmap.count("model") != 0 || (!include_plan); - const bool enable_layerset_slicing = vmap.count("enable-layerset-slicing") != 0; - const bool layerset_first = vmap.count("layerset-first") != 0; - const bool use_element_names = vmap.count("use-element-names") != 0; - const bool use_element_guids = vmap.count("use-element-guids") != 0; - const bool use_element_stepids = vmap.count("use-element-numeric-ids") != 0; - const bool use_material_names = vmap.count("use-material-names") != 0; - const bool use_element_types = vmap.count("use-element-types") != 0; - const bool use_element_hierarchy = vmap.count("use-element-hierarchy") != 0; - const bool use_y_up = vmap.count("y-up") != 0; - const bool no_normals = vmap.count("no-normals") != 0; + const bool center_model = vmap.count("center-model") != 0; const bool center_model_geometry = vmap.count("center-model-geometry") != 0; const bool model_offset = vmap.count("model-offset") != 0; const bool model_rotation = vmap.count("model-rotation") != 0; - const bool site_local_placement = vmap.count("site-local-placement") != 0; - const bool building_local_placement = vmap.count("building-local-placement") != 0; - const bool generate_uvs = vmap.count("generate-uvs") != 0; - const bool validate = vmap.count("validate") != 0; - const bool edge_arrows = vmap.count("edge-arrows") != 0; - const bool no_wire_intersection_check = vmap.count("no-wire-intersection-check") != 0; - const bool no_wire_intersection_tolerance = vmap.count("no-wire-intersection-tolerance") != 0; - const bool strict_tolerance = vmap.count("strict-tolerance") != 0; if (!quiet || vmap.count("version")) { print_version(); @@ -849,12 +730,12 @@ int main(int argc, char** argv) { settings.threads = num_threads; } - settings.settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings.settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, !settings.apply_openings); + settings.settings.get().value = false; + settings.settings.get().value = false; + settings.settings.get().value = true; + settings.settings.get().value = true; + settings.settings.get().value = ifcopenshell::geometry::settings::NATIVE; + settings.settings.get().value = !settings.apply_openings; if (include_filter.type != geom_filter::UNUSED) { settings.entity_names = include_filter.values; @@ -916,77 +797,43 @@ int main(int argc, char** argv) { } } - SerializerSettings settings; - /// @todo Make APPLY_DEFAULT_MATERIALS configurable? Quickly tested setting this to false and using obj exporter caused the program to crash and burn. - settings.set(IfcGeom::IteratorSettings::APPLY_DEFAULT_MATERIALS, true); - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, use_world_coords || output_extension == OBJ || output_extension == STP || output_extension == IGS); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, weld_vertices); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, orient_shells || output_extension == SVG); // svg depends on correct solids for boolean subtractions for hlr - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, convert_back_units); - settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, disable_opening_subtractions); - settings.set(IfcGeom::IteratorSettings::DISABLE_BOOLEAN_RESULT, disable_boolean_results); - settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, include_plan); - 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); - settings.set(IfcGeom::IteratorSettings::ELEMENT_HIERARCHY, use_element_hierarchy || output_extension == SVG); - settings.set(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT, site_local_placement); - settings.set(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT, building_local_placement); - settings.set(IfcGeom::IteratorSettings::VALIDATE_QUANTITIES, validate); - settings.set(IfcGeom::IteratorSettings::NO_WIRE_INTERSECTION_CHECK, no_wire_intersection_check); - settings.set(IfcGeom::IteratorSettings::NO_WIRE_INTERSECTION_TOLERANCE, no_wire_intersection_tolerance); - settings.set(IfcGeom::IteratorSettings::STRICT_TOLERANCE, strict_tolerance); - settings.set(IfcGeom::IteratorSettings::BOOLEAN_ATTEMPT_2D, !vmap.count("no-2d-boolean")); + if (!geometry_settings.get().has()) { + geometry_settings.get().value = false; + } - settings.set(SerializerSettings::USE_ELEMENT_NAMES, use_element_names); - settings.set(SerializerSettings::USE_ELEMENT_GUIDS, use_element_guids); - settings.set(SerializerSettings::USE_Y_UP, use_y_up); - settings.set(SerializerSettings::USE_ELEMENT_STEPIDS, use_element_stepids); - settings.set(SerializerSettings::USE_MATERIAL_NAMES, use_material_names); - settings.set(SerializerSettings::USE_ELEMENT_TYPES, use_element_types); - settings.set(SerializerSettings::USE_ELEMENT_HIERARCHY, use_element_hierarchy); - settings.set_deflection_tolerance(deflection_tolerance); - settings.set_angular_tolerance(angular_tolerance); - settings.precision = precision; - - if (vmap.count("force-space-transparency")) { - settings.force_space_transparency(force_space_transparency); - IfcGeom::update_default_style("IfcSpace").transparency = force_space_transparency; + if (geometry_settings.get().has()) { + IfcGeom::update_default_style("IfcSpace").transparency = geometry_settings.get().get(); } boost::shared_ptr serializer; /**< @todo use std::unique_ptr when possible */ if (output_extension == OBJ) { // Do not use temp file for MTL as it's such a small file. const path_t mtl_filename = change_extension(output_filename, MTL); - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), settings); + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), IfcUtil::path::to_utf8(mtl_filename), geometry_settings, serializer_settings); #ifdef WITH_OPENCOLLADA } else if (output_extension == DAE) { - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), geometry_settings, serializer_settings); #endif #ifdef WITH_GLTF } else if (output_extension == GLB) { - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), geometry_settings, serializer_settings); #endif #ifdef IFOPSH_WITH_OPENCASCADE } else if (output_extension == STP) { - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), geometry_settings, serializer_settings); } else if (output_extension == IGS) { #if OCC_VERSION_HEX < 0x60900 // According to https://tracker.dev.opencascade.org/view.php?id=25689 something has been fixed in 6.9.0 IGESControl_Controller::Init(); // work around Open Cascade bug #endif - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), geometry_settings, serializer_settings); } else if (output_extension == SVG) { - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); + geometry_settings.get().value = ifcopenshell::geometry::settings::NATIVE; + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), geometry_settings, serializer_settings); #ifdef WITH_HDF5 } else if (output_extension == HDF) { - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), settings); + geometry_settings.get().value = ifcopenshell::geometry::settings::NATIVE; + serializer = boost::make_shared(IfcUtil::path::to_utf8(output_temp_filename), geometry_settings, serializer_settings); #endif #endif } else { @@ -996,7 +843,7 @@ int main(int argc, char** argv) { return EXIT_FAILURE; } - if (use_element_hierarchy && output_extension != DAE) { + if (geometry_settings.get().get() && output_extension != DAE) { cerr_ << "[Error] --use-element-hierarchy can be used only with .dae output.\n"; /// @todo Lots of duplicate error-and-exit code. write_log(!quiet); @@ -1007,17 +854,17 @@ int main(int argc, char** argv) { const bool is_tesselated = serializer->isTesselated(); // isTesselated() doesn't change at run-time if (!is_tesselated) { - if (weld_vertices) { + if (geometry_settings.get().get()) { Logger::Notice("Weld vertices setting ignored when writing non-tesselated output"); } - if (generate_uvs) { + if (geometry_settings.get().get()) { Logger::Notice("Generate UVs setting ignored when writing non-tesselated output"); } if (center_model || center_model_geometry || model_offset) { Logger::Notice("Centering/offsetting model setting ignored when writing non-tesselated output"); } - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); + geometry_settings.get().value = ifcopenshell::geometry::settings::NATIVE; } if (!serializer->ready()) { @@ -1042,6 +889,8 @@ int main(int argc, char** argv) { Logger::SetOutput(quiet ? nullptr : &cout_, vcounter.count > 1 ? &cout_ : &log_stream); } + /* + // @todo if (model_rotation) { std::array &rotation = settings.rotation; if (sscanf(rotation_str.c_str(), "%lf;%lf;%lf;%lf", &rotation[0], &rotation[1], &rotation[2], &rotation[3]) != 4) { @@ -1104,10 +953,10 @@ int main(int argc, char** argv) { msg << std::setprecision (std::numeric_limits< double >::max_digits10) << "Using model offset (" << offset[0] << "," << offset[1] << "," << offset[2] << ")"; Logger::Notice(msg.str()); } - + */ std::unique_ptr context_iterator; if (!elems_from_adaptor) { - context_iterator.reset(new IfcGeom::Iterator(geometry_kernel, settings, ifc_file, filter_funcs, num_threads)); + context_iterator.reset(new IfcGeom::Iterator(geometry_kernel, geometry_settings, ifc_file, filter_funcs, num_threads)); } #if defined(WITH_HDF5) && defined(IFOPSH_WITH_OPENCASCADE) @@ -1116,7 +965,7 @@ int main(int argc, char** argv) { if (!vmap.count("cache-file")) { cache_file = input_filename + CACHE + HDF; } - cache.reset(new HdfSerializer(IfcUtil::path::to_utf8(cache_file), settings)); + cache.reset(new HdfSerializer(IfcUtil::path::to_utf8(cache_file), geometry_settings, serializer_settings)); context_iterator->set_cache(cache.get()); } #endif @@ -1209,7 +1058,7 @@ int main(int argc, char** argv) { } #endif - if (context_iterator && convert_back_units) { + if (context_iterator && geometry_settings.get().get()) { serializer->setUnitNameAndMagnitude(context_iterator->unit_name(), static_cast(context_iterator->unit_magnitude())); } else { serializer->setUnitNameAndMagnitude("METER", 1.0f); @@ -1315,7 +1164,7 @@ int main(int argc, char** argv) { output_temp_filename << "' for the conversion result."; } - if (validate && Logger::MaxSeverity() >= Logger::LOG_ERROR) { + if (geometry_settings.get().get() && Logger::MaxSeverity() >= Logger::LOG_ERROR) { Logger::Error("Errors encountered during processing."); successful = false; } @@ -1666,12 +1515,12 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std } } - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); + ifcopenshell::geometry::Settings settings; + settings.get().value = false; + settings.get().value = false; + settings.get().value = true; + settings.get().value = true; + settings.get().value = ifcopenshell::geometry::settings::NATIVE; IfcGeom::Iterator context_iterator(settings, &f, {}, 1); diff --git a/src/ifcconvert/validate_space_boundaries.cpp b/src/ifcconvert/validate_space_boundaries.cpp index c15c7c763d..abe5d976fc 100644 --- a/src/ifcconvert/validate_space_boundaries.cpp +++ b/src/ifcconvert/validate_space_boundaries.cpp @@ -45,14 +45,14 @@ void fix_spaceboundaries(IfcParse::IfcFile& f, bool no_progress, bool quiet, boo return; } - IfcGeom::IteratorSettings settings; + ifcopenshell::geometry::Settings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true); + settings.get().value = false; + settings.get().value = false; + settings.get().value = true; + settings.get().value = true; + settings.get().value = ifcopenshell::geometry::settings::NATIVE; + settings.get().value = true; ifcopenshell::geometry::Converter c("cgal", &f2, settings); diff --git a/src/ifcconvert/validate_storey_containment.cpp b/src/ifcconvert/validate_storey_containment.cpp index 9bd60d701a..2766a206c3 100644 --- a/src/ifcconvert/validate_storey_containment.cpp +++ b/src/ifcconvert/validate_storey_containment.cpp @@ -10,13 +10,14 @@ #include void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true); + ifcopenshell::geometry::Settings settings; + + settings.get().value = false; + settings.get().value = false; + settings.get().value = true; + settings.get().value = true; + settings.get().value = ifcopenshell::geometry::settings::NATIVE; + settings.get().value = true; std::vector no_openings_and_spaces = { IfcGeom::entity_filter(false, false, {"IfcOpeningElement", "IfcSpace"}) @@ -133,7 +134,7 @@ void fix_storeycontainment(IfcParse::IfcFile& f, bool no_progress, bool quiet, b std::vector intersection_volumes(nefs.size()); for (auto& g : geom_object->geometry()) { - auto s = ((ifcopenshell::geometry::CgalShape*) g.Shape())->shape(); + auto s = std::static_pointer_cast(g.Shape())->poly(); const auto& m = g.Placement()->ccomponents(); const auto& n = geom_object->transformation().data()->ccomponents(); diff --git a/src/ifcconvert/validate_wall_connectivity.cpp b/src/ifcconvert/validate_wall_connectivity.cpp index fdb6e91b1a..7a41fd78e7 100644 --- a/src/ifcconvert/validate_wall_connectivity.cpp +++ b/src/ifcconvert/validate_wall_connectivity.cpp @@ -12,17 +12,17 @@ using namespace ifcopenshell::geometry; void fix_wallconnectivity(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool stderr_progress) { intersection_validator v(f, { "IfcWall" }, 1.e-3, no_progress, quiet, stderr_progress); + ifcopenshell::geometry::Settings settings; - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true); + settings.get().value = false; + settings.get().value = false; + settings.get().value = true; + settings.get().value = true; + settings.get().value = ifcopenshell::geometry::settings::NATIVE; + settings.get().value = true; - settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true); - settings.set(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES, true); + settings.get().value = true; + settings.get().value = false; ifcopenshell::geometry::Converter c("cgal", &f, settings); diff --git a/src/ifcconvert/validation_utils.h b/src/ifcconvert/validation_utils.h index 3c0eb8b222..a47a909755 100644 --- a/src/ifcconvert/validation_utils.h +++ b/src/ifcconvert/validation_utils.h @@ -433,13 +433,13 @@ struct intersection_validator { intersection_validator(IfcParse::IfcFile& f, std::initializer_list entities, double eps, bool no_progress, bool quiet, bool stderr_progress) { - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings.set(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS, true); + ifcopenshell::geometry::Settings settings; + settings.get().value = false; + settings.get().value = false; + settings.get().value = true; + settings.get().value = true; + settings.get().value = ifcopenshell::geometry::settings::NATIVE; + settings.get().value = true; std::vector spaces_and_walls = { IfcGeom::entity_filter(true, false, entities) diff --git a/src/ifcgeom/AbstractKernel.cpp b/src/ifcgeom/AbstractKernel.cpp index 5041381cc4..09f0cda1a9 100644 --- a/src/ifcgeom/AbstractKernel.cpp +++ b/src/ifcgeom/AbstractKernel.cpp @@ -33,12 +33,12 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::pt } } -const ConversionSettings & ifcopenshell::geometry::kernels::AbstractKernel::settings() const +const Settings& ifcopenshell::geometry::kernels::AbstractKernel::settings() const { - return conv_settings_; + return settings_; } -ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, const ConversionSettings& conv_settings) { +ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(const std::string& geometry_library, const Settings& conv_settings) { const std::string geometry_library_lower = boost::to_lower_copy(geometry_library); #ifdef IFOPSH_WITH_OPENCASCADE diff --git a/src/ifcgeom/AbstractKernel.h b/src/ifcgeom/AbstractKernel.h index 80c4936a0c..7f4ed08692 100644 --- a/src/ifcgeom/AbstractKernel.h +++ b/src/ifcgeom/AbstractKernel.h @@ -20,15 +20,15 @@ namespace ifcopenshell { namespace geometry { namespace kernels { class IFC_GEOM_API AbstractKernel { protected: std::string geometry_library; - ConversionSettings conv_settings_; + Settings settings_; public: - AbstractKernel(const std::string& geometry_library, const ConversionSettings& settings) + AbstractKernel(const std::string& geometry_library, const Settings& settings) : geometry_library(geometry_library) - , conv_settings_(settings) {} + , settings_(settings) {} bool convert(const taxonomy::ptr, IfcGeom::ConversionResults&); - const ConversionSettings& settings() const; + const Settings& settings() const; virtual bool convert_impl(const taxonomy::matrix4::ptr, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); } virtual bool convert_impl(const taxonomy::point3::ptr, IfcGeom::ConversionResults&) { throw std::runtime_error("Not implemented"); } @@ -68,7 +68,7 @@ namespace ifcopenshell { namespace geometry { namespace kernels { }; - AbstractKernel* construct(const std::string& geometry_library, const ConversionSettings& conv_settings); + AbstractKernel* construct(const std::string& geometry_library, const Settings& conv_settings); } } diff --git a/src/ifcgeom/ConversionResult.cpp b/src/ifcgeom/ConversionResult.cpp index b8f657e22a..da29dc380e 100644 --- a/src/ifcgeom/ConversionResult.cpp +++ b/src/ifcgeom/ConversionResult.cpp @@ -1,7 +1,7 @@ #include "ConversionResult.h" #include "IfcGeomRepresentation.h" -IfcGeom::Representation::Triangulation * IfcGeom::ConversionResultShape::Triangulate(const IfcGeom::IteratorSettings & settings) const +IfcGeom::Representation::Triangulation * IfcGeom::ConversionResultShape::Triangulate(const ifcopenshell::geometry::Settings& settings) const { auto t = IfcGeom::Representation::Triangulation::empty(settings); static ifcopenshell::geometry::taxonomy::matrix4 iden; diff --git a/src/ifcgeom/ConversionResult.h b/src/ifcgeom/ConversionResult.h index 411f9e0845..692ff87618 100644 --- a/src/ifcgeom/ConversionResult.h +++ b/src/ifcgeom/ConversionResult.h @@ -21,7 +21,7 @@ #define IFCSHAPELIST_H #include "../ifcgeom/IfcGeomRenderStyles.h" -#include "../ifcgeom/IteratorSettings.h" +#include "../ifcgeom/ConversionSettings.h" #include "../ifcgeom/taxonomy.h" #include @@ -183,8 +183,8 @@ namespace IfcGeom { class IFC_GEOM_API ConversionResultShape { public: - virtual void Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const = 0; - IfcGeom::Representation::Triangulation* Triangulate(const IfcGeom::IteratorSettings& settings) const; + virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int surface_style_id) const = 0; + IfcGeom::Representation::Triangulation* Triangulate(const ifcopenshell::geometry::Settings& settings) const; virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const = 0; virtual int surface_genus() const = 0; @@ -223,6 +223,7 @@ namespace IfcGeom { virtual ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const = 0; virtual ~ConversionResultShape() {} + }; class IFC_GEOM_API ConversionResult { diff --git a/src/ifcgeom/ConversionSettings.cpp b/src/ifcgeom/ConversionSettings.cpp index 555b1e5e78..e2fc14175d 100644 --- a/src/ifcgeom/ConversionSettings.cpp +++ b/src/ifcgeom/ConversionSettings.cpp @@ -1,5 +1,6 @@ #include "ConversionSettings.h" +/* void ifcopenshell::geometry::ConversionSettings::setValue(GeomValue var, double value) { values_[var] = value; } @@ -7,3 +8,32 @@ void ifcopenshell::geometry::ConversionSettings::setValue(GeomValue var, double double ifcopenshell::geometry::ConversionSettings::getValue(GeomValue var) const { return values_[var]; } +*/ + +std::istream& std::operator>>(istream& in, set& ints) { + string tokens; + in >> tokens; + vector strs; + boost::split(strs, tokens, boost::is_any_of(",")); + for (auto& s : strs) { + ints.insert(boost::lexical_cast(s)); + } + return in; +} + +std::istream& ifcopenshell::geometry::settings::operator>>(std::istream& in, IteratorOutputOptions& ioo) +{ + std::string token; + in >> token; + boost::to_upper(token); + if (token == "TRIANGULATED") { + ioo = TRIANGULATED; + } else if (token == "NATIVE") { + ioo = NATIVE; + } else if (token == "SERIALIZED") { + ioo = SERIALIZED; + } else { + in.setstate(std::ios_base::failbit); + } + return in; +} diff --git a/src/ifcgeom/ConversionSettings.h b/src/ifcgeom/ConversionSettings.h index 77b77193ce..18195f2f75 100644 --- a/src/ifcgeom/ConversionSettings.h +++ b/src/ifcgeom/ConversionSettings.h @@ -4,77 +4,453 @@ #include #include #include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include #include "ifc_geom_api.h" +#ifndef SWIG +namespace po = boost::program_options; + +namespace std { + istream& operator>>(istream& in, set& ints); +} +#endif + namespace ifcopenshell { namespace geometry { + inline namespace settings { - class IFC_GEOM_API ConversionSettings { +#ifndef SWIG + template + struct HasDefault : std::false_type { }; + + template + struct HasDefault : std::true_type { }; +#endif + + template + struct SettingBase { + typedef T base_type; + + boost::optional value; + + SettingBase() {} + + void defineOption(po::options_description& desc) { + auto apply_default = [](auto x) { + if constexpr (HasDefault()) { + return x->default_value(Derived::defaultvalue); + } else { + return x; + } + }; + if constexpr (std::is_same_v) { + // @todo bool_switch doesn't work with optional unfortunately... + value.emplace(); + desc.add_options()(Derived::name, apply_default(po::bool_switch(&*value)), Derived::description); + } else { + desc.add_options()(Derived::name, apply_default(po::value(&value)), Derived::description); + } + } + + T get() const { + if (value) { + return value.get(); + } + if constexpr (HasDefault()) { + return Derived::defaultvalue; + } + throw std::runtime_error("Setting not set"); + } + + bool has() const { + // @todo this is not reliable, better use vmap[...].defaulted() + return !!value; + } + }; + + // These are the old geometry settings values from the kernel + + struct MesherLinearDeflection : public SettingBase { + static constexpr const char* const name = "mesher-linear-deflection"; + static constexpr const char* const description = "Specifies the linear deflection of the mesher. Controls the detail of curved surfaces in triangulated output formats."; + static constexpr double defaultvalue = 0.001; + }; + + struct MesherAngularDeflection : public SettingBase { + static constexpr const char* const name = "mesher-angular-deflection"; + static constexpr const char* const description = "Sets the angular tolerance of the mesher in radians 0.5 by default if not specified."; + static constexpr double defaultvalue = 0.5; + }; + + struct ReorientShells : public SettingBase { + static constexpr const char* const name = "reorient-shells"; + static constexpr const char* const description = "Specifies whether to orient the faces of IfcConnectedFaceSets. " + "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."; + static constexpr bool defaultvalue = false; + }; + + struct LengthUnit : public SettingBase { + static constexpr const char* const name = "length-unit"; + static constexpr const char* const description = ""; + static constexpr double defaultvalue = 1.0; + }; + + struct PlaneUnit : public SettingBase { + static constexpr const char* const name = "angle-unit"; + static constexpr const char* const description = ""; + static constexpr double defaultvalue = 1.0; + }; + + struct Precision : public SettingBase { + static constexpr const char* const name = "precision"; + static constexpr const char* const description = ""; + static constexpr double defaultvalue = 0.00001; + }; + + struct IncludeCurves : public SettingBase { + static constexpr const char* const name = "plan"; + static constexpr const char* const description = "Specifies whether to include curves in the output result. Typically " + "these are representations of type Plan or Axis. Excluded by default."; + static constexpr bool defaultvalue = false; + }; + + struct IncludeSurfaces : public SettingBase { + static constexpr const char* const name = "model"; + static constexpr const char* const description = "Specifies whether to include surfaces and solids in the output result. " + "Typically these are representations of type Body or Facetation. " + "Included by default."; + static constexpr bool defaultvalue = true; + }; + + struct LayersetFirst : public SettingBase { + static constexpr const char* const name = "layerset-first"; + static constexpr const char* const description = "Assigns the first layer material of the layerset " + "to the complete product."; + static constexpr bool defaultvalue = false; + }; + + struct DisableBooleanResult : public SettingBase { + static constexpr const char* const name = "disable-boolean-result"; + static constexpr const char* const description = "Specifies whether to disable the boolean operation within representations " + "such as clippings by means of IfcBooleanResult and subtypes"; + static constexpr bool defaultvalue = false; + }; + + struct NoWireIntersectionCheck : public SettingBase { + static constexpr const char* const name = "no-wire-intersection-check"; + static constexpr const char* const description = "Skip wire intersection check."; + static constexpr bool defaultvalue = false; + }; + + struct NoWireIntersectionTolerance : public SettingBase { + static constexpr const char* const name = "no-wire-intersection-tolerance"; + static constexpr const char* const description = "Set wire intersection tolerance to 0."; + static constexpr bool defaultvalue = false; + }; + + struct PrecisionFactor : public SettingBase { + static constexpr const char* const name = "precision-factor"; + static constexpr const char* const description = "Option to increase linear tolerance for more permissive edge curves and fewer artifacts after " + "boolean operations at the expense of geometric detail " + "due to vertex collapsing and wire intersection fuzziness."; + static constexpr double defaultvalue = 1.0; + }; + + struct DebugBooleanOperations : public SettingBase { + static constexpr const char* const name = "debug-boolean"; + static constexpr const char* const description = ""; + static constexpr bool defaultvalue = false; + }; + + struct BooleanAttempt2d : public SettingBase { + static constexpr const char* const name = "boolean-attempt-2d"; + static constexpr const char* const description = "Do not attempt to process boolean subtractions in 2D."; + static constexpr bool defaultvalue = true; + }; + + // These are the old IteratorSettings + + struct WeldVertices : public SettingBase { + static constexpr const char* const name = "weld-vertices"; + static constexpr const char* const description = "Specifies whether vertices are welded, meaning that the coordinates " + "vector will only contain unique xyz-triplets. This results in a " + "manifold mesh which is useful for modelling applications, but might " + "result in unwanted shading artefacts in rendering applications."; + static constexpr bool defaultvalue = true; + }; + + struct UseWorldCoords : public SettingBase { + static constexpr const char* const name = "use-world-coords"; + static constexpr const char* const description = "Specifies whether to apply the local placements of building elements " + "directly to the coordinates of the representation mesh rather than " + "to represent the local placement in the 4x3 matrix, which will in that " + "case be the identity matrix."; + static constexpr bool defaultvalue = false; + }; + + struct ConvertBackUnits : public SettingBase { + static constexpr const char* const name = "convert-back-units"; + static constexpr const char* const description = "Specifies whether to convert back geometrical output back to the " + "unit of measure in which it is defined in the IFC file. Default is " + "to use meters."; + static constexpr bool defaultvalue = false; + }; + + struct ContextIds : public SettingBase> { + static constexpr const char* const name = "context-ids"; + static constexpr const char* const description = ""; + }; + + enum IteratorOutputOptions { + TRIANGULATED, + NATIVE, + SERIALIZED + }; + + std::istream& operator>>(std::istream& in, IteratorOutputOptions& ioo); + + struct IteratorOutput : public SettingBase { + static constexpr const char* const name = "iterator-output"; + static constexpr const char* const description = ""; + static constexpr IteratorOutputOptions defaultvalue = TRIANGULATED; + }; + + struct DisableOpeningSubtractions : public SettingBase { + static constexpr const char* const name = "disable-opening-subtractions"; + static constexpr const char* const description = "Specifies whether to disable the boolean subtraction of " + "IfcOpeningElement Representations from their RelatingElements."; + static constexpr bool defaultvalue = false; + }; + + struct ApplyDefaultMaterials : public SettingBase { + static constexpr const char* const name = "apply-default-materials"; + static constexpr const char* const description = ""; + static constexpr bool defaultvalue = true; + }; + + struct DontEmitNormals : public SettingBase { + static constexpr const char* const name = "no-normals"; + static constexpr const char* const description = "Disables computation of normals.Saves time and file size and is useful " + "in instances where you're going to recompute normals for the exported " + "model in other modelling application in any case."; + static constexpr bool defaultvalue = false; + }; + + struct GenerateUvs : public SettingBase { + static constexpr const char* const name = "generate-uvs"; + static constexpr const char* const description = "Generates UVs (texture coordinates) by using simple box projection. Requires normals. " + "Not guaranteed to work properly if used with --weld-vertices."; + static constexpr bool defaultvalue = false; + }; + + struct ApplyLayerSets : public SettingBase { + static constexpr const char* const name = "enable-layerset-slicing"; + static constexpr const char* const description = "Specifies whether to enable the slicing of products according " + "to their associated IfcMaterialLayerSet."; + static constexpr bool defaultvalue = false; + }; + + struct UseElementHierarchy : public SettingBase { + static constexpr const char* const name = "element-hierarchy"; + static constexpr const char* const description = "Assign the elements using their e.g IfcBuildingStorey parent." + "Applicable to DAE output."; + static constexpr bool defaultvalue = false; + }; + + struct ValidateQuantities : public SettingBase { + static constexpr const char* const name = "validate"; + static constexpr const char* const description = "Checks whether geometrical output conforms to the included explicit quantities."; + static constexpr bool defaultvalue = false; + }; + + struct EdgeArrows : public SettingBase { + static constexpr const char* const name = "edge-arrows"; + static constexpr const char* const description = "Adds arrow heads to edge segments to signify edge direction"; + static constexpr bool defaultvalue = false; + }; + + struct SiteLocalPlacement : public SettingBase { + static constexpr const char* const name = "site-local-placement"; + static constexpr const char* const description = "Place elements locally in the IfcSite coordinate system, instead of placing " + "them in the IFC global coords. Applicable for OBJ, DAE, and STP output."; + static constexpr bool defaultvalue = false; + }; + + struct BuildingLocalPlacement : public SettingBase { + static constexpr const char* const name = "building-local-placement"; + static constexpr const char* const description = "Similar to --site-local-placement, but placing elements in locally in the parent IfcBuilding coord system"; + static constexpr bool defaultvalue = false; + }; + + struct ForceSpaceTransparency : public SettingBase { + static constexpr const char* const name = "force-space-transparency"; + static constexpr const char* const description = "Overrides transparency of spaces in geometry output."; + }; + + } + + template + class IFC_GEOM_API SettingsContainer { public: - // Tolerances and settings for various geometrical operations: - enum GeomValue { - // Specifies the deflection of the mesher - // Default: 0.001m / 1mm - GV_DEFLECTION_TOLERANCE, - // Specifies the minimal area of a face to be included in an IfcConnectedFaceset - // Read-only - GV_MINIMAL_FACE_AREA, - // Specifies the threshold distance under which cartesian points are deemed equal - // Read-only - GV_POINT_EQUALITY_TOLERANCE, - // Specifies maximum number of faces for a shell to be reoriented. - // Default: -1 - GV_MAX_FACES_TO_ORIENT, - // The length unit used the creation of TopoDS_Shapes, primarily affects the - // interpretation of IfcCartesianPoints and IfcVector magnitudes - // DefaultL 1.0 - GV_LENGTH_UNIT, - // The plane angle unit used for the creation of TopoDS_Shapes, primarily affects - // the interpretation of IfcParamaterValues of IfcTrimmedCurves - // Default: -1.0 (= not set, fist try degrees, then radians) - GV_PLANEANGLE_UNIT, - // The precision used in boolean operations, setting this value too low results - // in artefacts and potentially modelling failures - // Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available) - GV_PRECISION, - // Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0) - GV_DIMENSIONALITY, - GV_LAYERSET_FIRST, - GV_DISABLE_BOOLEAN_RESULT, - GV_NO_WIRE_INTERSECTION_CHECK, - GV_PRECISION_FACTOR, - GV_NO_WIRE_INTERSECTION_TOLERANCE, - GV_DEBUG_BOOLEAN, - GV_BOOLEAN_ATTEMPT_2D, - NUM_SETTINGS - }; - - void setValue(GeomValue var, double value); - - double getValue(GeomValue var) const; - + typedef boost::variant, IteratorOutputOptions> value_variant_t; private: - std::array values_ = { - /* deflection_tolerance = */ 0.001, - // @todo make sure these 'read-only' variables work. - /* minimal_face_area = */ std::numeric_limits::quiet_NaN(), - /* max_faces_to_orient = */ -1.0, - /* ifc_length_unit = */ 1.0, - /* ifc_planeangle_unit = */ -1.0, - /* modelling_precision = */ 0.00001, - /* dimensionality = */ 1., - /* layerset_first = */ -1., - /* disable_boolean_result = */ -1. - /* no_wire_intersection_check = */ -1., - /* precision_factor = */ 10., - /* no_wire_intersection_tolerance = */ -1., - /* boolean_debug_setting = */ -1., - /* boolean_attempt_2d = */ 1. - }; + settings_t settings; + + template + void define_options_(po::options_description& desc) { + std::get(settings).defineOption(desc); + if constexpr (Index + 1 < std::tuple_size_v) { + define_options_(desc); + } + } + + template + value_variant_t get_option_(const std::string& name) const { + if (std::tuple_element_t::name == name) { + return std::get(settings).get(); + } + if constexpr (Index + 1 < std::tuple_size_v) { + return get_option_(name); + } else { + throw std::runtime_error("Setting not available"); + } + } + + template + void set_option_(const std::string& name, const value_variant_t& val) { + if (std::tuple_element_t::name == name) { + std::get(settings).value = boost::get::base_type>(val); + } else if constexpr (Index + 1 < std::tuple_size_v) { + set_option_(name, val); + } else { + throw std::runtime_error("Setting not available"); + } + } + + template + void get_setting_names_(std::vector& vec) const { + vec.push_back(std::tuple_element_t::name); + if constexpr (Index + 1 < std::tuple_size_v) { + return get_setting_names_(vec); + } + } + public: + typedef settings_t settings_tuple; + + void define_options(po::options_description& desc) { + define_options_<0>(desc); + } + + template + const T& get() const { + return std::get(settings); + } + + template + T& get() { + return std::get(settings); + } + + template + void set(T& v) { + std::get(settings) = v; + } + + value_variant_t get(const std::string& name) const { + return get_option_<0>(name); + } + + void set(const std::string& name, value_variant_t val) { + set_option_<0>(name, val); + } + + std::vector setting_names() const { + std::vector r; + get_setting_names_<0>(r); + return r; + } }; - } + + class IFC_GEOM_API Settings : public SettingsContainer< + std::tuple + > + {}; } +} + +// namespace ifcopenshell { +// namespace geometry { +// +// class IFC_GEOM_API ConversionSettings { +// public: +// // Tolerances and settings for various geometrical operations: +// enum GeomValue { +// // +// // Default: 0.001m / 1mm +// GV_DEFLECTION_TOLERANCE, +// +// // The length unit used the creation of TopoDS_Shapes, primarily affects the +// // interpretation of IfcCartesianPoints and IfcVector magnitudes +// // DefaultL 1.0 +// GV_LENGTH_UNIT, +// // The plane angle unit used for the creation of TopoDS_Shapes, primarily affects +// // the interpretation of IfcParamaterValues of IfcTrimmedCurves +// // Default: -1.0 (= not set, fist try degrees, then radians) +// GV_PLANEANGLE_UNIT, +// // The precision used in boolean operations, setting this value too low results +// // in artefacts and potentially modelling failures +// // Default: 0.00001 (obtained from IfcGeometricRepresentationContext if available) +// GV_PRECISION, +// // Whether to process shapes of type Face or higher (1) Wire or lower (-1) or all (0) +// GV_DIMENSIONALITY, +// GV_LAYERSET_FIRST, +// GV_DISABLE_BOOLEAN_RESULT, +// GV_NO_WIRE_INTERSECTION_CHECK, +// GV_PRECISION_FACTOR, +// GV_NO_WIRE_INTERSECTION_TOLERANCE, +// GV_DEBUG_BOOLEAN, +// GV_BOOLEAN_ATTEMPT_2D, +// NUM_SETTINGS +// }; +// +// void setValue(GeomValue var, double value); +// +// double getValue(GeomValue var) const; +// +// private: +// std::array values_ = { +// /* deflection_tolerance = */ 0.001, +// // @todo make sure these 'read-only' variables work. +// /* minimal_face_area = */ std::numeric_limits::quiet_NaN(), +// /* max_faces_to_orient = */ -1.0, +// /* ifc_length_unit = */ 1.0, +// /* ifc_planeangle_unit = */ -1.0, +// /* modelling_precision = */ 0.00001, +// /* dimensionality = */ 1., +// /* layerset_first = */ -1., +// /* disable_boolean_result = */ -1. +// /* no_wire_intersection_check = */ -1., +// /* precision_factor = */ 10., +// /* no_wire_intersection_tolerance = */ -1., +// /* boolean_debug_setting = */ -1., +// /* boolean_attempt_2d = */ 1. +// }; +// }; +// } +// } // @todo find a place namespace IfcGeom { diff --git a/src/ifcgeom/Converter.cpp b/src/ifcgeom/Converter.cpp index ab856d1301..ad73f5f3b4 100644 --- a/src/ifcgeom/Converter.cpp +++ b/src/ifcgeom/Converter.cpp @@ -4,12 +4,12 @@ using namespace ifcopenshell::geometry; -ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file, IfcGeom::IteratorSettings& s) +ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& s) : geometry_library_(boost::to_lower_copy(geometry_library)) , settings_(s) { mapping_ = impl::mapping_implementations().construct(file, settings_); - kernel_ = kernels::construct(geometry_library, mapping_->conversion_settings()); + kernel_ = kernels::construct(geometry_library, mapping_->settings()); } namespace { @@ -44,7 +44,7 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe return 0; } - if (settings_.get(IfcGeom::IteratorSettings::APPLY_LAYERSETS)) { + if (settings_.get().get()) { ifcopenshell::geometry::layerset_information layerinfo; std::vector neighbours; std::map neigbour_layers; @@ -133,11 +133,11 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe representation_id_builder << "-material-" << single_material->data().id(); } - if (settings_.force_space_transparency() >= 0. && product->declaration().is("IfcSpace")) { + if (settings_.get().has() && product->declaration().is("IfcSpace")) { for (auto& s : shapes) { if (s.hasStyle()) { // @todo the uglyness - const_cast(&*s.StylePtr())->transparency = settings_.force_space_transparency(); + const_cast(&*s.StylePtr())->transparency = settings_.get().get(); } } } @@ -156,14 +156,12 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe const std::string guid = product->get_value("GlobalId", ""); const std::string product_type = product->declaration().name(); - IfcGeom::ElementSettings element_settings(settings_, mapping_->get_length_unit(), product_type); - // Does the IfcElement have any IfcOpenings? // Note that openings for IfcOpeningElements are not processed auto openings = mapping_->find_openings(product); - if (!settings_.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && openings && openings->size()) { + if (!settings_.get().get() && openings && openings->size()) { representation_id_builder << "-openings"; for (auto it = openings->begin(); it != openings->end(); ++it) { representation_id_builder << "-" << (*it)->data().id(); @@ -191,23 +189,23 @@ IfcGeom::BRepElement* ifcopenshell::geometry::Converter::create_brep_for_represe opened_shapes = shapes; } - if (settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS)) { + if (settings_.get().get()) { for (auto it = opened_shapes.begin(); it != opened_shapes.end(); ++it) { it->prepend(place); } place = ifcopenshell::geometry::taxonomy::make(); representation_id_builder << "-world-coords"; } - shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), opened_shapes); - } else if (settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS)) { + shape = new IfcGeom::Representation::BRep(settings_, product_type, representation_id_builder.str(), opened_shapes); + } else if (settings_.get().get()) { for (auto it = shapes.begin(); it != shapes.end(); ++it) { it->prepend(place); } place = ifcopenshell::geometry::taxonomy::make(); representation_id_builder << "-world-coords"; - shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes); + shape = new IfcGeom::Representation::BRep(settings_, product_type, representation_id_builder.str(), shapes); } else { - shape = new IfcGeom::Representation::BRep(element_settings, representation_id_builder.str(), shapes); + shape = new IfcGeom::Representation::BRep(settings_, product_type, representation_id_builder.str(), shapes); } std::string context_string = ""; diff --git a/src/ifcgeom/Converter.h b/src/ifcgeom/Converter.h index 554876a7a4..c3d52966d9 100644 --- a/src/ifcgeom/Converter.h +++ b/src/ifcgeom/Converter.h @@ -18,19 +18,19 @@ namespace ifcopenshell { namespace geometry { typedef boost::shared_ptr brep_ptr; private: std::string geometry_library_; - abstract_mapping* mapping_; - kernels::AbstractKernel* kernel_; - IfcGeom::IteratorSettings settings_; + ifcopenshell::geometry::abstract_mapping* mapping_; + ifcopenshell::geometry::kernels::AbstractKernel* kernel_; + ifcopenshell::geometry::Settings settings_; std::map cache_; public: - kernels::AbstractKernel* kernel() { return kernel_; } + ifcopenshell::geometry::kernels::AbstractKernel* kernel() { return kernel_; } - Converter(const std::string& geometry_library, IfcParse::IfcFile* file, IfcGeom::IteratorSettings& settings); + Converter(const std::string& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& settings); ~Converter() {} - abstract_mapping* mapping() const { return mapping_; } + ifcopenshell::geometry::abstract_mapping* mapping() const { return mapping_; } /* virtual NativeElement* convert( @@ -49,8 +49,8 @@ namespace ifcopenshell { namespace geometry { IfcGeom::BRepElement* create_brep_for_representation_and_product(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product); // IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* representation, const IfcUtil::IfcBaseEntity* product, IfcGeom::BRepElement* brep); - IfcGeom::BRepElement* create_brep_for_representation_and_product(taxonomy::ptr, const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4::ptr& place); - IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* product, const taxonomy::matrix4::ptr& place, IfcGeom::BRepElement*); + IfcGeom::BRepElement* create_brep_for_representation_and_product(ifcopenshell::geometry::taxonomy::ptr, const IfcUtil::IfcBaseEntity* product, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place); + IfcGeom::BRepElement* create_brep_for_processed_representation(const IfcUtil::IfcBaseEntity* product, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place, IfcGeom::BRepElement*); }; }} diff --git a/src/ifcgeom/GeometrySerializer.h b/src/ifcgeom/GeometrySerializer.h index acd6b65902..862f042601 100644 --- a/src/ifcgeom/GeometrySerializer.h +++ b/src/ifcgeom/GeometrySerializer.h @@ -23,45 +23,69 @@ #include "../ifcgeom/Serializer.h" #include "../ifcgeom/IfcGeomElement.h" -class SerializerSettings : public IfcGeom::IteratorSettings -{ -public: - enum Setting : uint64_t - { - /// Use entity names instead of unique IDs for naming elements. - /// Applicable for OBJ, DAE, and SVG output. - USE_ELEMENT_NAMES = 1U << (IfcGeom::IteratorSettings::NUM_SETTINGS + 1U), - /// Use entity GUIDs instead of unique IDs for naming elements. - /// Applicable for OBJ, DAE, and SVG output. - USE_ELEMENT_GUIDS = 1U << (IfcGeom::IteratorSettings::NUM_SETTINGS + 2U), - /// Use material names instead of unique IDs for naming materials. - /// Applicable for OBJ and DAE output. - USE_MATERIAL_NAMES = 1U << (IfcGeom::IteratorSettings::NUM_SETTINGS + 3U), - /// Use element types instead of unique IDs for naming elements. - /// Applicable for DAE output. - USE_ELEMENT_TYPES = 1U << (IfcGeom::IteratorSettings::NUM_SETTINGS + 4U), - /// Order the elements using their IfcBuildingStorey parent - /// Applicable for DAE output - USE_ELEMENT_HIERARCHY = 1U << (IfcGeom::IteratorSettings::NUM_SETTINGS + 5U), - /// Use step ids for naming elements. - /// Applicable for OBJ, DAE, and SVG output. - USE_ELEMENT_STEPIDS = 1U << (IfcGeom::IteratorSettings::NUM_SETTINGS + 6U), - /// Use Y UP . - /// Applicable for OBJ output. - USE_Y_UP = 1ULL << (IfcGeom::IteratorSettings::NUM_SETTINGS + 7ULL), - /// Number of different setting flags. - NUM_SETTINGS = 7 - }; +namespace ifcopenshell { +namespace geometry { +inline namespace settings { - SerializerSettings() - : precision(DEFAULT_PRECISION) { } + struct UseElementNames : public SettingBase { + static constexpr const char* const name = "use-element-names"; + static constexpr const char* const description = "Use entity instance IfcRoot.Name instead of unique IDs for naming elements upon serialization. " + "Applicable for OBJ, DAE, STP, and SVG output."; + static constexpr bool defaultvalue = false; + }; - /// Sets the precision used to format floating-point values, 15 by default. - /// Use a negative value to use the system's default precision (should be 6 typically). - short precision; + struct UseElementGuids : public SettingBase { + static constexpr const char* const name = "use-element-guids"; + static constexpr const char* const description = "Use entity instance IfcRoot.GlobalId instead of unique IDs for naming elements upon serialization. " + "Applicable for OBJ, DAE, STP, and SVG output."; + static constexpr bool defaultvalue = false; + }; - enum { DEFAULT_PRECISION = 15 }; -}; + struct UseElementStepIds : public SettingBase { + static constexpr const char* const name = "use-element-step-ids"; + static constexpr const char* const description = "Use the numeric step identifier (entity instance name) for naming elements upon serialization. " + "Applicable for OBJ, DAE, STP, and SVG output."; + static constexpr bool defaultvalue = false; + }; + + struct UseMaterialNames : public SettingBase { + static constexpr const char* const name = "use-material-names"; + static constexpr const char* const description = "Use material names instead of unique IDs for naming materials upon serialization. " + "Applicable for OBJ and DAE output."; + static constexpr bool defaultvalue = false; + }; + + struct UseElementTypes : public SettingBase { + static constexpr const char* const name = "use-element-types"; + static constexpr const char* const description = "Use element types instead of unique IDs for naming elements upon serialization. " + "Applicable to DAE output."; + static constexpr bool defaultvalue = false; + }; + + struct UseYUp : public SettingBase { + static constexpr const char* const name = "y-up"; + static constexpr const char* const description = "Change the 'up' axis to positive Y, default is Z UP. Applicable to OBJ output."; + static constexpr bool defaultvalue = false; + }; + + struct FloatingPointDigits : public SettingBase { + static constexpr const char* const name = "digits"; + static constexpr const char* const description = "Sets the precision to be used to format floating-point values, 15 by default. " + "Use a negative value to use the system's default precision (should be 6 typically). " + "Applicable for OBJ and DAE output. For DAE output, value >= 15 means that up to 16 decimals are used, " + " and any other value means that 6 or 7 decimals are used."; + static constexpr bool defaultvalue = 15; + }; +} + +class SerializerSettings : public SettingsContainer < + // @todo should we use tuple_cat here to unify the settings into a single class? + std::tuple +> +{}; + +} +} class stream_or_filename { private: @@ -103,7 +127,10 @@ class GeometrySerializer : public Serializer { public: enum read_type { READ_BREP, READ_TRIANGULATION }; - GeometrySerializer(const SerializerSettings& settings) : settings_(settings) {} + GeometrySerializer(const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : geometry_settings_(geometry_settings) + , settings_(settings) + {} virtual ~GeometrySerializer() {} virtual bool isTesselated() const = 0; @@ -112,25 +139,29 @@ public: virtual void setUnitNameAndMagnitude(const std::string& name, float magnitude) = 0; virtual IfcGeom::Element* read(IfcParse::IfcFile& f, const std::string& guid, const std::string& representation_id, read_type rt = READ_BREP) = 0; - const SerializerSettings& settings() const { return settings_; } - SerializerSettings& settings() { return settings_; } + const ifcopenshell::geometry::SerializerSettings& settings() const { return settings_; } + ifcopenshell::geometry::SerializerSettings& settings() { return settings_; } + + const ifcopenshell::geometry::Settings& geometry_settings() const { return geometry_settings_; } + ifcopenshell::geometry::Settings& geometry_settings() { return geometry_settings_; } /// Returns ID for the object depending on the used setting. virtual std::string object_id(const IfcGeom::Element* o) { - if (settings_.get(SerializerSettings::USE_ELEMENT_GUIDS)) return o->guid(); - if (settings_.get(SerializerSettings::USE_ELEMENT_NAMES)) return o->name(); - if (settings_.get(SerializerSettings::USE_ELEMENT_STEPIDS)) return "id-" + boost::lexical_cast(o->id()); + if (settings_.get().get()) return o->guid(); + if (settings_.get().get()) return o->name(); + if (settings_.get().get()) return "id-" + boost::lexical_cast(o->id()); return o->unique_id(); } protected: - SerializerSettings settings_; + ifcopenshell::geometry::Settings geometry_settings_; + ifcopenshell::geometry::SerializerSettings settings_; }; class WriteOnlyGeometrySerializer : public GeometrySerializer { public: - WriteOnlyGeometrySerializer(const SerializerSettings& settings) : GeometrySerializer(settings) {} + WriteOnlyGeometrySerializer(const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) : GeometrySerializer(geometry_settings, settings) {} virtual IfcGeom::Element* read(IfcParse::IfcFile&, const std::string&, const std::string&, read_type = READ_BREP) { throw std::runtime_error("Not supported"); diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index 8577754b96..14c321f620 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -35,10 +35,10 @@ namespace IfcGeom { class Transformation { private: - ElementSettings settings_; + ifcopenshell::geometry::Settings settings_; ifcopenshell::geometry::taxonomy::matrix4::ptr matrix_; public: - Transformation(const ElementSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4::ptr& matrix) + Transformation(const ifcopenshell::geometry::Settings& settings, const ifcopenshell::geometry::taxonomy::matrix4::ptr& matrix) : settings_(settings) , matrix_(matrix) {} @@ -93,7 +93,7 @@ namespace IfcGeom { const std::vector parents() const { return _parents; } void SetParents(std::vector newparents) { _parents = newparents; } - Element(const ElementSettings& settings, int id, int parent_id, const std::string& name, const std::string& type, + Element(const ifcopenshell::geometry::Settings& settings, int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4::ptr& trsf, const IfcUtil::IfcBaseEntity* product) : _id(id), _parent_id(parent_id), _name(name), _type(type), _guid(guid), _context(context), _transformation(settings, trsf) , product_(product) @@ -132,7 +132,7 @@ namespace IfcGeom { BRepElement(int id, int parent_id, const std::string& name, const std::string& type, const std::string& guid, const std::string& context, const ifcopenshell::geometry::taxonomy::matrix4::ptr& trsf, const boost::shared_ptr& geometry, const IfcUtil::IfcBaseEntity* product) - : Element(geometry->settings() ,id, parent_id, name, type, guid, context, trsf, product) + : Element(geometry->settings(), id, parent_id, name, type, guid, context, trsf, product) , _geometry(geometry) {} diff --git a/src/ifcgeom/IfcGeomFilter.h b/src/ifcgeom/IfcGeomFilter.h index 9b8a5c853f..c41dbef0d5 100644 --- a/src/ifcgeom/IfcGeomFilter.h +++ b/src/ifcgeom/IfcGeomFilter.h @@ -75,7 +75,7 @@ namespace IfcGeom { // in IfcConvert so invocation is bound to a single file with a single // schema. // @todo pass settings - IfcGeom::IteratorSettings s; + ifcopenshell::geometry::Settings s; static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file, s); while ((parent = mapping->get_decomposing_entity(current, traverse_openings)) != nullptr) { if (pred(parent)) { @@ -183,7 +183,7 @@ namespace IfcGeom { bool match(IfcUtil::IfcBaseEntity* prod) const { // @todo - IfcGeom::IteratorSettings s; + ifcopenshell::geometry::Settings s; static auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(prod->data().file, s); layer_map_t layers = mapping->get_layers(prod); return std::find_if(layers.begin(), layers.end(), wildcards_match(values)) != layers.end(); diff --git a/src/ifcgeom/IfcGeomIteratorSettings.cpp b/src/ifcgeom/IfcGeomIteratorSettings.cpp index e63f56e50c..f239cc4437 100644 --- a/src/ifcgeom/IfcGeomIteratorSettings.cpp +++ b/src/ifcgeom/IfcGeomIteratorSettings.cpp @@ -2,6 +2,7 @@ #include "../ifcparse/IfcLogger.h" +/* void IfcGeom::IteratorSettings::set_deflection_tolerance(double value) { deflection_tolerance_ = value; @@ -10,3 +11,5 @@ void IfcGeom::IteratorSettings::set_deflection_tolerance(double value) deflection_tolerance_ = 1e-3; } } + +*/ \ No newline at end of file diff --git a/src/ifcgeom/IfcGeomRepresentation.cpp b/src/ifcgeom/IfcGeomRepresentation.cpp index 0df4f6ea6b..1c6e31813a 100644 --- a/src/ifcgeom/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/IfcGeomRepresentation.cpp @@ -142,7 +142,7 @@ namespace { #endif IfcGeom::Representation::Serialization::Serialization(const BRep& brep) - : Representation(brep.settings()) + : Representation(brep.settings(), brep.entity()) , id_(brep.id()) { for (auto it = brep.begin(); it != brep.end(); ++it) { @@ -213,9 +213,9 @@ IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool trsf = tr; } - if (!force_meters && settings().get(IteratorSettings::CONVERT_BACK_UNITS)) { + if (!force_meters && settings().get().get()) { gp_Trsf scale; - scale.SetScaleFactor(1.0 / settings().unit_magnitude()); + scale.SetScaleFactor(1.0 / settings().get().get()); trsf.PreMultiply(scale); } @@ -299,7 +299,7 @@ bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ifcop for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { double x, y, z; - surface_area_along_direction(settings().deflection_tolerance(), *std::static_pointer_cast(it->Shape()), ax, x, y, z); + surface_area_along_direction(settings().get().get(), *std::static_pointer_cast(it->Shape()), ax, x, y, z); if (util::is_manifold(*std::static_pointer_cast(it->Shape()))) { x /= 2.; @@ -323,7 +323,7 @@ bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ifcop } IfcGeom::Representation::Triangulation::Triangulation(const BRep& shape_model) - : Representation(shape_model.settings()) + : Representation(shape_model.settings(), shape_model.entity()) , id_(shape_model.id()) , weld_offset_(0) { @@ -343,8 +343,8 @@ IfcGeom::Representation::Triangulation::Triangulation(const BRep& shape_model) } } - if (settings().get(IteratorSettings::APPLY_DEFAULT_MATERIALS) && surface_style_id == -1) { - const auto& material = IfcGeom::get_default_style(settings().element_type()); + if (settings().get().get() && surface_style_id == -1) { + const auto& material = IfcGeom::get_default_style(shape_model.entity()); auto mit = std::find(_materials.begin(), _materials.end(), material); if (mit == _materials.end()) { surface_style_id = (int)_materials.size(); @@ -390,12 +390,13 @@ std::vector IfcGeom::Representation::Triangulation::box_project_uvs(cons } int IfcGeom::Representation::Triangulation::addVertex(int material_index, double pX, double pY, double pZ) { - const bool convert = settings().get(IteratorSettings::CONVERT_BACK_UNITS); - const double X = convert ? (pX / settings().unit_magnitude()) : pX; - const double Y = convert ? (pY / settings().unit_magnitude()) : pY; - const double Z = convert ? (pZ / settings().unit_magnitude()) : pZ; + const bool convert = settings().get().get(); + auto unit_magnitude = settings().get().get(); + const double X = convert ? (pX /unit_magnitude) : pX; + const double Y = convert ? (pY /unit_magnitude) : pY; + const double Z = convert ? (pZ /unit_magnitude) : pZ; int i = (int)_verts.size() / 3; - if (settings().get(IteratorSettings::WELD_VERTICES)) { + if (settings().get().get()) { const VertexKey key = std::make_pair(material_index, std::make_pair(X, std::make_pair(Y, Z))); typename VertexKeyMap::const_iterator it = welds.find(key); if (it != welds.end()) return it->second; diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom/IfcGeomRepresentation.h index 0de11dda83..d071cfcce7 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom/IfcGeomRepresentation.h @@ -20,7 +20,7 @@ #ifndef IFCGEOMREPRESENTATION_H #define IFCGEOMREPRESENTATION_H -#include "../ifcgeom/IteratorSettings.h" +#include "../ifcgeom/ConversionSettings.h" #include "../ifcgeom/ConversionResult.h" #include @@ -33,12 +33,17 @@ namespace IfcGeom { Representation(const Representation&); //N/A Representation& operator =(const Representation&); //N/A protected: - const ElementSettings settings_; + const ifcopenshell::geometry::Settings settings_; + const std::string entity_; public: - explicit Representation(const ElementSettings& settings) - : settings_(settings) + explicit Representation(const ifcopenshell::geometry::Settings& settings, const std::string& entity) + : settings_(settings) + , entity_(entity) {} - const ElementSettings& settings() const { return settings_; } + const ifcopenshell::geometry::Settings& settings() const { return settings_; } + const std::string& entity() const { + return entity_; + } virtual ~Representation() {} }; @@ -49,8 +54,8 @@ namespace IfcGeom { BRep(const BRep& other); BRep& operator=(const BRep& other); public: - BRep(const ElementSettings& settings, const std::string& id, const IfcGeom::ConversionResults& shapes) - : Representation(settings) + BRep(const ifcopenshell::geometry::Settings& settings, const std::string& entity, const std::string& id, const IfcGeom::ConversionResults& shapes) + : Representation(settings, entity) , id_(id) , shapes_(shapes) {} @@ -108,8 +113,8 @@ namespace IfcGeom { size_t weld_offset_; VertexKeyMap welds; - Triangulation(IfcGeom::IteratorSettings settings) - : Representation(IfcGeom::ElementSettings{ settings, 1., "" }) + Triangulation(const ifcopenshell::geometry::Settings& settings, const std::string& entity) + : Representation(settings, entity) , weld_offset_(0) {} @@ -127,7 +132,8 @@ namespace IfcGeom { Triangulation(const BRep& shape_model); Triangulation( - ElementSettings settings, + const ifcopenshell::geometry::Settings& settings, + const std::string& entity, const std::string& id, const std::vector& verts, const std::vector& faces, @@ -137,7 +143,7 @@ namespace IfcGeom { const std::vector& material_ids, const std::vector& materials ) - : Representation(settings) + : Representation(settings, entity) , id_(id) , _verts(verts) , _faces(faces) @@ -154,7 +160,7 @@ namespace IfcGeom { /// @todo Very simple impl. Assumes that input vertices and normals match 1:1. static std::vector box_project_uvs(const std::vector &vertices, const std::vector &normals); - static Triangulation* empty(IfcGeom::IteratorSettings settings) { return new Triangulation(settings); } + static Triangulation* empty(const ifcopenshell::geometry::Settings& settings) { return new Triangulation(settings, ""); } /// Welds vertices that belong to different faces int addVertex(int material_index, double X, double Y, double Z); diff --git a/src/ifcgeom/Iterator.h b/src/ifcgeom/Iterator.h index cb4cf92389..b5698a570b 100644 --- a/src/ifcgeom/Iterator.h +++ b/src/ifcgeom/Iterator.h @@ -85,14 +85,11 @@ #include #include -// @todo -using namespace ifcopenshell::geometry; - namespace { struct geometry_conversion_result { int index; ifcopenshell::geometry::taxonomy::ptr item; - std::vector> products; + std::vector> products; std::vector breps; std::vector elements; }; @@ -124,17 +121,17 @@ namespace IfcGeom { std::string geometry_library_; - IteratorSettings settings_; + ifcopenshell::geometry::Settings settings_; IfcParse::IfcFile* ifc_file; std::vector filters_; bool owns_ifc_file; int num_threads_; // When single-threaded - Converter* converter_; + ifcopenshell::geometry::Converter* converter_; // When multi-threaded - std::vector kernel_pool; + std::vector kernel_pool; // The object is fetched beforehand to be sure that get() returns a valid element TriangulationElement* current_triangulation; @@ -151,8 +148,8 @@ namespace IfcGeom { std::string unit_name_; double unit_magnitude_; - taxonomy::point3 bounds_min_; - taxonomy::point3 bounds_max_; + ifcopenshell::geometry::taxonomy::point3 bounds_min_; + ifcopenshell::geometry::taxonomy::point3 bounds_max_; // Should not be destructed because, destructor is blocking std::future init_future_; @@ -171,8 +168,8 @@ namespace IfcGeom { return *initialization_outcome_; } - converter_ = new Converter(geometry_library_, ifc_file, settings_); - std::vector reps; + converter_ = new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_); + std::vector reps; converter_->mapping()->get_representations(reps, filters_); for (auto& task : reps) { @@ -183,7 +180,7 @@ namespace IfcGeom { } std::transform(task.products->begin(), task.products->end(), std::back_inserter(res.products), [this, &res](IfcUtil::IfcBaseClass* prod) { auto prod_item = converter_->mapping()->map(prod); - return std::make_pair(prod->as(), taxonomy::cast(prod_item)->matrix); + return std::make_pair(prod->as(), ifcopenshell::geometry::taxonomy::cast(prod_item)->matrix); }); tasks_.push_back(res); } @@ -279,13 +276,13 @@ namespace IfcGeom { kernel_pool.reserve(conc_threads); for (unsigned i = 0; i < conc_threads; ++i) { - kernel_pool.push_back(new Converter(geometry_library_, ifc_file, settings_)); + kernel_pool.push_back(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)); } std::vector> threadpool; for (auto& rep : tasks_) { - Converter* K = nullptr; + ifcopenshell::geometry::Converter* K = nullptr; if (threadpool.size() < kernel_pool.size()) { K = kernel_pool[threadpool.size()]; } @@ -309,8 +306,8 @@ namespace IfcGeom { std::future fu = std::async( std::launch::async, [this]( - Converter* kernel, - const IfcGeom::IteratorSettings& settings, + ifcopenshell::geometry::Converter* kernel, + ifcopenshell::geometry::Settings settings, geometry_conversion_result* rep) { this->create_element_(kernel, settings, rep); return rep; @@ -364,7 +361,7 @@ namespace IfcGeom { } } while (++num_created, next()); } else { - std::vector reps; + std::vector reps; converter_->mapping()->get_representations(reps, filters_); std::vector products; @@ -374,7 +371,7 @@ namespace IfcGeom { for (auto& product : products) { auto prod_item = converter_->mapping()->map(product); - auto vec = taxonomy::cast(prod_item)->matrix->translation_part(); + auto vec = ifcopenshell::geometry::taxonomy::cast(prod_item)->matrix->translation_part(); for (int i = 0; i < 3; ++i) { bounds_min_.components()(i) = std::min(bounds_min_.components()(i), vec(i)); @@ -395,8 +392,8 @@ namespace IfcGeom { const std::vector& filters() const { return filters_; } std::vector& filters() { return filters_; } - const taxonomy::point3& bounds_min() const { return bounds_min_; } - const taxonomy::point3& bounds_max() const { return bounds_max_; } + const ifcopenshell::geometry::taxonomy::point3& bounds_min() const { return bounds_min_; } + const ifcopenshell::geometry::taxonomy::point3& bounds_max() const { return bounds_max_; } private: @@ -460,8 +457,8 @@ namespace IfcGeom { } void create_element_( - Converter* kernel, - const IfcGeom::IteratorSettings& settings, + ifcopenshell::geometry::Converter* kernel, + ifcopenshell::geometry::Settings settings, geometry_conversion_result* rep) { auto representation = rep->item; @@ -507,18 +504,18 @@ namespace IfcGeom { } IfcGeom::Element* process_based_on_settings( - const IfcGeom::IteratorSettings& settings, + ifcopenshell::geometry::Settings settings, IfcGeom::BRepElement* elem, IfcGeom::TriangulationElement* previous = nullptr) { - if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) { + if (settings.get().get() == ifcopenshell::geometry::settings::SERIALIZED) { try { return new IfcGeom::SerializedElement(*elem); } catch (...) { Logger::Message(Logger::LOG_ERROR, "Getting a serialized element from model failed."); return nullptr; } - } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { + } else if (settings.get().get() == ifcopenshell::geometry::settings::TRIANGULATED) { // the part before the hyphen is the representation id auto gid2 = elem->geometry().id(); auto hyphen = gid2.find("-"); @@ -610,7 +607,7 @@ namespace IfcGeom { auto ret = *task_result_iterator_; // If we want to organize the element considering their hierarchy - if (settings_.get(IteratorSettings::ELEMENT_HIERARCHY)) + if (settings_.get().get()) { // We are going to build a vector with the element parents. // First, create the parent vector @@ -665,7 +662,7 @@ namespace IfcGeom { } const Element* get_object(int id) { - taxonomy::matrix4::ptr m4; + ifcopenshell::geometry::taxonomy::matrix4::ptr m4; int parent_id = -1; std::string instance_type, product_name, product_guid; IfcUtil::IfcBaseEntity* ifc_product = 0; @@ -684,7 +681,7 @@ namespace IfcGeom { parent_id = parent_object->data().id(); } - m4 = taxonomy::cast(converter_->mapping()->map(ifc_product))->matrix; + m4 = ifcopenshell::geometry::taxonomy::cast(converter_->mapping()->map(ifc_product))->matrix; } catch (const std::exception& e) { Logger::Error(e); } @@ -701,9 +698,7 @@ namespace IfcGeom { Logger::Error("Unknown error returning product"); } - ElementSettings element_settings(settings_, unit_magnitude_, instance_type); - - Element* ifc_object = new Element(element_settings, id, parent_id, product_name, instance_type, product_guid, "", m4, ifc_product); + Element* ifc_object = new Element(settings_, id, parent_id, product_name, instance_type, product_guid, "", m4, ifc_product); return ifc_object; } @@ -729,7 +724,7 @@ namespace IfcGeom { return product; } - Iterator(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) + Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) : settings_(settings) , ifc_file(file) , filters_(filters) @@ -739,7 +734,7 @@ namespace IfcGeom { { } - Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) + Iterator(const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) : settings_(settings) , ifc_file(file) , filters_(filters) @@ -749,7 +744,7 @@ namespace IfcGeom { { } - Iterator(const IteratorSettings& settings, IfcParse::IfcFile* file) + Iterator(const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file) : settings_(settings) , ifc_file(file) , owns_ifc_file(false) @@ -758,7 +753,7 @@ namespace IfcGeom { { } - Iterator(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file) + Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file) : settings_(settings) , ifc_file(file) , owns_ifc_file(false) @@ -767,7 +762,7 @@ namespace IfcGeom { { } - Iterator(const std::string& geometry_library, const IteratorSettings& settings, IfcParse::IfcFile* file, int num_threads) + Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, int num_threads) : settings_(settings) , ifc_file(file) , owns_ifc_file(false) @@ -781,7 +776,7 @@ namespace IfcGeom { delete ifc_file; } - if (!settings_.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { + if (!settings_.get().get() == ifcopenshell::geometry::settings::NATIVE) { for (auto& p : all_processed_native_elements_) { delete p; } diff --git a/src/ifcgeom/IteratorSettings.h b/src/ifcgeom/IteratorSettings.h index 03c6bc0ab8..2a7c03c507 100644 --- a/src/ifcgeom/IteratorSettings.h +++ b/src/ifcgeom/IteratorSettings.h @@ -20,6 +20,8 @@ #ifndef IFCGEOMITERATORSETTINGS_H #define IFCGEOMITERATORSETTINGS_H +/* + #include "ifc_geom_api.h" #include "../ifcparse/IfcException.h" @@ -205,4 +207,6 @@ namespace IfcGeom }; } +*/ + #endif diff --git a/src/ifcgeom/abstract_mapping.cpp b/src/ifcgeom/abstract_mapping.cpp index aa81658c80..d954b604c5 100644 --- a/src/ifcgeom/abstract_mapping.cpp +++ b/src/ifcgeom/abstract_mapping.cpp @@ -33,7 +33,7 @@ void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std: this->insert(std::make_pair(schema_name_lower, fn)); } -ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, IfcGeom::IteratorSettings& s) { +ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(IfcParse::IfcFile* file, Settings& s) { const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name()); std::map::const_iterator it; it = this->find(schema_name_lower); diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h index e6230fc062..52f7394fd6 100644 --- a/src/ifcgeom/abstract_mapping.h +++ b/src/ifcgeom/abstract_mapping.h @@ -27,10 +27,9 @@ namespace geometry { class abstract_mapping { protected: - IfcGeom::IteratorSettings settings_; - ConversionSettings conv_settings_; + Settings settings_; public: - abstract_mapping(IfcGeom::IteratorSettings& s) : settings_(s) {} + abstract_mapping(Settings& s) : settings_(s) {} virtual ifcopenshell::geometry::taxonomy::ptr map(const IfcUtil::IfcBaseInterface*) = 0; virtual void get_representations(std::vector& tasks, std::vector& filters) = 0; @@ -44,18 +43,17 @@ namespace geometry { virtual double get_length_unit() const = 0; virtual IfcUtil::IfcBaseEntity* representation_of(const IfcUtil::IfcBaseEntity* product) = 0; - const IfcGeom::IteratorSettings& settings() const { return settings_; } - const ConversionSettings& conversion_settings() const { return conv_settings_; } + const Settings& settings() const { return settings_; } }; namespace impl { - typedef boost::function2 mapping_fn; + typedef boost::function2 mapping_fn; class MappingFactoryImplementation : public std::map { public: MappingFactoryImplementation(); void bind(const std::string& schema_name, mapping_fn); - abstract_mapping* construct(IfcParse::IfcFile*, IfcGeom::IteratorSettings&); + abstract_mapping* construct(IfcParse::IfcFile*, Settings&); }; MappingFactoryImplementation& mapping_implementations(); diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index b62c0ff1dd..2d29b2d3a1 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -18,7 +18,7 @@ using ifcopenshell::geometry::NumberEpeck; #define NumberType NumberEpeck #endif -void ifcopenshell::geometry::CgalShape::Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { +void ifcopenshell::geometry::CgalShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { // Copy is made because triangulate_faces() obviously does not accept a const argument // ... also becuase of transforming the vertex positions, right? cgal_shape_t s = *this; @@ -372,7 +372,7 @@ void ifcopenshell::geometry::CgalShape::map(OpaqueCoordinate<4>& from, OpaqueCoo #ifndef IFOPSH_SIMPLE_KERNEL -void ifcopenshell::geometry::CgalShapeHalfSpaceDecomposition::Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { +void ifcopenshell::geometry::CgalShapeHalfSpaceDecomposition::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { throw std::runtime_error("Not implemented"); } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index bda2dd90af..e5d7e896e3 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -205,7 +205,7 @@ namespace ifcopenshell { namespace geometry { operator const cgal_shape_t& () const { to_poly(); return *shape_; } const cgal_shape_t& poly() const { to_poly(); return *shape_; } - virtual void Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const; virtual IfcGeom::ConversionResultShape* clone() const { @@ -268,7 +268,7 @@ namespace ifcopenshell { namespace geometry { planes_.push_back(shape); } - virtual void Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const; virtual int surface_genus() const; diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 39511bb08d..4fa2f456db 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -1109,7 +1109,7 @@ bool CgalKernel::process_extrusion(const cgal_face_t& bottom_face, taxonomy::dir bool CgalKernel::convert(const taxonomy::extrusion::ptr extrusion, cgal_shape_t &shape) { const double& height = extrusion->depth; - if (height < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { + if (height < settings_.get().get()) { Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", extrusion->instance); return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 64a72fc523..37f65c675a 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -86,13 +86,13 @@ namespace ifcopenshell { bool thin_solid(const CGAL::Nef_polyhedron_3& a, CGAL::Nef_polyhedron_3& result); CGAL::Nef_polyhedron_3 create_precision_cube_() const { - auto cc = utils::create_cube(conv_settings_.getValue(ConversionSettings::GV_PRECISION)); + auto cc = utils::create_cube(settings_.get().get()); return CGAL::Nef_polyhedron_3(cc); } #endif public: - CgalKernel(const ConversionSettings& settings) + CgalKernel(const Settings& settings) : AbstractKernel("cgal", settings) , circle_segments_(32) {} diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index 95826db674..6c94a7fe8f 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -269,7 +269,7 @@ namespace IfcGeom { std::vector select(const IfcGeom::BRepElement* elem, bool completely_within = false, double extend = -1.e-5) const { auto shp = elem->geometry().as_compound(); - auto compound = ((OpenCascadeShape*)shp)->shape(); + auto compound = ((ifcopenshell::geometry::OpenCascadeShape*)shp)->shape(); const auto& m = elem->transformation().data()->ccomponents(); gp_Trsf tr; tr.SetValues( @@ -369,10 +369,10 @@ namespace IfcGeom { tree() {}; tree(IfcParse::IfcFile& f) { - add_file(f, IfcGeom::IteratorSettings()); + add_file(f, ifcopenshell::geometry::Settings{}); } - tree(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) { + tree(IfcParse::IfcFile& f, ifcopenshell::geometry::Settings settings) { add_file(f, settings); } @@ -380,11 +380,11 @@ namespace IfcGeom { add_file(it); } - void add_file(IfcParse::IfcFile& f, const IfcGeom::IteratorSettings& settings) { - IfcGeom::IteratorSettings settings_ = settings; - settings_.set(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION, true); - settings_.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, true); - settings_.set(IfcGeom::IteratorSettings::SEW_SHELLS, true); + void add_file(IfcParse::IfcFile& f, ifcopenshell::geometry::Settings settings) { + ifcopenshell::geometry::Settings settings_ = settings; + settings_.get().value = ifcopenshell::geometry::settings::NATIVE; + settings_.get().value = true; + settings_.get().value = true; IfcGeom::Iterator it(settings_, &f, {}, 1); diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index 3a9df92d0f..723ecc585a 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -31,7 +31,7 @@ namespace { } } -void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { +void ifcopenshell::geometry::OpenCascadeShape::Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const { // @todo remove duplication with OpenCascadeKernel::convert(const taxonomy::matrix4::ptr matrix, gp_GTrsf& trsf); // above can be static? @@ -50,7 +50,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::Iterat // Triangulate the shape try { - BRepMesh_IncrementalMesh(shape_, settings.deflection_tolerance(), false, settings.angular_tolerance()); + BRepMesh_IncrementalMesh(shape_, settings.get().get(), false, settings.get().get()); } catch (...) { Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); return; @@ -77,8 +77,8 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::Iterat std::map dict; // Vertex normals are only calculated if vertices are not welded and calculation is not disable explicitly. - const bool calculate_normals = !settings.get(IfcGeom::IteratorSettings::WELD_VERTICES) && - !settings.get(IfcGeom::IteratorSettings::NO_NORMALS); + const bool calculate_normals = !settings.get().get() && + !settings.get().get(); for (int i = 1; i <= tri->NbNodes(); ++i) { coords.push_back(tri->Node(i).Transformed(loc).XYZ()); @@ -155,7 +155,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::Iterat } } - if (!t->normals().empty() && settings.get(IfcGeom::IteratorSettings::GENERATE_UVS)) { + if (!t->normals().empty() && settings.get().get()) { t->uvs() = IfcGeom::Representation::Triangulation::box_project_uvs(t->verts(), t->normals()); } @@ -166,7 +166,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::Iterat // belong to any face. for (TopExp_Explorer texp(shape_, TopAbs_EDGE); texp.More(); texp.Next()) { BRepAdaptor_Curve crv(TopoDS::Edge(texp.Current())); - GCPnts_QuasiUniformDeflection tessellater(crv, settings.deflection_tolerance()); + GCPnts_QuasiUniformDeflection tessellater(crv, settings.get().get()); int n = tessellater.NbPoints(); int previous = -1; @@ -182,7 +182,7 @@ void ifcopenshell::geometry::OpenCascadeShape::Triangulate(const IfcGeom::Iterat segments.push_back(std::make_pair(previous, current)); } - if (settings.get(IfcGeom::IteratorSettings::EDGE_ARROWS)) { + if (settings.get().get()) { // In case you want direction arrows on your edges double u = tessellater.Parameter(i); gp_XYZ p2, p3; diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h index 4b9600f25b..2046852255 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h @@ -50,7 +50,7 @@ namespace ifcopenshell { const TopoDS_Shape& shape() const { return shape_; } operator const TopoDS_Shape& () { return shape_; } - virtual void Triangulate(const IfcGeom::IteratorSettings& settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; + virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int surface_style_id) const; virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const; virtual IfcGeom::ConversionResultShape* clone() const { diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp index 4b770a3dbd..bea99141eb 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.cpp @@ -201,13 +201,15 @@ namespace { }; } +using namespace ifcopenshell::geometry; + bool IfcGeom::OpenCascadeKernel::convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector>& openings, const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes) { util::boolean_settings bst; - bst.attempt_2d = conv_settings_.getValue(ConversionSettings::GV_BOOLEAN_ATTEMPT_2D) > 0.; - bst.debug = conv_settings_.getValue(ConversionSettings::GV_DEBUG_BOOLEAN) > 0.; - bst.precision = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + bst.attempt_2d = settings_.get().get(); + bst.debug = settings_.get().get(); + bst.precision = settings_.get().get(); std::vector< std::pair > opening_vector; @@ -248,7 +250,7 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const IfcUtil::IfcBaseEntity* for (unsigned int i = 0; i < opening_shapes.size(); ++i) { TopoDS_Shape opening_shape_solid; auto opening_shape_i = std::static_pointer_cast(opening_shapes[i].Shape())->shape(); - const TopoDS_Shape& opening_shape_unlocated = util::ensure_fit_for_subtraction(opening_shape_i, opening_shape_solid, conv_settings_.getValue(ConversionSettings::GV_PRECISION)); + const TopoDS_Shape& opening_shape_unlocated = util::ensure_fit_for_subtraction(opening_shape_i, opening_shape_solid, settings_.get().get()); auto gtrsf = opening_shapes[i].Placement(); // @todo check @@ -306,7 +308,7 @@ bool IfcGeom::OpenCascadeKernel::convert_openings(const IfcUtil::IfcBaseEntity* if (as_shell) { entity_shape_unlocated = entity_part; } else { - entity_shape_unlocated = util::ensure_fit_for_subtraction(entity_part, entity_shape_solid, conv_settings_.getValue(ConversionSettings::GV_PRECISION)); + entity_shape_unlocated = util::ensure_fit_for_subtraction(entity_part, entity_shape_solid, settings_.get().get()); } const auto& m = it3->Placement()->ccomponents(); // @todo diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index 424771f697..f05597b123 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -56,12 +56,9 @@ #include "../../../ifcgeom/taxonomy.h" #include "../../../ifcgeom/ConversionSettings.h" -// @todo remove once merged to same ns. -using namespace ifcopenshell::geometry; - namespace IfcGeom { -class IFC_GEOM_API OpenCascadeKernel : public kernels::AbstractKernel { +class IFC_GEOM_API OpenCascadeKernel : public ifcopenshell::geometry::kernels::AbstractKernel { private: /* @@ -81,7 +78,7 @@ private: double eps_; bool non_manifold_; - void loop_(const taxonomy::loop::ptr ps, const std::function& callback); + void loop_(const ifcopenshell::geometry::taxonomy::loop::ptr ps, const std::function& callback); /* bool construct(const IfcSchema::IfcCartesianPoint* cp, gp_Pnt* l); @@ -99,7 +96,7 @@ private: std::vector get_idxs(const std::vector& it); */ public: - faceset_helper(OpenCascadeKernel* kernel, const taxonomy::shell::ptr l); + faceset_helper(OpenCascadeKernel* kernel, const ifcopenshell::geometry::taxonomy::shell::ptr l); ~faceset_helper(); bool non_manifold() const { return non_manifold_; } @@ -108,8 +105,8 @@ private: bool edge(int A, int B, TopoDS_Edge& e); - bool wire(const taxonomy::loop::ptr loop, TopoDS_Wire& wire); - bool wires(const taxonomy::loop::ptr loop, TopTools_ListOfShape& wires); + bool wire(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopoDS_Wire& wire); + bool wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopTools_ListOfShape& wires); }; faceset_helper* faceset_helper_; @@ -124,28 +121,28 @@ private: double precision_; public: - OpenCascadeKernel(const ConversionSettings& settings) + OpenCascadeKernel(const ifcopenshell::geometry::Settings& settings) : AbstractKernel("opencascade", settings) , faceset_helper_(nullptr) - , precision_(settings.getValue(ConversionSettings::GV_PRECISION)) + , precision_(settings.get().get()) {} - bool convert(const taxonomy::extrusion::ptr, TopoDS_Shape&); - bool convert(const taxonomy::face::ptr, TopoDS_Shape&); - bool convert(const taxonomy::loop::ptr, TopoDS_Wire&); - bool convert(const taxonomy::matrix4::ptr, gp_GTrsf&); - bool convert(const taxonomy::shell::ptr, TopoDS_Shape&); - bool convert(const taxonomy::solid::ptr, TopoDS_Shape&); - bool convert(const taxonomy::bspline_surface::ptr bs, Handle(Geom_Surface) surf); + bool convert(const ifcopenshell::geometry::taxonomy::extrusion::ptr, TopoDS_Shape&); + bool convert(const ifcopenshell::geometry::taxonomy::face::ptr, TopoDS_Shape&); + bool convert(const ifcopenshell::geometry::taxonomy::loop::ptr, TopoDS_Wire&); + bool convert(const ifcopenshell::geometry::taxonomy::matrix4::ptr, gp_GTrsf&); + bool convert(const ifcopenshell::geometry::taxonomy::shell::ptr, TopoDS_Shape&); + bool convert(const ifcopenshell::geometry::taxonomy::solid::ptr, TopoDS_Shape&); + bool convert(const ifcopenshell::geometry::taxonomy::bspline_surface::ptr bs, Handle(Geom_Surface) surf); - virtual bool convert_impl(const taxonomy::loop::ptr, IfcGeom::ConversionResults&); - virtual bool convert_impl(const taxonomy::face::ptr, IfcGeom::ConversionResults&); - virtual bool convert_impl(const taxonomy::solid::ptr, IfcGeom::ConversionResults&); - virtual bool convert_impl(const taxonomy::shell::ptr, IfcGeom::ConversionResults&); - virtual bool convert_impl(const taxonomy::extrusion::ptr, IfcGeom::ConversionResults&); - virtual bool convert_impl(const taxonomy::boolean_result::ptr, IfcGeom::ConversionResults&); + virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::loop::ptr, IfcGeom::ConversionResults&); + virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::face::ptr, IfcGeom::ConversionResults&); + virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::solid::ptr, IfcGeom::ConversionResults&); + virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::shell::ptr, IfcGeom::ConversionResults&); + virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::extrusion::ptr, IfcGeom::ConversionResults&); + virtual bool convert_impl(const ifcopenshell::geometry::taxonomy::boolean_result::ptr, IfcGeom::ConversionResults&); - virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector>& openings, + virtual bool convert_openings(const IfcUtil::IfcBaseEntity* entity, const std::vector>& openings, const IfcGeom::ConversionResults& entity_shapes, const ifcopenshell::geometry::taxonomy::matrix4& entity_trsf, IfcGeom::ConversionResults& cut_shapes); template diff --git a/src/ifcgeom/kernels/opencascade/boolean_result.cpp b/src/ifcgeom/kernels/opencascade/boolean_result.cpp index 9764316ee1..768b9859ef 100644 --- a/src/ifcgeom/kernels/opencascade/boolean_result.cpp +++ b/src/ifcgeom/kernels/opencascade/boolean_result.cpp @@ -46,7 +46,7 @@ namespace { bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, ConversionResults& results) { bool valid_result = false; bool first = true; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); TopoDS_Shape a; TopTools_ListOfShape b; @@ -58,14 +58,14 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con AbstractKernel::convert(c, cr); if (first && br->operation == taxonomy::boolean_result::SUBTRACTION) { // @todo A will be null on union/intersection, intended? - IfcGeom::util::flatten_shape_list(cr, a, false, conv_settings_.getValue(ifcopenshell::geometry::ConversionSettings::GV_PRECISION)); + IfcGeom::util::flatten_shape_list(cr, a, false, settings_.get().get()); first_item_style = c->surface_style; if (!first_item_style && c->kind() == taxonomy::COLLECTION) { // @todo recursively right? first_item_style = taxonomy::cast(taxonomy::cast(c)->children[0])->surface_style; } - if (conv_settings_.getValue(ConversionSettings::GV_DISABLE_BOOLEAN_RESULT) > 0.0) { + if (settings_.get().get()) { results.emplace_back(IfcGeom::ConversionResult( (int)br->instance->data().id(), br->matrix, @@ -109,9 +109,9 @@ bool OpenCascadeKernel::convert_impl(const taxonomy::boolean_result::ptr br, Con } util::boolean_settings bst; - bst.attempt_2d = conv_settings_.getValue(ConversionSettings::GV_BOOLEAN_ATTEMPT_2D) > 0.; - bst.debug = conv_settings_.getValue(ConversionSettings::GV_DEBUG_BOOLEAN) > 0.; - bst.precision = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + bst.attempt_2d = settings_.get().get(); + bst.debug = settings_.get().get(); + bst.precision = settings_.get().get(); TopoDS_Shape r; diff --git a/src/ifcgeom/kernels/opencascade/extrusion.cpp b/src/ifcgeom/kernels/opencascade/extrusion.cpp index e5c6c6d5c1..bfeaa021eb 100644 --- a/src/ifcgeom/kernels/opencascade/extrusion.cpp +++ b/src/ifcgeom/kernels/opencascade/extrusion.cpp @@ -9,7 +9,7 @@ using namespace IfcGeom; bool OpenCascadeKernel::convert(const taxonomy::extrusion::ptr extrusion, TopoDS_Shape& shape) { const double& height = extrusion->depth; - if (height < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { + if (height < settings_.get().get()) { Logger::Error("Non-positive extrusion height encountered for:", extrusion->instance); return false; } diff --git a/src/ifcgeom/kernels/opencascade/faceset_helper.cpp b/src/ifcgeom/kernels/opencascade/faceset_helper.cpp index 7f2ea86104..683a3c6d32 100644 --- a/src/ifcgeom/kernels/opencascade/faceset_helper.cpp +++ b/src/ifcgeom/kernels/opencascade/faceset_helper.cpp @@ -27,21 +27,21 @@ namespace { IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper( OpenCascadeKernel* kernel, - const taxonomy::shell::ptr shell + const ifcopenshell::geometry::taxonomy::shell::ptr shell ) : kernel_(kernel) , non_manifold_(false) { // @todo use pointers? - std::vector points; - std::vector loops; + std::vector points; + std::vector loops; for (auto& f : shell->children) { for (auto& l : f->children) { loops.push_back(l); for (auto& e : l->children) { // @todo make sure only cartesian points are provided here - points.push_back(boost::get(e->start)); + points.push_back(boost::get(e->start)); } } } @@ -79,12 +79,12 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper( double bdiff = std::numeric_limits::infinity(); for (size_t i = 0; i < 3; ++i) { const double d = bmax[i] - bmin[i]; - if (d > kernel->settings().getValue(ConversionSettings::GV_PRECISION) * 10. && d < bdiff) { + if (d > kernel->settings().get().get() * 10. && d < bdiff) { bdiff = d; } } - eps_ = kernel->settings().getValue(ConversionSettings::GV_PRECISION) * 10. * (std::min)(1.0, bdiff); + eps_ = kernel->settings().get().get() * 10. * (std::min)(1.0, bdiff); size_t loops_removed, non_manifold, duplicate_faces; @@ -192,15 +192,15 @@ IfcGeom::OpenCascadeKernel::faceset_helper::faceset_helper( } } -void IfcGeom::OpenCascadeKernel::faceset_helper::loop_(const taxonomy::loop::ptr ps, const std::function& callback) { +void IfcGeom::OpenCascadeKernel::faceset_helper::loop_(const ifcopenshell::geometry::taxonomy::loop::ptr ps, const std::function& callback) { if (ps->children.size() < 3) { return; } - auto a = boost::get(ps->children.back()->start); + auto a = boost::get(ps->children.back()->start); auto A = a->identity(); for (auto& b : ps->children) { - auto B = boost::get(b->start)->identity(); + auto B = boost::get(b->start)->identity(); auto C = vertex_mapping_[A], D = vertex_mapping_[B]; bool fwd = C < D; if (!fwd) { @@ -222,7 +222,7 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::edge(int A, int B, TopoDS_Edge& return true; } -bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const taxonomy::loop::ptr loop, TopoDS_Wire& w) { +bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopoDS_Wire& w) { TopTools_ListOfShape ws; if (!wires(loop, ws)) { return false; @@ -231,7 +231,7 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::wire(const taxonomy::loop::ptr return true; } -bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const taxonomy::loop::ptr loop, TopTools_ListOfShape& wires) { +bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const ifcopenshell::geometry::taxonomy::loop::ptr loop, TopTools_ListOfShape& wires) { if (duplicates_.find(loop->identity()) != duplicates_.end()) { return false; } @@ -253,7 +253,11 @@ bool IfcGeom::OpenCascadeKernel::faceset_helper::wires(const taxonomy::loop::ptr wire.Closed(true); TopTools_ListOfShape results; - if (kernel_->settings().getValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_CHECK) < 0. && util::wire_intersections(wire, results, {kernel_->settings().getValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_CHECK) < 0., kernel_->settings().getValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_TOLERANCE) < 0., 0., kernel_->settings().getValue(ConversionSettings::GV_PRECISION)})) { + if (!kernel_->settings().get().get() && util::wire_intersections(wire, results, { + !kernel_->settings().get().get(), + !kernel_->settings().get().get(), 0., + kernel_->settings().get().get()})) + { Logger::Warning("Self-intersections with " + boost::lexical_cast(results.Extent()) + " cycles detected"); non_manifold_ = true; wires = results; diff --git a/src/ifcgeom/kernels/opencascade/shell.cpp b/src/ifcgeom/kernels/opencascade/shell.cpp index 25defac364..5ffd78c99e 100644 --- a/src/ifcgeom/kernels/opencascade/shell.cpp +++ b/src/ifcgeom/kernels/opencascade/shell.cpp @@ -72,7 +72,7 @@ bool OpenCascadeKernel::convert(const taxonomy::shell::ptr l, TopoDS_Shape& shap // @todo /* face_list.Extent() > getValue(GV_MAX_FACES_TO_ORIENT) || */ - if (!create_solid_from_faces(face_list, shape, conv_settings_.getValue(ifcopenshell::geometry::ConversionSettings::GV_PRECISION))) { + if (!create_solid_from_faces(face_list, shape, settings_.get().get())) { TopoDS_Compound compound; BRep_Builder builder; builder.MakeCompound(compound); diff --git a/src/ifcgeom/mapping/IfcCShapeProfileDef.cpp b/src/ifcgeom/mapping/IfcCShapeProfileDef.cpp index 2b62b44fcd..3e69e5f096 100644 --- a/src/ifcgeom/mapping/IfcCShapeProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcCShapeProfileDef.cpp @@ -40,7 +40,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCShapeProfileDef* inst) { f2 = f1 + d1; } - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if ( x < tol || y < tol || d1 < tol || d2 < tol) { Logger::Message(Logger::LOG_NOTICE," Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcCircle.cpp b/src/ifcgeom/mapping/IfcCircle.cpp index fe470c8062..6693cd18ca 100644 --- a/src/ifcgeom/mapping/IfcCircle.cpp +++ b/src/ifcgeom/mapping/IfcCircle.cpp @@ -25,7 +25,7 @@ using namespace ifcopenshell::geometry; taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCircle* inst) { const double r = inst->Radius() * length_unit_; - if (r < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { + if (r < settings_.get().get()) { Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", inst); return nullptr; } diff --git a/src/ifcgeom/mapping/IfcCompositeCurve.cpp b/src/ifcgeom/mapping/IfcCompositeCurve.cpp index 6b814e5181..7d73741a9c 100644 --- a/src/ifcgeom/mapping/IfcCompositeCurve.cpp +++ b/src/ifcgeom/mapping/IfcCompositeCurve.cpp @@ -37,7 +37,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCompositeCurve* inst) { Logger::Notice("Infinite IfcLine used as ParentCurve of segment, treating as a segment", segment); double u0 = 0.0; double u1 = segment->as()->ParentCurve()->as()->Dir()->Magnitude() * length_unit_; - if (u1 < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { + if (u1 < settings_.get().get()) { Logger::Warning("Segment length below tolerance", segment); } diff --git a/src/ifcgeom/mapping/IfcCurveSegment.cpp b/src/ifcgeom/mapping/IfcCurveSegment.cpp index 9586747f70..1d46dba51b 100644 --- a/src/ifcgeom/mapping/IfcCurveSegment.cpp +++ b/src/ifcgeom/mapping/IfcCurveSegment.cpp @@ -632,7 +632,7 @@ class curve_segment_evaluator { auto dy = p2y - p1y; auto l = sqrt(dx * dx + dy * dy); - if (l < mapping_->conversion_settings().getValue(ConversionSettings::GV_PRECISION)) + if (l < mapping_->settings().get().get()) { std::ostringstream os; os << "Coincident IfcPolyline.Points are not expected. Skipping point " << std::distance(iter, begin) << std::endl; diff --git a/src/ifcgeom/mapping/IfcEllipse.cpp b/src/ifcgeom/mapping/IfcEllipse.cpp index c6e6fe5955..1d1e70e303 100644 --- a/src/ifcgeom/mapping/IfcEllipse.cpp +++ b/src/ifcgeom/mapping/IfcEllipse.cpp @@ -24,7 +24,7 @@ using namespace ifcopenshell::geometry; taxonomy::ptr mapping::map_impl(const IfcSchema::IfcEllipse* inst) { double x = inst->SemiAxis1() * length_unit_; double y = inst->SemiAxis2() * length_unit_; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol) { Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", inst); return nullptr; diff --git a/src/ifcgeom/mapping/IfcEllipseProfileDef.cpp b/src/ifcgeom/mapping/IfcEllipseProfileDef.cpp index 925ca5b508..6d14bf4bf7 100644 --- a/src/ifcgeom/mapping/IfcEllipseProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcEllipseProfileDef.cpp @@ -24,7 +24,7 @@ using namespace ifcopenshell::geometry; taxonomy::ptr mapping::map_impl(const IfcSchema::IfcEllipseProfileDef* inst) { double rx = inst->SemiAxis1() * length_unit_; double ry = inst->SemiAxis2() * length_unit_; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (rx < tol || ry < tol) { Logger::Message(Logger::LOG_ERROR, "Radius not greater than zero for:", inst); return nullptr; diff --git a/src/ifcgeom/mapping/IfcExtrudedAreaSolid.cpp b/src/ifcgeom/mapping/IfcExtrudedAreaSolid.cpp index 4c27fbd3ee..fcdff6952f 100644 --- a/src/ifcgeom/mapping/IfcExtrudedAreaSolid.cpp +++ b/src/ifcgeom/mapping/IfcExtrudedAreaSolid.cpp @@ -26,7 +26,7 @@ using namespace ifcopenshell::geometry; taxonomy::ptr mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolid* inst) { const double height = inst->Depth() * length_unit_; - if (height < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { + if (height < settings_.get().get()) { Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", inst); #ifndef PERMISSIVE_EXTRUSION return nullptr; diff --git a/src/ifcgeom/mapping/IfcExtrudedAreaSolidTapered.cpp b/src/ifcgeom/mapping/IfcExtrudedAreaSolidTapered.cpp index 47209846d2..16c3eb1b95 100644 --- a/src/ifcgeom/mapping/IfcExtrudedAreaSolidTapered.cpp +++ b/src/ifcgeom/mapping/IfcExtrudedAreaSolidTapered.cpp @@ -26,7 +26,7 @@ using namespace ifcopenshell::geometry; #define mapping POSTFIX_SCHEMA(mapping) taxonomy::ptr mapping::map_impl(const IfcSchema::IfcExtrudedAreaSolidTapered* inst) { const double height = inst->Depth() * length_unit_; - if (height < conv_settings_.getValue(ConversionSettings::GV_PRECISION)) { + if (height < settings_.get().get()) { Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", inst); return nullptr; } diff --git a/src/ifcgeom/mapping/IfcIShapeProfileDef.cpp b/src/ifcgeom/mapping/IfcIShapeProfileDef.cpp index 1e3be1b571..1b653a6857 100644 --- a/src/ifcgeom/mapping/IfcIShapeProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcIShapeProfileDef.cpp @@ -78,7 +78,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcIShapeProfileDef* inst) { fe2 = fe1; } - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x1 < tol || x2 < tol || y < tol || d1 < tol || ft1 < tol || ft2 < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcLShapeProfileDef.cpp b/src/ifcgeom/mapping/IfcLShapeProfileDef.cpp index 047af31d8b..4136fa0d4b 100644 --- a/src/ifcgeom/mapping/IfcLShapeProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcLShapeProfileDef.cpp @@ -42,7 +42,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcLShapeProfileDef* inst) { f2 = *inst->EdgeRadius() * length_unit_; } - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if ( x < tol || y < tol || d < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcPolyLoop.cpp b/src/ifcgeom/mapping/IfcPolyLoop.cpp index 1e334d8f8f..34f7ad1aa3 100644 --- a/src/ifcgeom/mapping/IfcPolyLoop.cpp +++ b/src/ifcgeom/mapping/IfcPolyLoop.cpp @@ -41,7 +41,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolyLoop* inst) { } // @todo Remove points that are too close to one another - const double eps = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double eps = settings_.get().get(); // util::remove_duplicate_points_from_loop(polygon, true, eps); int count = polygon.size(); diff --git a/src/ifcgeom/mapping/IfcPolyline.cpp b/src/ifcgeom/mapping/IfcPolyline.cpp index 8b166e1e31..220a0cd936 100644 --- a/src/ifcgeom/mapping/IfcPolyline.cpp +++ b/src/ifcgeom/mapping/IfcPolyline.cpp @@ -33,7 +33,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcPolyline* inst) { return taxonomy::cast(map(p)); }); - const bool closed_by_proximity = polygon.size() >= 3 && (*polygon.front()->components_ - *polygon.back()->components_).norm() < conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const bool closed_by_proximity = polygon.size() >= 3 && (*polygon.front()->components_ - *polygon.back()->components_).norm() < settings_.get().get(); if (closed_by_proximity) { polygon.resize(polygon.size() - 1); polygon.push_back(polygon.front()); diff --git a/src/ifcgeom/mapping/IfcRectangleHollowProfileDef.cpp b/src/ifcgeom/mapping/IfcRectangleHollowProfileDef.cpp index c5be1981d7..c4b18e398a 100644 --- a/src/ifcgeom/mapping/IfcRectangleHollowProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcRectangleHollowProfileDef.cpp @@ -34,7 +34,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRectangleHollowProfileDef* i const double r1 = fr1 ? (*inst->OuterFilletRadius()) * length_unit_ : 0.; const double r2 = fr2 ? (*inst->InnerFilletRadius()) * length_unit_ : 0.; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcRectangleProfileDef.cpp b/src/ifcgeom/mapping/IfcRectangleProfileDef.cpp index 5418274879..2006596ce9 100644 --- a/src/ifcgeom/mapping/IfcRectangleProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcRectangleProfileDef.cpp @@ -27,7 +27,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRectangleProfileDef* inst) { const double x = inst->XDim() / 2.0f * length_unit_; const double y = inst->YDim() / 2.0f * length_unit_; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcRepresentation.cpp b/src/ifcgeom/mapping/IfcRepresentation.cpp index 198447c2fa..0d87f13e64 100644 --- a/src/ifcgeom/mapping/IfcRepresentation.cpp +++ b/src/ifcgeom/mapping/IfcRepresentation.cpp @@ -22,7 +22,8 @@ using namespace ifcopenshell::geometry; taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRepresentation* inst) { - const bool use_body = !this->settings_.get(IfcGeom::IteratorSettings::INCLUDE_CURVES); + // @todo + const bool use_body = !this->settings_.get().get(); auto items = map_to_collection(this, inst->Items()); if (items == nullptr) { diff --git a/src/ifcgeom/mapping/IfcRoundedRectangleProfileDef.cpp b/src/ifcgeom/mapping/IfcRoundedRectangleProfileDef.cpp index 40a08d14e9..3203c8c751 100644 --- a/src/ifcgeom/mapping/IfcRoundedRectangleProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcRoundedRectangleProfileDef.cpp @@ -28,7 +28,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcRoundedRectangleProfileDef* const double y = inst->YDim() / 2.0f * length_unit_; const double r = inst->RoundingRadius() * length_unit_; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcSweptDiskSolid.cpp b/src/ifcgeom/mapping/IfcSweptDiskSolid.cpp index 67aa117e68..e70cfea746 100644 --- a/src/ifcgeom/mapping/IfcSweptDiskSolid.cpp +++ b/src/ifcgeom/mapping/IfcSweptDiskSolid.cpp @@ -62,7 +62,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcSweptDiskSolid* inst) { ep = inst->EndParam(); #endif - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); #ifdef SCHEMA_HAS_IfcSweptDiskSolidPolygonal if (inst->as()) { diff --git a/src/ifcgeom/mapping/IfcTShapeProfileDef.cpp b/src/ifcgeom/mapping/IfcTShapeProfileDef.cpp index 809441a743..a4d44976ad 100644 --- a/src/ifcgeom/mapping/IfcTShapeProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcTShapeProfileDef.cpp @@ -37,7 +37,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTShapeProfileDef* inst) { const double flangeSlope = hasFlangeSlope ? (*inst->FlangeSlope() * angle_unit_) : 0.; const double webSlope = hasWebSlope ? (*inst->WebSlope() * angle_unit_) : 0.; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol || d1 < tol || d2 < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcTrapeziumProfileDef.cpp b/src/ifcgeom/mapping/IfcTrapeziumProfileDef.cpp index d3d1ac8f06..b9f9ac0549 100644 --- a/src/ifcgeom/mapping/IfcTrapeziumProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcTrapeziumProfileDef.cpp @@ -33,7 +33,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTrapeziumProfileDef* inst) { // The trapezium x center should not be midway of BottomXDim but rather at the center of the overall bounding box. const double x_offset = ((std::min(dx, 0.) + std::max(w + dx, x1 * 2.)) / 2.) - x1; - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x1 < tol || w < tol || y < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcTrimmedCurve.cpp b/src/ifcgeom/mapping/IfcTrimmedCurve.cpp index 22b8c5e4bb..aa1d286ca4 100644 --- a/src/ifcgeom/mapping/IfcTrimmedCurve.cpp +++ b/src/ifcgeom/mapping/IfcTrimmedCurve.cpp @@ -70,7 +70,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { } } - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); trim_cartesian &= has_pnts[0] && has_pnts[1]; bool trim_cartesian_failed = !trim_cartesian; @@ -126,7 +126,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcTrimmedCurve* inst) { } // @todo is 100. not too much? Check with the original issue. - const double precision_markup = conv_settings_.getValue(ConversionSettings::GV_PRECISION_FACTOR) == 1. ? 1. : 100.; + const double precision_markup = settings_.get().get() == 1. ? 1. : 100.; if (isConic && std::fabs(fmod(flts[1] - flts[0], pi * 2.)) < precision_markup * tol / (2 * pi * radius)) { flts[0] = 0.; diff --git a/src/ifcgeom/mapping/IfcUShapeProfileDef.cpp b/src/ifcgeom/mapping/IfcUShapeProfileDef.cpp index c9bb0b3a0c..510a1bf71e 100644 --- a/src/ifcgeom/mapping/IfcUShapeProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcUShapeProfileDef.cpp @@ -51,7 +51,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcUShapeProfileDef* inst) { dy2 = x * tan(slope); } - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol || d1 < tol || d2 < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/IfcZShapeProfileDef.cpp b/src/ifcgeom/mapping/IfcZShapeProfileDef.cpp index e5cb99209e..ab1eed254e 100644 --- a/src/ifcgeom/mapping/IfcZShapeProfileDef.cpp +++ b/src/ifcgeom/mapping/IfcZShapeProfileDef.cpp @@ -42,7 +42,7 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcZShapeProfileDef* inst) { f2 = *inst->EdgeRadius() * length_unit_; } - const double tol = conv_settings_.getValue(ConversionSettings::GV_PRECISION); + const double tol = settings_.get().get(); if (x < tol || y < tol || dx < tol || dy < tol) { Logger::Message(Logger::LOG_NOTICE, "Skipping zero sized profile:", inst); diff --git a/src/ifcgeom/mapping/mapping.cpp b/src/ifcgeom/mapping/mapping.cpp index 2cd9b05730..d33ac0c0db 100644 --- a/src/ifcgeom/mapping/mapping.cpp +++ b/src/ifcgeom/mapping/mapping.cpp @@ -32,7 +32,7 @@ using namespace IfcGeom; namespace { struct POSTFIX_SCHEMA(factory_t) { - abstract_mapping* operator()(IfcParse::IfcFile* file, IteratorSettings& settings) const { + abstract_mapping* operator()(IfcParse::IfcFile* file, Settings& settings) const { ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)* m = new ifcopenshell::geometry::POSTFIX_SCHEMA(mapping)(file, settings); return m; } @@ -114,7 +114,7 @@ namespace { bool mapping::reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) { // With world coords enabled, object transformations are directly applied to // the BRep. There is no way to re-use the geometry for multiple products. - if (settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS)) { + if (settings_.get().get()) { return false; } @@ -127,11 +127,11 @@ bool mapping::reuse_ok_(const IfcSchema::IfcProduct::list::ptr& products) { for (IfcSchema::IfcProduct::list::it it = products->begin(); it != products->end(); ++it) { IfcSchema::IfcProduct* product = *it; - if (!settings_.get(IfcGeom::IteratorSettings::DISABLE_OPENING_SUBTRACTIONS) && find_openings(product)->size()) { + if (!settings_.get().get() && find_openings(product)->size()) { return false; } - if (settings_.get(IfcGeom::IteratorSettings::APPLY_LAYERSETS)) { + if (settings_.get().get()) { IfcSchema::IfcRelAssociates::list::ptr associations = product->HasAssociations(); for (IfcSchema::IfcRelAssociates::list::it jt = associations->begin(); jt != associations->end(); ++jt) { IfcSchema::IfcRelAssociatesMaterial* assoc = (*jt)->as(); @@ -188,7 +188,7 @@ aggregate_of_instance::ptr mapping::find_openings(const IfcUtil::IfcBaseEntity* void mapping::get_representations(std::vector& tasks, std::vector& filters) { IfcSchema::IfcRepresentation::list::ptr representations(new IfcSchema::IfcRepresentation::list); - if (settings_.context_ids().empty()) { + if (!settings_.get().has()) { addRepresentationsFromDefaultContexts(representations); } else { addRepresentationsFromContextIds(representations); @@ -664,8 +664,8 @@ void mapping::initialize_units_() { } void mapping::initialize_settings() { - conv_settings_.setValue(ConversionSettings::GV_LENGTH_UNIT, length_unit_); - conv_settings_.setValue(ConversionSettings::GV_PLANEANGLE_UNIT, angle_unit_); + settings_.get().value = length_unit_; + settings_.get().value = angle_unit_; // Set precision from file double lowest_precision_encountered = std::numeric_limits::infinity(); @@ -679,12 +679,13 @@ void mapping::initialize_settings() { IfcSchema::IfcGeometricRepresentationContext* context = *it; // See if there is a context_id filter and whether the context is selected - if (!settings_.context_ids().empty()) { - if (settings_.context_ids().find(context->data().id()) == settings_.context_ids().end()) { + if (settings_.get().has()) { + auto cids = settings_.get().get(); + if (cids.find(context->data().id()) == cids.end()) { bool selected_sub_context = false; auto subs = context->HasSubContexts(); for (auto& sub : *subs) { - if (settings_.context_ids().find(context->data().id()) != settings_.context_ids().end()) { + if (cids.find(context->data().id()) != cids.end()) { selected_sub_context = true; break; } @@ -695,9 +696,10 @@ void mapping::initialize_settings() { } } - if (context->Precision() && (*context->Precision() * length_unit_ * 10.) < lowest_precision_encountered) { + auto fp = settings_.get().get(); + if (context->Precision() && (*context->Precision() * length_unit_ * fp) < lowest_precision_encountered) { // Some arbitrary factor that has proven to work better for the models in the set of test files. - lowest_precision_encountered = *context->Precision() * length_unit_ * 10.; + lowest_precision_encountered = *context->Precision() * length_unit_ * fp; any_precision_encountered = true; } } @@ -713,7 +715,7 @@ void mapping::initialize_settings() { } } - conv_settings_.setValue(ConversionSettings::GV_PRECISION, precision_to_set); + settings_.get().value = precision_to_set; } bool mapping::get_layerset_information(const IfcUtil::IfcBaseInterface* p, layerset_information& info, int &) @@ -920,7 +922,7 @@ IfcSchema::IfcRepresentation* mapping::find_representation(const IfcSchema::IfcP } void mapping::addRepresentationsFromContextIds(IfcSchema::IfcRepresentation::list::ptr& representations) { - for (auto context_id : settings_.context_ids()) { + for (auto context_id : settings_.get().get()) { IfcSchema::IfcGeometricRepresentationContext* context; try { context = file_->instance_by_id(context_id)->as(); @@ -944,7 +946,7 @@ void mapping::addRepresentationsFromDefaultContexts(IfcSchema::IfcRepresentation allowed_context_types.insert("notdefined"); std::set context_types; - if (!settings_.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) { + if (settings_.get().get()) { // Really this should only be 'Model', as per // the standard 'Design' is deprecated. So, // just for backwards compatibility: @@ -954,7 +956,7 @@ void mapping::addRepresentationsFromDefaultContexts(IfcSchema::IfcRepresentation context_types.insert("model view"); context_types.insert("detail view"); } - if (settings_.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) { + if (settings_.get().get()) { context_types.insert("plan"); } @@ -1020,63 +1022,6 @@ void mapping::addRepresentationsFromDefaultContexts(IfcSchema::IfcRepresentation } } -void mapping::apply_settings() { - conv_settings_.setValue(ConversionSettings::GV_MAX_FACES_TO_ORIENT, settings_.get(IfcGeom::IteratorSettings::SEW_SHELLS) ? std::numeric_limits::infinity() : -1); - conv_settings_.setValue(ConversionSettings::GV_DIMENSIONALITY, (settings_.get(IfcGeom::IteratorSettings::INCLUDE_CURVES) - ? (settings_.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES) ? -1. : 0.) : +1.)); - conv_settings_.setValue(ConversionSettings::GV_LAYERSET_FIRST, - settings_.get(IfcGeom::IteratorSettings::LAYERSET_FIRST) - ? +1.0 - : -1.0 - ); - conv_settings_.setValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_CHECK, - settings_.get(IfcGeom::IteratorSettings::NO_WIRE_INTERSECTION_CHECK) - ? +1.0 - : -1.0 - ); - conv_settings_.setValue(ConversionSettings::GV_NO_WIRE_INTERSECTION_TOLERANCE, - settings_.get(IfcGeom::IteratorSettings::NO_WIRE_INTERSECTION_TOLERANCE) - ? +1.0 - : -1.0 - ); - conv_settings_.setValue(ConversionSettings::GV_PRECISION_FACTOR, - settings_.get(IfcGeom::IteratorSettings::STRICT_TOLERANCE) - ? 1.0 - : 10.0 - ); - - conv_settings_.setValue(ConversionSettings::GV_DISABLE_BOOLEAN_RESULT, - settings_.get(IfcGeom::IteratorSettings::DISABLE_BOOLEAN_RESULT) - ? +1.0 - : -1.0 - ); - - conv_settings_.setValue(ConversionSettings::GV_DEBUG_BOOLEAN, - settings_.get(IfcGeom::IteratorSettings::DEBUG_BOOLEAN) - ? +1.0 - : -1.0 - ); - - conv_settings_.setValue(ConversionSettings::GV_BOOLEAN_ATTEMPT_2D, - settings_.get(IfcGeom::IteratorSettings::BOOLEAN_ATTEMPT_2D) - ? +1.0 - : -1.0 - ); - - if (settings_.get(IfcGeom::IteratorSettings::BUILDING_LOCAL_PLACEMENT)) { - if (settings_.get(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT)) { - Logger::Message(Logger::LOG_WARNING, "building-local-placement takes precedence over site-local-placement"); - } - placement_rel_to_type_ = &IfcSchema::IfcBuilding::Class(); - } else if (settings_.get(IfcGeom::IteratorSettings::SITE_LOCAL_PLACEMENT)) { - placement_rel_to_type_ = &IfcSchema::IfcSite::Class(); - } - - // @todo - // conv_settings_.set_offset(settings_.offset); - // conv_settings_.set_rotation(settings_.rotation); -} - IfcUtil::IfcBaseEntity* mapping::representation_of(const IfcUtil::IfcBaseEntity* product) { // @todo correct, but very inefficient IfcSchema::IfcRepresentation::list::ptr representations(new IfcSchema::IfcRepresentation::list); @@ -1084,7 +1029,7 @@ IfcUtil::IfcBaseEntity* mapping::representation_of(const IfcUtil::IfcBaseEntity* IfcSchema::IfcRepresentation::list::ptr intersection(new IfcSchema::IfcRepresentation::list); IfcSchema::IfcRepresentation::list::ptr intersection_no_box(new IfcSchema::IfcRepresentation::list); - if (settings_.context_ids().empty()) { + if (!settings_.get().has()) { addRepresentationsFromDefaultContexts(representations); } else { addRepresentationsFromContextIds(representations); @@ -1100,7 +1045,7 @@ IfcUtil::IfcBaseEntity* mapping::representation_of(const IfcUtil::IfcBaseEntity* } } - if (intersection->size() == 0 && settings_.context_ids().empty() && settings_.get(IfcGeom::IteratorSettings::INCLUDE_CURVES) && settings_.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) { + if (intersection->size() == 0 && settings_.get().has() && settings_.get().get() && !settings_.get().get()) { for (auto& r : *of_product) { if (r->RepresentationIdentifier() && *r->RepresentationIdentifier() == "Axis") { intersection->push(r); diff --git a/src/ifcgeom/mapping/mapping.h b/src/ifcgeom/mapping/mapping.h index fa825788fc..bae4404287 100644 --- a/src/ifcgeom/mapping/mapping.h +++ b/src/ifcgeom/mapping/mapping.h @@ -31,9 +31,8 @@ namespace geometry { void addRepresentationsFromContextIds(IfcSchema::IfcRepresentation::list::ptr&); void addRepresentationsFromDefaultContexts(IfcSchema::IfcRepresentation::list::ptr&); public: - POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file, IfcGeom::IteratorSettings& settings) : abstract_mapping(settings), file_(file), placement_rel_to_type_(0), placement_rel_to_instance_(0) { + POSTFIX_SCHEMA(mapping)(IfcParse::IfcFile* file, Settings& settings) : abstract_mapping(settings), file_(file), placement_rel_to_type_(0), placement_rel_to_instance_(0) { initialize_units_(); - apply_settings(); } virtual ifcopenshell::geometry::taxonomy::ptr map(const IfcUtil::IfcBaseInterface*); virtual void get_representations(std::vector& tasks, std::vector& filters); @@ -42,8 +41,6 @@ namespace geometry { virtual double get_length_unit() const { return length_unit_; } virtual aggregate_of_instance::ptr find_openings(const IfcUtil::IfcBaseEntity*); virtual IfcUtil::IfcBaseEntity* representation_of(const IfcUtil::IfcBaseEntity* product); - - void apply_settings(); virtual const IfcUtil::IfcBaseEntity* get_single_material_association(const IfcUtil::IfcBaseEntity* product); IfcSchema::IfcRepresentation* representation_mapped_to(const IfcSchema::IfcRepresentation* representation); diff --git a/src/ifcgeomserver/IfcGeomServer.cpp b/src/ifcgeomserver/IfcGeomServer.cpp index 753fe3146d..b51166bcbe 100644 --- a/src/ifcgeomserver/IfcGeomServer.cpp +++ b/src/ifcgeomserver/IfcGeomServer.cpp @@ -583,23 +583,26 @@ int main () { char* data = new char[len]; memcpy(data, m.string().c_str(), len); - IfcGeom::IteratorSettings settings; - settings.set(IfcGeom::IteratorSettings::USE_WORLD_COORDS, false); - settings.set(IfcGeom::IteratorSettings::WELD_VERTICES, false); - settings.set(IfcGeom::IteratorSettings::CONVERT_BACK_UNITS, true); + ifcopenshell::geometry::Settings settings; + settings.get().value = false; + settings.get().value = false; + settings.get().value = true; // settings.set(IfcGeom::IteratorSettings::INCLUDE_CURVES, true); + /* + // @todo std::vector< std::pair >::const_iterator it = setting_pairs.begin(); for (; it != setting_pairs.end(); ++it) { - settings.set(it->first, it->second != 0); + settings.get(it->first, it->second != 0); if (it->first == IfcGeom::IteratorSettings::SEW_SHELLS && it->second) { // Quantities (especially volume) can be emitted if there are proper // topologically valid geometries being created. emit_quantities = true; } } + */ - settings.set_deflection_tolerance(deflection); + settings.get().value = deflection; file = new IfcParse::IfcFile(data, (int)len); iterator = new IfcGeom::Iterator(settings, file); diff --git a/src/ifcopenshell-python/ifcopenshell/geom/main.py b/src/ifcopenshell-python/ifcopenshell/geom/main.py index 4fe6dfe210..551f331972 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/main.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/main.py @@ -50,28 +50,59 @@ if has_occ: else: return shape +class missing_setting: + def __repr__(self): return '-' -# Subclass the settings module to provide an additional -# setting to enable pythonOCC when available +class settings_mixin: + """ + Pythonic interface mixin to the settings modules and + to provide an additional setting to enable pythonOCC + when available + """ + + def __init__(self, **kwargs): + super(settings_mixin, self).__init__() + for k, v in kwargs.items(): + self.set(getattr(self, k), v) -# nb: we just subclass serializer settings, so in python -# we do not differentiate between the two setting types + def __repr__(self): + def safe_get(x): + try: return self.get_(x) + except: return missing_setting() + fmt_pair = lambda x: "%s = %r" % (self.rname(x), safe_get(x)) + return "%s(%s)" % ( + type(self).__name__, + ", ".join(map(fmt_pair, self.setting_names())) + ) + + @staticmethod + def name(k): + return k.lower().replace('_', '-') + + @staticmethod + def rname(k): + return k.upper().replace('-', '_') + + def set(self, k, v): + if k == "USE_PYTHON_OPENCASCADE": + if not has_occ: + raise ArgumentError("Python OpenCASCADE is not installed") + if v: + self.set_("iterator-output", ifcopenshell_wrapper.SERIALIZED) + self.set_("use-world-coords", True) + self.use_python_opencascade = True + else: + self.set_(self.name(k), v) + + def get(self, k): + return self.get_(self.name(k)) -class settings(ifcopenshell_wrapper.SerializerSettings): - if has_occ: - USE_PYTHON_OPENCASCADE = -1 - - def set(self, *args): - setting, value = args - if setting == settings.USE_PYTHON_OPENCASCADE: - self.set(settings.USE_BREP_DATA, value) - self.set(settings.USE_WORLD_COORDS, value) - self.set(settings.DISABLE_TRIANGULATION, value) - self.use_python_opencascade = value - else: - ifcopenshell_wrapper.SerializerSettings.set(self, *args) +class serializer_settings(settings_mixin, ifcopenshell_wrapper.SerializerSettings): + pass +class settings(settings_mixin, ifcopenshell_wrapper.Settings): + pass # Make sure people are able to use python's platform agnostic paths class iterator(ifcopenshell_wrapper.Iterator): diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 466a03ba54..d25eda18da 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -30,7 +30,7 @@ } // SWIG does not support bool references in a meaningful way, so the -// IfcGeom::IteratorSettings functions degrade to return a read only value +// ifcopenshell::geometry::Settings functions degrade to return a read only value %typemap(out) double& { $result = SWIG_From_double(*$1); } @@ -62,6 +62,7 @@ %include "../ifcgeom/Converter.h" %include "../ifcgeom/ConversionResult.h" %include "../ifcgeom/IteratorSettings.h" +%include "../ifcgeom/ConversionSettings.h" %include "../ifcgeom/IfcGeomElement.h" %include "../ifcgeom/IfcGeomRepresentation.h" %include "../ifcgeom/Iterator.h" @@ -74,6 +75,55 @@ %include "../serializers/XmlSerializer.h" %include "../serializers/GltfSerializer.h" + +%extend ifcopenshell::geometry::Settings { + void set_(const std::string& name, bool val) { + return $self->set(name, val); + } + void set_(const std::string& name, int val) { + return $self->set(name, val); + } + void set_(const std::string& name, double val) { + return $self->set(name, val); + } + void set_(const std::string& name, const std::string& val) { + return $self->set(name, val); + } + void set_(const std::string& name, const std::set& val) { + return $self->set(name, val); + } + boost::variant> get_(const std::string& name) { + return $self->get(name); + } + std::vector setting_names() { + return $self->setting_names(); + } +} + +%extend ifcopenshell::geometry::SerializerSettings { + void set_(const std::string& name, bool val) { + return $self->set(name, val); + } + void set_(const std::string& name, int val) { + return $self->set(name, val); + } + void set_(const std::string& name, double val) { + return $self->set(name, val); + } + void set_(const std::string& name, const std::string& val) { + return $self->set(name, val); + } + void set_(const std::string& name, const std::set& val) { + return $self->set(name, val); + } + boost::variant> get_(const std::string& name) { + return $self->get(name); + } + std::vector setting_names() { + return $self->setting_names(); + } +} + #ifdef IFOPSH_WITH_OPENCASCADE %template(ray_intersection_results) std::vector; @@ -184,33 +234,6 @@ struct ShapeRTTI : public boost::static_visitor $result = boost::apply_visitor(ShapeRTTI(), $1); } -%extend SerializerSettings { - %pythoncode %{ - - old_init = __init__ - - def __init__(self, **kwargs): - self.old_init() - for k, v in kwargs.items(): - self.set(getattr(self, k), v) - - def __repr__(self): - def d(): - import numbers - for x in dir(self): - if x.isupper() and x not in {"NUM_SETTINGS", "USE_PYTHON_OPENCASCADE", "DEFAULT_PRECISION"}: - v = getattr(self, x) - if isinstance(v, numbers.Integral): - yield x - - return "%s(%s)" % ( - type(self).__name__, - (", ".join(map(lambda x: "%s = %r" % (x, self.get(getattr(self, x))), d()))) - ) - - %} -} - %newobject construct_iterator_with_include_exclude; %newobject construct_iterator_with_include_exclude_globalid; %newobject construct_iterator_with_include_exclude_id; @@ -218,13 +241,13 @@ struct ShapeRTTI : public boost::static_visitor // I couldn't get the vector typemap to be applied when %extending Iterator constructor. // anyway it does not matter as SWIG generates C code without actual constructors %inline %{ - IfcGeom::Iterator* construct_iterator_with_include_exclude(const std::string& geometry_library, IfcGeom::IteratorSettings settings, IfcParse::IfcFile* file, std::vector elems, bool include, int num_threads) { + IfcGeom::Iterator* construct_iterator_with_include_exclude(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, IfcParse::IfcFile* file, std::vector elems, bool include, int num_threads) { std::set elems_set(elems.begin(), elems.end()); IfcGeom::entity_filter ef{ include, false, elems_set }; return new IfcGeom::Iterator(geometry_library, settings, file, {ef}, num_threads); } - IfcGeom::Iterator* construct_iterator_with_include_exclude_globalid(const std::string& geometry_library, IfcGeom::IteratorSettings settings, IfcParse::IfcFile* file, std::vector elems, bool include, int num_threads) { + IfcGeom::Iterator* construct_iterator_with_include_exclude_globalid(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, IfcParse::IfcFile* file, std::vector elems, bool include, int num_threads) { std::set elems_set(elems.begin(), elems.end()); IfcGeom::attribute_filter af; af.attribute_name = "GlobalId"; @@ -233,7 +256,7 @@ struct ShapeRTTI : public boost::static_visitor return new IfcGeom::Iterator(geometry_library, settings, file, {af}, num_threads); } - IfcGeom::Iterator* construct_iterator_with_include_exclude_id(const std::string& geometry_library, IfcGeom::IteratorSettings settings, IfcParse::IfcFile* file, std::vector elems, bool include, int num_threads) { + IfcGeom::Iterator* construct_iterator_with_include_exclude_id(const std::string& geometry_library, ifcopenshell::geometry::Settings settings, IfcParse::IfcFile* file, std::vector elems, bool include, int num_threads) { std::set elems_set(elems.begin(), elems.end()); IfcGeom::instance_id_filter af(include, false, elems_set); return new IfcGeom::Iterator(geometry_library, settings, file, {af}, num_threads); @@ -374,7 +397,7 @@ struct ShapeRTTI : public boost::static_visitor } template - static boost::variant helper_fn_create_shape(const std::string& geometry_library, IfcGeom::IteratorSettings& settings, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0) { + static boost::variant helper_fn_create_shape(const std::string& geometry_library, ifcopenshell::geometry::Settings& settings, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0) { IfcParse::IfcFile* file = instance->data().file; ifcopenshell::geometry::Converter kernel(geometry_library, file, settings); @@ -403,13 +426,13 @@ struct ShapeRTTI : public boost::static_visitor if (!rep->RepresentationIdentifier()) { continue; } - if (!settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) { + if (settings.get().get()) { if (*rep->RepresentationIdentifier() == "Body") { ifc_representation = rep; break; } } - if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) { + if (settings.get().get()) { if (*rep->RepresentationIdentifier() == "Plan" || *rep->RepresentationIdentifier() == "Axis") { ifc_representation = rep; break; @@ -427,13 +450,13 @@ struct ShapeRTTI : public boost::static_visitor // TODO: Remove redundancy with IfcGeomIterator.h if (context->ContextType()) { std::set context_types; - if (!settings.get(IfcGeom::IteratorSettings::EXCLUDE_SOLIDS_AND_SURFACES)) { + if (settings.get().get()) { context_types.insert("model"); context_types.insert("design"); context_types.insert("model view"); context_types.insert("detail view"); } - if (settings.get(IfcGeom::IteratorSettings::INCLUDE_CURVES)) { + if (settings.get().get()) { context_types.insert("plan"); } @@ -461,11 +484,11 @@ struct ShapeRTTI : public boost::static_visitor if (!brep) { throw IfcParse::IfcException("Failed to process shape"); } - if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) { + if (settings.get().get() == ifcopenshell::geometry::settings::SERIALIZED) { IfcGeom::SerializedElement* serialization = new IfcGeom::SerializedElement(*brep); delete brep; return serialization; - } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { + } else if (settings.get().get() == ifcopenshell::geometry::settings::TRIANGULATED) { IfcGeom::TriangulationElement* triangulation = new IfcGeom::TriangulationElement(*brep); delete brep; return triangulation; @@ -481,12 +504,11 @@ struct ShapeRTTI : public boost::static_visitor ) { IfcGeom::ConversionResults shapes = kernel.convert(instance); - IfcGeom::ElementSettings element_settings(settings, kernel.mapping()->get_length_unit(), instance->declaration().name()); - IfcGeom::Representation::BRep brep(element_settings, to_locale_invariant_string(instance->data().id()), shapes); + IfcGeom::Representation::BRep brep(settings, instance->declaration().name(), to_locale_invariant_string(instance->data().id()), shapes); try { - if (settings.get(IfcGeom::IteratorSettings::USE_BREP_DATA)) { + if (settings.get().get() == ifcopenshell::geometry::settings::SERIALIZED) { return new IfcGeom::Representation::Serialization(brep); - } else if (!settings.get(IfcGeom::IteratorSettings::DISABLE_TRIANGULATION)) { + } else if (settings.get().get() == ifcopenshell::geometry::settings::TRIANGULATED) { return new IfcGeom::Representation::Triangulation(brep); } } catch (...) { @@ -502,7 +524,7 @@ struct ShapeRTTI : public boost::static_visitor %} %inline %{ - static boost::variant create_shape(IfcGeom::IteratorSettings& settings, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0, const char* const geometry_library="opencascade") { + static boost::variant create_shape(ifcopenshell::geometry::Settings& settings, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0, const char* const geometry_library="opencascade") { const std::string& schema_name = instance->declaration().schema()->name(); #ifdef HAS_SCHEMA_2x3 diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index 0ab31e71c0..c5abadb467 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -56,6 +56,7 @@ %shared_ptr(IfcGeom::OpaqueNumber); %ignore IfcGeom::NumberNativeDouble; +%ignore ifcopenshell::geometry::Converter; // General python-specific rename rules for comparison operators. // Mostly to silence warnings, but might be of use some time. @@ -134,6 +135,7 @@ #include "../ifcparse/IfcSchema.h" #include "../ifcparse/utils.h" + #include "../ifcgeom/ConversionSettings.h" #include "../ifcgeom/ConversionResult.h" #include "../svgfill/src/svgfill.h" @@ -204,6 +206,9 @@ #include "../ifcparse/IfcFile.h" #include "../ifcparse/IfcSchema.h" #include "../ifcparse/utils.h" + + #include "../ifcgeom/ConversionSettings.h" + #include "../ifcgeom/ConversionResult.h" #include "../svgfill/src/svgfill.h" %} diff --git a/src/ifcwrap/utils/type_conversion.i b/src/ifcwrap/utils/type_conversion.i index 3ecd6c6660..b2b1ad8256 100644 --- a/src/ifcwrap/utils/type_conversion.i +++ b/src/ifcwrap/utils/type_conversion.i @@ -185,4 +185,20 @@ } return pyobj; } + + struct pythonizing_visitor { + typedef PyObject* result_type; + + template + PyObject* operator()(const T& t) { + return pythonize(t); + } + + template <> + PyObject* operator()(const std::set& t) { + std::vector vs(t.begin(), t.end()); + return pythonize_vector(vs); + } + }; + %} diff --git a/src/ifcwrap/utils/typemaps_out.i b/src/ifcwrap/utils/typemaps_out.i index e8ea58f2b0..bdeea95e55 100644 --- a/src/ifcwrap/utils/typemaps_out.i +++ b/src/ifcwrap/utils/typemaps_out.i @@ -147,3 +147,8 @@ CREATE_VECTOR_TYPEMAP_OUT(IfcParse::inverse_attribute const *) CREATE_VECTOR_TYPEMAP_OUT(IfcParse::entity const *) CREATE_VECTOR_TYPEMAP_OUT(IfcParse::declaration const *) CREATE_VECTOR_TYPEMAP_OUT(IfcGeom::ConversionResultShape *) + +%typemap(out) boost::variant> { + pythonizing_visitor vis; + $result = $1.apply_visitor(vis); +} diff --git a/src/serializers/ColladaSerializer.cpp b/src/serializers/ColladaSerializer.cpp index d43243e53a..65c8bbcb3b 100644 --- a/src/serializers/ColladaSerializer.cpp +++ b/src/serializers/ColladaSerializer.cpp @@ -409,7 +409,7 @@ void ColladaSerializer::ColladaExporter::write(const IfcGeom::TriangulationEleme DeferredObject deferred(name, representation_id, o->type(), o->transformation(), mesh.verts(), mesh.normals(), mesh.faces(), mesh.edges(), mesh.material_ids(), mesh.materials(), material_references, mesh.uvs()); - if (serializer->settings().get(SerializerSettings::USE_ELEMENT_HIERARCHY)) { + if (serializer->geometry_settings().get().get()) { deferred.parents() = o->parents(); } @@ -451,7 +451,7 @@ std::string ColladaSerializer::differentiateSlabTypes(const IfcUtil::IfcBaseEnti std::string ColladaSerializer::object_id(const IfcGeom::Element* o) /*override*/ { - if (settings_.get(SerializerSettings::USE_ELEMENT_TYPES)) { + if (settings_.get().get()) { const std::string slabSuffix = (o->product() && o->product()->declaration().name() == "IfcSlab") ? differentiateSlabTypes(o->product()) : ""; @@ -464,7 +464,7 @@ void ColladaSerializer::ColladaExporter::endDocument() { // In fact due the XML based nature of Collada and its dependency on library nodes, // only at this point all objects are written to the stream. materials.write(); - bool use_hierarchy = serializer->settings().get(SerializerSettings::USE_ELEMENT_HIERARCHY); + bool use_hierarchy = serializer->geometry_settings().get().get(); std::set geometries_written; diff --git a/src/serializers/ColladaSerializer.h b/src/serializers/ColladaSerializer.h index 27fe8c91ac..58dc4de4fa 100644 --- a/src/serializers/ColladaSerializer.h +++ b/src/serializers/ColladaSerializer.h @@ -219,9 +219,9 @@ private: std::string unit_name; float unit_magnitude; public: - ColladaSerializer(const std::string& dae_filename, const SerializerSettings& settings) - : WriteOnlyGeometrySerializer(settings) - , exporter("IfcOpenShell", dae_filename, this, settings.precision >= 15) + ColladaSerializer(const std::string& dae_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : WriteOnlyGeometrySerializer(geometry_settings, settings) + , exporter("IfcOpenShell", dae_filename, this, settings.get().get() >= 15) { exporter.serializer = this; exporter.materials.serializer = this; diff --git a/src/serializers/GltfSerializer.cpp b/src/serializers/GltfSerializer.cpp index 9eee5de0be..ef8c8c92f1 100644 --- a/src/serializers/GltfSerializer.cpp +++ b/src/serializers/GltfSerializer.cpp @@ -44,8 +44,8 @@ static const uint32_t PRIM_TRIANGLES = 4; static const uint32_t PRIM_TRIANGLE_STRIP = 5; static const uint32_t PRIM_TRIANGLE_FAN = 6; -GltfSerializer::GltfSerializer(const std::string& filename, const SerializerSettings& settings) - : WriteOnlyGeometrySerializer(settings) +GltfSerializer::GltfSerializer(const std::string& filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : WriteOnlyGeometrySerializer(geometry_settings, settings) , filename_(filename) , tmp_filename1_(filename + ".indices.tmp") , tmp_filename2_(filename + ".vertices.tmp") diff --git a/src/serializers/GltfSerializer.h b/src/serializers/GltfSerializer.h index b977af344b..2c8d2da876 100644 --- a/src/serializers/GltfSerializer.h +++ b/src/serializers/GltfSerializer.h @@ -39,7 +39,7 @@ private: int writeMaterial(const ifcopenshell::geometry::taxonomy::style& style); public: - GltfSerializer(const std::string& filename, const SerializerSettings& settings); + GltfSerializer(const std::string& filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings); virtual ~GltfSerializer(); bool ready(); void writeHeader(); diff --git a/src/serializers/HdfSerializer.cpp b/src/serializers/HdfSerializer.cpp index e0b40ed4bf..4bcdfb4b5e 100644 --- a/src/serializers/HdfSerializer.cpp +++ b/src/serializers/HdfSerializer.cpp @@ -53,8 +53,8 @@ herr_t print_stack(hid_t /*estack*/, void*) { return 0; } -HdfSerializer::HdfSerializer(const std::string& hdf_filename, const SerializerSettings& settings, bool read_only) - : GeometrySerializer(settings) +HdfSerializer::HdfSerializer(const std::string& hdf_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings, bool read_only) + : GeometrySerializer(geometry_settings, settings) , hdf_filename(hdf_filename) , settings_(settings) { @@ -284,7 +284,6 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g auto representation_group = element_group.openGroup(representation_id_str); std::string geom_id = read_scalar_attribute(representation_group, "geom_id"); - IfcGeom::ElementSettings element_settings(settings_, f.getUnit("LENGTHUNIT").second, type); auto inst = f.instance_by_id(id)->as(); boost::shared_ptr brep_geometry; @@ -305,6 +304,9 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g if (rt == READ_BREP && !brep_geometry) { auto brepDataset = representation_group.openDataSet(DATASET_NAME_OCCT); + /* + // @todo + static const auto ignored_settings = // Settings that do not affect storage of brep data IfcGeom::IteratorSettings::DISABLE_TRIANGULATION | IfcGeom::IteratorSettings::USE_BREP_DATA | @@ -325,6 +327,7 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g if (stored_settings != requested_settings && (stored_settings | IfcGeom::IteratorSettings::USE_WORLD_COORDS) != requested_settings) { throw std::runtime_error("Settings mismatch"); } + */ std::vector parts; { @@ -357,6 +360,9 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g shapes.push_back(IfcGeom::ConversionResult(part.id, matrix, new ifcopenshell::geometry::OpenCascadeShape(shp), style_ptr)); } + /* + // @todo + // World coordinates can be applied post-hoc if (settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS) && !(stored_settings & IfcGeom::IteratorSettings::USE_WORLD_COORDS)) { for (IfcGeom::ConversionResults::iterator it = shapes.begin(); it != shapes.end(); ++it) { @@ -364,13 +370,16 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g } trsf = ifcopenshell::geometry::taxonomy::make(); } + */ - brep_geometry = boost::shared_ptr(new IfcGeom::Representation::BRep(element_settings, geom_id, shapes)); - + brep_geometry = boost::shared_ptr(new IfcGeom::Representation::BRep(geometry_settings(), type, geom_id, shapes)); + /* + // @todo if (!settings_.get(IfcGeom::IteratorSettings::USE_WORLD_COORDS)) { brep_cache_.insert({ representation_id_str, brep_geometry }); } + */ } if (rt == READ_TRIANGULATION && !triangulation_geometry) { @@ -413,7 +422,8 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g } triangulation_geometry = boost::shared_ptr(new IfcGeom::Representation::Triangulation( - element_settings, + geometry_settings_, + type, geom_id, verts, faces, @@ -432,7 +442,7 @@ IfcGeom::Element* HdfSerializer::read(IfcParse::IfcFile& f, const std::string& g } else { return new IfcGeom::TriangulationElement( IfcGeom::Element( - element_settings, + geometry_settings_, id, parent_id, name, @@ -619,7 +629,11 @@ void HdfSerializer::write(const IfcGeom::BRepElement* o) { H5::DataSpace attrdspace(H5S_SCALAR); H5::Attribute att = brepDataset.createAttribute("settings", H5::PredType::NATIVE_UINT64, attrdspace); + /* + // @todo uint64_t value = o->geometry().settings().get_raw(); + */ + uint64_t value = 0; att.write(H5::PredType::NATIVE_UINT64, &value); } diff --git a/src/serializers/HdfSerializer.h b/src/serializers/HdfSerializer.h index 0b9510bb44..d6fdcffe87 100644 --- a/src/serializers/HdfSerializer.h +++ b/src/serializers/HdfSerializer.h @@ -38,7 +38,7 @@ private: const std::string hdf_filename; unsigned int vcount_total; H5::H5File file; - SerializerSettings settings_; + ifcopenshell::geometry::SerializerSettings settings_; static const H5std_string DATASET_NAME_POSITIONS; static const H5std_string DATASET_NAME_UVCOORDS; @@ -92,7 +92,7 @@ private: void write_style(surface_style_serialization& data, const ifcopenshell::geometry::taxonomy::style& s); public: - HdfSerializer(const std::string& hdf_filename, const SerializerSettings& settings, bool read_only=false); + HdfSerializer(const std::string& hdf_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings, bool read_only=false); virtual ~HdfSerializer() {} bool ready(); void writeHeader(); diff --git a/src/serializers/IgesSerializer.h b/src/serializers/IgesSerializer.h index 365189add3..cdfe7f79cd 100644 --- a/src/serializers/IgesSerializer.h +++ b/src/serializers/IgesSerializer.h @@ -40,8 +40,8 @@ private: public: /// @note IGESControl_Controller::Init() must be called prior to instantiating IgesSerializer. /// See http://tracker.dev.opencascade.org/view.php?id=23679 for more information. - IgesSerializer(const std::string& out_filename, const SerializerSettings& settings) - : OpenCascadeBasedSerializer(out_filename, settings) + IgesSerializer(const std::string& out_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : OpenCascadeBasedSerializer(out_filename, geometry_settings, settings) {} virtual ~IgesSerializer() {} void writeShape(const std::string&, const TopoDS_Shape& shape) { diff --git a/src/serializers/OpenCascadeBasedSerializer.h b/src/serializers/OpenCascadeBasedSerializer.h index 67982fa3cc..44b252b27c 100644 --- a/src/serializers/OpenCascadeBasedSerializer.h +++ b/src/serializers/OpenCascadeBasedSerializer.h @@ -36,8 +36,8 @@ protected: const std::string out_filename; const char* getSymbolForUnitMagnitude(float mag); public: - explicit OpenCascadeBasedSerializer(const std::string& out_filename, const SerializerSettings& settings) - : WriteOnlyGeometrySerializer(settings) + explicit OpenCascadeBasedSerializer(const std::string& out_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : WriteOnlyGeometrySerializer(geometry_settings, settings) , out_filename(out_filename) {} virtual ~OpenCascadeBasedSerializer() {} diff --git a/src/serializers/StepSerializer.h b/src/serializers/StepSerializer.h index 5a4ade0335..19144a35cc 100644 --- a/src/serializers/StepSerializer.h +++ b/src/serializers/StepSerializer.h @@ -34,8 +34,8 @@ class StepSerializer : public OpenCascadeBasedSerializer private: STEPControl_Writer writer; public: - explicit StepSerializer(const std::string& out_filename, const SerializerSettings& settings) - : OpenCascadeBasedSerializer(out_filename, settings) + explicit StepSerializer(const std::string& out_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& serializer_settings) + : OpenCascadeBasedSerializer(out_filename, geometry_settings, serializer_settings) {} virtual ~StepSerializer() {} void writeShape(const std::string& name, const TopoDS_Shape& shape) { diff --git a/src/serializers/SvgSerializer.cpp b/src/serializers/SvgSerializer.cpp index 71e1c93593..3fc5b58ea0 100644 --- a/src/serializers/SvgSerializer.cpp +++ b/src/serializers/SvgSerializer.cpp @@ -311,7 +311,7 @@ void SvgSerializer::write(path_object& p, const TopoDS_Shape& comp_or_wire, boos ycoords.push_back(path.add(p2.Y())); } else if (ty != STANDARD_TYPE(Geom_Line)) { BRepAdaptor_Curve crv(edge); - GCPnts_QuasiUniformDeflection tessellater(crv, settings().deflection_tolerance()); + GCPnts_QuasiUniformDeflection tessellater(crv, geometry_settings().get().get()); // NB: Start at 2: 1-based and skip the first point, assume it coincides with p1. for (int i = 2; i <= tessellater.NbPoints(); ++i) { gp_Pnt pi = tessellater.Value(i); @@ -379,9 +379,8 @@ namespace { for (const auto& p : o->parents()) { if (p->type() == "IfcBuildingStorey") { try { - const IfcGeom::ElementSettings& settings = o->geometry().settings(); double e = *p->product()->get("Elevation"); - double storey_elevation = e * settings.unit_magnitude(); + double storey_elevation = e * o->geometry().settings().get().get(); return std::make_pair(p->product(), storey_elevation); } catch (...) { continue; @@ -1883,7 +1882,7 @@ void SvgSerializer::addTextAnnotations(const drawing_key& k) { auto desc = (std::string) *ds; if (object_type == "Text") { - auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, settings_); + auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, geometry_settings_); auto item = mapping->map(*pl); auto matrix = ifcopenshell::geometry::taxonomy::cast(item); delete mapping; @@ -2307,11 +2306,11 @@ std::string SvgSerializer::nameElement(const IfcUtil::IfcBaseEntity* storey, con std::string SvgSerializer::idElement(const IfcUtil::IfcBaseEntity* elem) { const std::string type = elem->declaration().is("IfcBuildingStorey") ? "storey" : "product"; const std::string name = - (settings().get(SerializerSettings::USE_ELEMENT_GUIDS) + (settings().get().get() ? static_cast(*elem->get("GlobalId")) - : ((settings().get(SerializerSettings::USE_ELEMENT_NAMES) && !elem->get("Name")->isNull())) + : ((settings().get().get() && !elem->get("Name")->isNull())) ? static_cast(*elem->get("Name")) - : (settings().get(SerializerSettings::USE_ELEMENT_STEPIDS)) + : (settings().get().get()) ? ("id-" + boost::lexical_cast(elem->data().id())) : IfcParse::IfcGlobalId(*elem->get("GlobalId")).formatted()); return type + "-" + name; @@ -2340,7 +2339,7 @@ void SvgSerializer::setFile(IfcParse::IfcFile* f) { auto storeys = f->instances_by_type("IfcBuildingStorey"); if (!storeys || storeys->size() == 0) { - auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, settings_); + auto mapping = ifcopenshell::geometry::impl::mapping_implementations().construct(file, geometry_settings_); std::vector to_derive_from; to_derive_from.push_back(f->schema()->declaration_by_name("IfcBuilding")); diff --git a/src/serializers/SvgSerializer.h b/src/serializers/SvgSerializer.h index 81a1cb7315..577d5ef0db 100644 --- a/src/serializers/SvgSerializer.h +++ b/src/serializers/SvgSerializer.h @@ -196,8 +196,8 @@ protected: subtract_before_project subtraction_settings_; public: - SvgSerializer(const stream_or_filename& out_filename, const SerializerSettings& settings) - : WriteOnlyGeometrySerializer(settings) + SvgSerializer(const stream_or_filename& out_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : WriteOnlyGeometrySerializer(geometry_settings, settings) , svg_file(out_filename) , xmin(+std::numeric_limits::infinity()) , ymin(+std::numeric_limits::infinity()) diff --git a/src/serializers/WavefrontObjSerializer.cpp b/src/serializers/WavefrontObjSerializer.cpp index 5896b32e68..8e25ddb89d 100644 --- a/src/serializers/WavefrontObjSerializer.cpp +++ b/src/serializers/WavefrontObjSerializer.cpp @@ -27,14 +27,14 @@ #include #include -WaveFrontOBJSerializer::WaveFrontOBJSerializer(const stream_or_filename& obj_filename, const stream_or_filename& mtl_filename, const SerializerSettings& settings) - : WriteOnlyGeometrySerializer(settings) +WaveFrontOBJSerializer::WaveFrontOBJSerializer(const stream_or_filename& obj_filename, const stream_or_filename& mtl_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) + : WriteOnlyGeometrySerializer(geometry_settings, settings) , obj_stream(obj_filename) , mtl_stream(mtl_filename) , vcount_total(1) { - obj_stream.stream << std::setprecision(settings.precision); - mtl_stream.stream << std::setprecision(settings.precision); + obj_stream.stream << std::setprecision(settings.get().get()); + mtl_stream.stream << std::setprecision(settings.get().get()); } bool WaveFrontOBJSerializer::ready() { @@ -91,7 +91,7 @@ void WaveFrontOBJSerializer::write(const IfcGeom::TriangulationElement* o) { obj_stream.stream << "g " << object_id(o) << "\n"; obj_stream.stream << "s 1" << "\n"; - const bool isyup = settings().get(SerializerSettings::USE_Y_UP); + const bool isyup = settings().get().get(); const IfcGeom::Representation::Triangulation& mesh = o->geometry(); diff --git a/src/serializers/WavefrontObjSerializer.h b/src/serializers/WavefrontObjSerializer.h index e99ad6349a..d732a231ce 100644 --- a/src/serializers/WavefrontObjSerializer.h +++ b/src/serializers/WavefrontObjSerializer.h @@ -35,7 +35,7 @@ private: unsigned int vcount_total; std::set materials; public: - WaveFrontOBJSerializer(const stream_or_filename& obj_filename, const stream_or_filename& mtl_filename, const SerializerSettings& settings); + WaveFrontOBJSerializer(const stream_or_filename& obj_filename, const stream_or_filename& mtl_filename, const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings); virtual ~WaveFrontOBJSerializer() {} bool ready(); void writeHeader(); diff --git a/src/serializers/schema_dependent/XmlSerializer.h b/src/serializers/schema_dependent/XmlSerializer.h index 48a8b3ff5b..a404c45cb7 100644 --- a/src/serializers/schema_dependent/XmlSerializer.h +++ b/src/serializers/schema_dependent/XmlSerializer.h @@ -35,7 +35,7 @@ private: IfcParse::IfcFile* file; // @todo - IfcGeom::IteratorSettings settings_; + ifcopenshell::geometry::Settings settings_; ifcopenshell::geometry::abstract_mapping* mapping_; public: