#ifndef CONVERSIONSETTINGS_H #define CONVERSIONSETTINGS_H #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 { #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."; }; struct CircleSegments : public SettingBase { static constexpr const char* const name = "circle-segments"; static constexpr const char* const description = "Number of segments to approximate full circles in CGAL kernel."; static constexpr int defaultvalue = 16; }; enum PiecewiseStepMethod { MAXSTEPSIZE, MINSTEPS }; std::istream& operator>>(std::istream& in, PiecewiseStepMethod& ioo); struct PiecewiseStepType : public SettingBase { static constexpr const char* const name = "piecewise-step-type"; static constexpr const char* const description = "Indicates the method used for defining step size when evaluating piecewise curves. Provides interpretation of piecewise-step-param"; static constexpr PiecewiseStepMethod defaultvalue = MAXSTEPSIZE; }; struct PiecewiseStepParam : public SettingBase { static constexpr const char* const name = "piecewise-step-param"; static constexpr const char* const description = "Indicates the parameter value for defining step size when evaluating piecewise curves."; static constexpr double defaultvalue = 0.5; // ceiling of this value is used when PiecewiseStepMethod is MinSteps }; } template class IFC_GEOM_API SettingsContainer { public: typedef boost::variant, IteratorOutputOptions, PiecewiseStepMethod> value_variant_t; private: 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 { class IFC_GEOM_API geometry_exception : public std::exception { protected: std::string message; public: geometry_exception(const std::string& m) : message(m) {} virtual ~geometry_exception() throw () {} virtual const char* what() const throw() { return message.c_str(); } }; class IFC_GEOM_API too_many_faces_exception : public geometry_exception { public: too_many_faces_exception() : geometry_exception("Too many faces for operation") {} }; } #endif