From ce91d296b6e98b2424a30facd261bf08887d7dc2 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Fri, 26 Sep 2025 14:24:49 +0200 Subject: [PATCH] dllimport/export #6926 --- src/ifcconvert/IfcConvert.cpp | 7 +- src/ifcgeom/AbstractKernel.cpp | 183 +--------- src/ifcgeom/AbstractKernel.h | 27 +- src/ifcgeom/ConversionResult.cpp | 3 + src/ifcgeom/ConversionResult.h | 12 + src/ifcgeom/ConversionSettings.h | 27 +- src/ifcgeom/Converter.cpp | 106 +----- src/ifcgeom/Converter.h | 9 +- src/ifcgeom/IfcGeomElement.h | 2 +- src/ifcgeom/IfcGeomRepresentation.cpp | 320 +++--------------- src/ifcgeom/IfcGeomRepresentation.h | 2 +- src/ifcgeom/Iterator.cpp | 2 +- src/ifcgeom/Iterator.h | 43 +-- src/ifcgeom/Serialization/Serialization.h | 6 +- .../Serialization/ifc_geomserialization_api.h | 37 ++ src/ifcgeom/abstract_mapping.h | 27 +- src/ifcgeom/function_item_evaluator.h | 6 +- src/ifcgeom/hybrid_kernel.cpp | 0 src/ifcgeom/hybrid_kernel.h | 239 +++++++++++++ src/ifcgeom/infra_sweep_helper.h | 6 +- .../kernels/cgal/CgalConversionResult.cpp | 48 +++ .../kernels/cgal/CgalConversionResult.h | 22 +- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 4 + src/ifcgeom/kernels/cgal/CgalKernel.h | 27 +- src/ifcgeom/kernels/ifc_geomlibrary_api.h | 37 ++ src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 3 +- .../OpenCascadeConversionResult.cpp | 129 +++++++ .../opencascade/OpenCascadeConversionResult.h | 6 +- .../kernels/opencascade/OpenCascadeKernel.h | 10 +- .../kernels/opencascade/base_utils.cpp | 68 +++- src/ifcgeom/kernels/opencascade/base_utils.h | 77 +++-- .../kernels/opencascade/boolean_utils.cpp | 15 - .../kernels/opencascade/boolean_utils.h | 4 +- src/ifcgeom/kernels/opencascade/clash_utils.h | 16 +- src/ifcgeom/kernels/opencascade/wire_utils.h | 30 +- src/ifcgeom/taxonomy.h | 120 ++++--- src/ifcparse/IfcCharacterDecoder.h | 6 +- src/ifcparse/IfcEntityInstanceData.cpp | 80 ++--- src/ifcparse/IfcEntityInstanceData.h | 22 +- src/ifcparse/IfcFile.h | 5 +- src/ifcparse/storage.h | 11 +- src/ifcwrap/IfcGeomWrapper.i | 10 +- src/ifcwrap/IfcPython.i | 1 + src/serializers/serializers_api.h | 2 +- 44 files changed, 957 insertions(+), 860 deletions(-) create mode 100644 src/ifcgeom/Serialization/ifc_geomserialization_api.h create mode 100644 src/ifcgeom/hybrid_kernel.cpp create mode 100644 src/ifcgeom/hybrid_kernel.h create mode 100644 src/ifcgeom/kernels/ifc_geomlibrary_api.h diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 341966adc2..a87ebaf93c 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -45,6 +45,7 @@ #include "../ifcgeom/IfcGeomFilter.h" #include "../ifcgeom/Iterator.h" #include "../ifcgeom/IfcGeomRenderStyles.h" +#include "../ifcgeom/hybrid_kernel.h" #include "../ifcparse/utils.h" @@ -1018,7 +1019,7 @@ int main(int argc, char** argv) { if (is_tesselated && (center_model || center_model_geometry)) { std::vector offset(3); - IfcGeom::Iterator tmp_context_iterator(geometry_kernel, geometry_settings, ifc_file, filter_funcs, num_threads); + IfcGeom::Iterator tmp_context_iterator(ifcopenshell::geometry::kernels::construct(ifc_file, geometry_kernel, geometry_settings), geometry_settings, ifc_file, filter_funcs, num_threads); time_t start, end; time(&start); @@ -1064,7 +1065,7 @@ int main(int argc, char** argv) { std::unique_ptr context_iterator; if (!elems_from_adaptor) { - context_iterator.reset(new IfcGeom::Iterator(geometry_kernel, geometry_settings, ifc_file, filter_funcs, num_threads)); + context_iterator.reset(new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(ifc_file, geometry_kernel, geometry_settings), geometry_settings, ifc_file, filter_funcs, num_threads)); } #if defined(WITH_HDF5) && defined(IFOPSH_WITH_OPENCASCADE) @@ -1639,7 +1640,7 @@ void fix_quantities(IfcParse::IfcFile& f, bool no_progress, bool quiet, bool std settings.get().value = true; settings.get().value = ifcopenshell::geometry::settings::NATIVE; - IfcGeom::Iterator context_iterator(settings, &f, {}, 1); + IfcGeom::Iterator context_iterator(ifcopenshell::geometry::kernels::construct(&f, "opencascade", settings), settings, &f, {}, 1); if (!context_iterator.initialize()) { return; diff --git a/src/ifcgeom/AbstractKernel.cpp b/src/ifcgeom/AbstractKernel.cpp index d88acf0a2e..724178a1cd 100644 --- a/src/ifcgeom/AbstractKernel.cpp +++ b/src/ifcgeom/AbstractKernel.cpp @@ -1,23 +1,9 @@ -#include "AbstractKernel.h" - #include "../ifcgeom/IfcGeomElement.h" #include "../ifcgeom/ConversionSettings.h" #include "../ifcgeom/abstract_mapping.h" #include "../ifcgeom/function_item_evaluator.h" -#ifdef IFOPSH_WITH_OPENCASCADE -#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" -#undef Handle -#endif - -#ifdef IFOPSH_WITH_CGAL -#include "../ifcgeom/kernels/cgal/CgalKernel.h" -#undef CGAL_KERNEL_H -#undef CGALCONVERSIONRESULT_H -#define IFOPSH_SIMPLE_KERNEL -#include "../ifcgeom/kernels/cgal/CgalKernel.h" -#undef CgalKernel -#endif +#include "AbstractKernel.h" using namespace ifcopenshell::geometry; @@ -73,173 +59,6 @@ const Settings& ifcopenshell::geometry::kernels::AbstractKernel::settings() cons return settings_; } - -bool is_valid_for_kernel(const ifcopenshell::geometry::kernels::AbstractKernel* k, const IfcGeom::ConversionResult& shp) { -#ifdef IFOPSH_WITH_OPENCASCADE - if (k->geometry_library() == "opencascade") { - return dynamic_cast(shp.Shape().get()) != nullptr; - } -#endif -#ifdef IFOPSH_WITH_CGAL - if (k->geometry_library() == "cgal-simple") { - return dynamic_cast(shp.Shape().get()) != nullptr; - } - if (k->geometry_library() == "cgal") { - return dynamic_cast(shp.Shape().get()) != nullptr; - } -#endif - return false; -} - -class HybridKernel : public ifcopenshell::geometry::kernels::AbstractKernel { - std::vector> kernels_; - ifcopenshell::geometry::abstract_mapping* mapping_; -public: - HybridKernel(const std::string& name, IfcParse::IfcFile* file, Settings& settings, std::vector>&& kernels) - : AbstractKernel(name, settings) - , kernels_(std::move(kernels)) - , mapping_(ifcopenshell::geometry::impl::mapping_implementations().construct(file, settings)) - {} - virtual bool convert(const taxonomy::ptr item, IfcGeom::ConversionResults& rs) { - auto ops = mapping_->find_openings(item->instance->as()); - bool has_openings = ops && ops->size(); - for (auto& k : kernels_) { -#ifdef IFOPSH_WITH_CGAL - if (has_openings && dynamic_cast(k.get())) { - // @todo this would fail later on in the find_openings() call, because we have a - // SimpleCgalShape which cannot be used on a kernel that supports booleans. - // @todo 1 implement the translation between various conversion result shapes - // @todo 2 fold the boolean result openings into the taxonomy item. This should be possible - // now that we have shared_ptr and caching in place. So the inability - // to instance wouldn't matter as much. - continue; - } -#endif - bool success = false; - try { - success = k->convert(item, rs); - } catch(...) {} - if (success) { - return true; - } - } - return false; - } - virtual bool apply_layerset(IfcGeom::ConversionResults& items, const ifcopenshell::geometry::layerset_information& layers) { - for (auto& k : kernels_) { - bool success = false; - try { - success = k->apply_layerset(items, layers); - } catch (...) {} - if (success) { - return true; - } - } - return false; - } - virtual bool apply_folded_layerset(IfcGeom::ConversionResults& items, const ifcopenshell::geometry::layerset_information& layers, const std::map& folds) { - for (auto& k : kernels_) { - bool success = false; - try { - success = k->apply_folded_layerset(items, layers, folds); - } catch (...) {} - if (success) { - return true; - } - } - return false; - } - 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) - { - for (auto& k : kernels_) { - bool is_valid = true; - for (auto& s : entity_shapes) { - if (!is_valid_for_kernel(k.get(), s)) { - is_valid = false; - break; - } - } - if (!is_valid) { - continue; - } - bool success = false; - try { - success = k->convert_openings(entity, openings, entity_shapes, entity_trsf, cut_shapes); - } catch (...) {} - if (success) { - return true; - } - } - return false; - } -}; - -ifcopenshell::geometry::kernels::AbstractKernel* ifcopenshell::geometry::kernels::construct(IfcParse::IfcFile* file, const std::string& geometry_library, Settings& conv_settings) { - std::string geometry_library_lower = boost::to_lower_copy(geometry_library); - -#ifdef IFOPSH_WITH_OPENCASCADE - if (geometry_library_lower == "opencascade") { - return new IfcGeom::OpenCascadeKernel(conv_settings); - } -#endif - -#ifdef IFOPSH_WITH_CGAL - if (geometry_library_lower == "cgal") { - return new CgalKernel(conv_settings); - } - - if (geometry_library_lower == "cgal-simple") { - return new SimpleCgalKernel(conv_settings); - } -#endif - - if (geometry_library_lower.rfind("hybrid-", 0) == 0) { - geometry_library_lower = geometry_library_lower.substr(strlen("hybrid")); - std::vector> kernels; - while (!geometry_library_lower.empty()) { - if (geometry_library_lower.find("-", 0) == 0) { - geometry_library_lower = geometry_library_lower.substr(strlen("-")); - } else { - throw IfcParse::IfcException("Invalid hybrid kernel " + geometry_library); - } - auto n = kernels.size(); -#ifdef IFOPSH_WITH_OPENCASCADE - if (geometry_library_lower.find("opencascade", 0) == 0) { - kernels.emplace_back(new IfcGeom::OpenCascadeKernel(conv_settings)); - geometry_library_lower = geometry_library_lower.substr(strlen("opencascade")); - } -#endif - -#ifdef IFOPSH_WITH_CGAL - if (geometry_library_lower.find("cgal-simple", 0) == 0) { - kernels.emplace_back(new SimpleCgalKernel(conv_settings)); - geometry_library_lower = geometry_library_lower.substr(strlen("cgal-simple")); - } - - if (geometry_library_lower.find("cgal", 0) == 0) { - kernels.emplace_back(new CgalKernel(conv_settings)); - geometry_library_lower = geometry_library_lower.substr(strlen("cgal")); - } -#endif - if (kernels.size() != n + 1) { - throw IfcParse::IfcException("Invalid hybrid kernel " + geometry_library); - } - } - - for (auto it = kernels.begin(); it != kernels.end(); ++it) { - (**it).propagate_exceptions = it == kernels.begin(); - (**it).partial_success_is_success = it == kernels.end() - 1; - } - - if (!kernels.empty()) { - return new HybridKernel(geometry_library, file, conv_settings, std::move(kernels)); - } - } - - throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library); -} - bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::collection::ptr collection, IfcGeom::ConversionResults& r) { auto s = r.size(); for (auto& c : collection->children) { diff --git a/src/ifcgeom/AbstractKernel.h b/src/ifcgeom/AbstractKernel.h index c78794c862..2f9aae7e1a 100644 --- a/src/ifcgeom/AbstractKernel.h +++ b/src/ifcgeom/AbstractKernel.h @@ -1,3 +1,22 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + #ifndef ABSTRACT_KERNEL_H #define ABSTRACT_KERNEL_H @@ -7,6 +26,7 @@ #include "../ifcgeom/IfcGeomRepresentation.h" #include "../ifcgeom/taxonomy.h" #include "../ifcgeom/ConversionSettings.h" +#include "../ifcgeom/abstract_mapping.h" static const double ALMOST_ZERO = 1.e-9; @@ -55,6 +75,8 @@ namespace ifcopenshell { return geometry_library_; } + virtual bool supports_boolean_operations() const = 0; + virtual bool convert_impl(const taxonomy::matrix4::ptr, IfcGeom::ConversionResults&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::point3::ptr, IfcGeom::ConversionResults&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::direction3::ptr, IfcGeom::ConversionResults&) { throw not_implemented_error(); } @@ -98,10 +120,9 @@ namespace ifcopenshell { 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) = 0; virtual bool unify_shapes(const IfcGeom::ConversionResults&, IfcGeom::ConversionResults&) { throw not_implemented_error(); } + + virtual AbstractKernel* clone() const = 0; }; - - AbstractKernel* construct(IfcParse::IfcFile* file, const std::string& geometry_library, Settings& conv_settings); - } } } diff --git a/src/ifcgeom/ConversionResult.cpp b/src/ifcgeom/ConversionResult.cpp index 96ab62f428..7e6360e927 100644 --- a/src/ifcgeom/ConversionResult.cpp +++ b/src/ifcgeom/ConversionResult.cpp @@ -26,3 +26,6 @@ std::string IfcGeom::NumberNativeDouble::to_string() const { ss << std::setprecision(std::numeric_limits::digits10 + 1) << value_; return ss.str(); } + +template struct IFC_GEOM_API IfcGeom::OpaqueCoordinate<3>; +template struct IFC_GEOM_API IfcGeom::OpaqueCoordinate<4>; \ No newline at end of file diff --git a/src/ifcgeom/ConversionResult.h b/src/ifcgeom/ConversionResult.h index 04a234cba8..7ec5adb9f2 100644 --- a/src/ifcgeom/ConversionResult.h +++ b/src/ifcgeom/ConversionResult.h @@ -290,10 +290,13 @@ namespace IfcGeom { virtual ConversionResultShape* add(ConversionResultShape*) = 0; virtual ConversionResultShape* subtract(ConversionResultShape*) = 0; virtual ConversionResultShape* intersect(ConversionResultShape*) = 0; + virtual ConversionResultShape* concat(ConversionResultShape*) = 0; virtual void map(OpaqueCoordinate<4>& from, OpaqueCoordinate<4>& to) = 0; virtual void map(const std::vector>& from, const std::vector>& to) = 0; virtual ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const = 0; + + virtual bool surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const = 0; virtual ~ConversionResultShape() {} @@ -327,6 +330,15 @@ namespace IfcGeom { ifcopenshell::geometry::taxonomy::style::ptr StylePtr() const { return style_; } void setStyle(ifcopenshell::geometry::taxonomy::style::ptr newStyle) { style_ = newStyle; } int ItemId() const { return id; } + ConversionResultShape* apply_transform(double unit_scale = 1.) const { + if (unit_scale != 1.) { + auto m = ifcopenshell::geometry::taxonomy::matrix4::ptr(placement_->clone_()); + m->pre_multiply_scale(unit_scale); + return shape_->moved(m); + } else { + return shape_->moved(placement_); + } + } }; typedef std::vector ConversionResults; diff --git a/src/ifcgeom/ConversionSettings.h b/src/ifcgeom/ConversionSettings.h index 5e47e7342d..0699668217 100644 --- a/src/ifcgeom/ConversionSettings.h +++ b/src/ifcgeom/ConversionSettings.h @@ -22,9 +22,9 @@ namespace po = boost::program_options; namespace std { - istream& operator>>(istream& in, set& ints); - istream& operator>>(istream& in, set& ints); - istream& operator>>(istream& in, vector& vs); + IFC_GEOM_API istream& operator>>(istream& in, set& ints); + IFC_GEOM_API istream& operator>>(istream& in, set& ints); + IFC_GEOM_API istream& operator>>(istream& in, vector& vs); } #endif @@ -249,7 +249,7 @@ namespace ifcopenshell { CURVES_SURFACES_AND_SOLIDS }; - std::istream& operator>>(std::istream& in, OutputDimensionalityTypes& ioo); + IFC_GEOM_API std::istream& operator>>(std::istream& in, OutputDimensionalityTypes& ioo); struct OutputDimensionality : public SettingBase { static constexpr const char* const name = "dimensionality"; @@ -266,7 +266,7 @@ namespace ifcopenshell { SERIALIZED }; - std::istream& operator>>(std::istream& in, IteratorOutputOptions& ioo); + IFC_GEOM_API std::istream& operator>>(std::istream& in, IteratorOutputOptions& ioo); struct IteratorOutput : public SettingBase { static constexpr const char* const name = "iterator-output"; @@ -395,7 +395,7 @@ namespace ifcopenshell { MAXSTEPSIZE, MINSTEPS }; - std::istream& operator>>(std::istream& in, FunctionStepMethod& ioo); + IFC_GEOM_API std::istream& operator>>(std::istream& in, FunctionStepMethod& ioo); struct FunctionStepType : public SettingBase { static constexpr const char* const name = "function-step-type"; @@ -425,7 +425,7 @@ namespace ifcopenshell { POLYHEDRON_WITH_HOLES }; - std::istream& operator>>(std::istream& in, TriangulationMethod& ioo); + IFC_GEOM_API std::istream& operator>>(std::istream& in, TriangulationMethod& ioo); struct TriangulationType : public SettingBase { static constexpr const char* const name = "triangulation-type"; @@ -536,7 +536,7 @@ namespace ifcopenshell { } template - class IFC_GEOM_API SettingsContainer { + class SettingsContainer { public: typedef boost::variant, std::set, std::vector, IteratorOutputOptions, FunctionStepMethod, OutputDimensionalityTypes, TriangulationMethod> value_variant_t; private: @@ -645,7 +645,7 @@ namespace ifcopenshell { } }; - class IFC_GEOM_API Settings : public SettingsContainer< + class Settings : public SettingsContainer< std::tuple > {}; @@ -654,16 +654,13 @@ namespace ifcopenshell { // @todo find a place namespace IfcGeom { - class IFC_GEOM_API geometry_exception : public std::exception { + class IFC_GEOM_API geometry_exception : public std::runtime_error { 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(); - } + : std::runtime_error(m) + {} }; class IFC_GEOM_API too_many_faces_exception : public geometry_exception { diff --git a/src/ifcgeom/Converter.cpp b/src/ifcgeom/Converter.cpp index 3b1aecc1fb..6b70ac7f51 100644 --- a/src/ifcgeom/Converter.cpp +++ b/src/ifcgeom/Converter.cpp @@ -4,20 +4,16 @@ using namespace ifcopenshell::geometry; -ifcopenshell::geometry::Converter::Converter(const std::string& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& s) - : geometry_library_(boost::to_lower_copy(geometry_library)) +ifcopenshell::geometry::Converter::Converter(std::unique_ptr&& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& s) + : kernel_(std::move(geometry_library)) { mapping_ = impl::mapping_implementations().construct(file, s); - kernel_ = kernels::construct(file, geometry_library, mapping_->settings()); // Mapping reads unit information and applies to settings settings_ = mapping_->settings(); } ifcopenshell::geometry::Converter::~Converter() { - if (kernel_ != nullptr) { - delete kernel_; - } if (mapping_ != nullptr) { delete mapping_; } @@ -414,101 +410,3 @@ IfcGeom::ConversionResults ifcopenshell::geometry::Converter::convert(IfcUtil::I } return results; } - -//#include "../../ifcparse/Ifc2x3.h" -//#include "../../ifcparse/Ifc4.h" -// -//// @todo remove -//#include "../../ifcgeom/schema_agnostic/opencascade/OpenCascadeConversionResult.h" -// -//#include -//#include -//#include -//#include -// -//IfcGeom::Kernel::Kernel(const std::string& geometry_library, IfcParse::IfcFile* file) { -// if (file != 0) { -// if (file->schema() == 0) { -// throw IfcParse::IfcException("No schema associated with file"); -// } -// -// const std::string& schema_name = file->schema()->name(); -// implementation_ = impl::kernel_implementations().construct(schema_name, geometry_library, file); -// } -//} -// -//int IfcGeom::Kernel::count(const ConversionResultShape* s_, int t_, bool unique) { -// // @todo make kernel agnostic -// const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape(); -// TopAbs_ShapeEnum t = (TopAbs_ShapeEnum) t_; -// -// if (unique) { -// TopTools_IndexedMapOfShape map; -// TopExp::MapShapes(s, t, map); -// return map.Extent(); -// } else { -// int i = 0; -// TopExp_Explorer exp(s, t); -// for (; exp.More(); exp.Next()) { -// ++i; -// } -// return i; -// } -//} -// -// -//int IfcGeom::Kernel::surface_genus(const ConversionResultShape* s_) { -// // @todo make kernel agnostic -// const TopoDS_Shape& s = ((OpenCascadeShape*) s_)->shape(); -// OpenCascadeShape Ss(s); -// -// int nv = count(&Ss, (int) TopAbs_VERTEX, true); -// int ne = count(&Ss, (int) TopAbs_EDGE, true); -// int nf = count(&Ss, (int) TopAbs_FACE, true); -// -// const int euler = nv - ne + nf; -// const int genus = (2 - euler) / 2; -// -// return genus; -//} -// -// -//IfcUtil::IfcBaseEntity* IfcGeom::Kernel::get_decomposing_entity(IfcUtil::IfcBaseEntity* inst, bool include_openings) { -// if (inst->as()) { -// return get_decomposing_entity_impl(inst->as(), include_openings); -// } else if (inst->as()) { -// return get_decomposing_entity_impl(inst->as(), include_openings); -// } else if (inst->declaration().name() == "IfcProject") { -// return nullptr; -// } else { -// throw IfcParse::IfcException("Unexpected entity " + inst->declaration().name()); -// } -//} -// -// -//bool IfcGeom::Kernel::is_manifold(const ConversionResultShape* s_) { -// // @todo make kernel agnostic -// const TopoDS_Shape& a = ((OpenCascadeShape*) s_)->shape(); -// -// if (a.ShapeType() == TopAbs_COMPOUND || a.ShapeType() == TopAbs_SOLID) { -// TopoDS_Iterator it(a); -// for (; it.More(); it.Next()) { -// OpenCascadeShape s(it.Value()); -// if (!is_manifold(&s)) { -// return false; -// } -// } -// return true; -// } else { -// TopTools_IndexedDataMapOfShapeListOfShape map; -// TopExp::MapShapesAndAncestors(a, TopAbs_EDGE, TopAbs_FACE, map); -// -// for (int i = 1; i <= map.Extent(); ++i) { -// if (map.FindFromIndex(i).Extent() != 2) { -// return false; -// } -// } -// -// return true; -// } -//} diff --git a/src/ifcgeom/Converter.h b/src/ifcgeom/Converter.h index f0dcc72515..9fff13df04 100644 --- a/src/ifcgeom/Converter.h +++ b/src/ifcgeom/Converter.h @@ -13,20 +13,19 @@ namespace ifcopenshell { namespace geometry { - class Converter { + class IFC_GEOM_API Converter { public: typedef boost::shared_ptr brep_ptr; private: - std::string geometry_library_; ifcopenshell::geometry::abstract_mapping* mapping_; - ifcopenshell::geometry::kernels::AbstractKernel* kernel_; + std::unique_ptr kernel_; ifcopenshell::geometry::Settings settings_; std::map cache_; public: - ifcopenshell::geometry::kernels::AbstractKernel* kernel() { return kernel_; } + ifcopenshell::geometry::kernels::AbstractKernel* kernel() { return &*kernel_; } - Converter(const std::string& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& settings); + Converter(std::unique_ptr&& geometry_library, IfcParse::IfcFile* file, ifcopenshell::geometry::Settings& settings); ~Converter(); diff --git a/src/ifcgeom/IfcGeomElement.h b/src/ifcgeom/IfcGeomElement.h index cb4ba87f06..0d7e179d7b 100644 --- a/src/ifcgeom/IfcGeomElement.h +++ b/src/ifcgeom/IfcGeomElement.h @@ -143,7 +143,7 @@ namespace IfcGeom { {} bool calculate_projected_surface_area(double& along_x, double& along_y, double& along_z) const { - return geometry().calculate_projected_surface_area(*this->transformation().data(), along_x, along_y, along_z); + return geometry().calculate_projected_surface_area(this->transformation().data(), along_x, along_y, along_z); } private: BRepElement(const BRepElement& other); diff --git a/src/ifcgeom/IfcGeomRepresentation.cpp b/src/ifcgeom/IfcGeomRepresentation.cpp index 822ce05feb..9ca210f6e6 100644 --- a/src/ifcgeom/IfcGeomRepresentation.cpp +++ b/src/ifcgeom/IfcGeomRepresentation.cpp @@ -19,128 +19,6 @@ #include "IfcGeomRepresentation.h" -#ifdef IFOPSH_WITH_OPENCASCADE -#include "../ifcparse/IfcLogger.h" -#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" -#include "../ifcgeom/kernels/opencascade/base_utils.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_Trsf& t) { - if (t.Form() == gp_Identity) { - return s; - } else { - /// @todo set to 1. and exactly 1. or use epsilon? - if (t.ScaleFactor() != 1.) { - return BRepBuilderAPI_Transform(s, t, true); - } else { - return s.Moved(t); - } - } -} - -TopoDS_Shape apply_transformation(const TopoDS_Shape& s, const gp_GTrsf& t) { - if (t.Form() == gp_Other) { - return BRepBuilderAPI_GTransform(s, t, true); - } else { - return apply_transformation(s, t.Trsf()); - } -} - -namespace { - void accumulate(const gp_Ax3& ax, const gp_Dir& normal, double area, double& along_x, double& along_y, double& along_z) { - along_x += area * fabs(ax.XDirection().Dot(normal)); - along_y += area * fabs(ax.YDirection().Dot(normal)); - along_z += area * fabs(ax.Direction().Dot(normal)); - } - - void surface_area_along_direction(double tol, const TopoDS_Shape& s, const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) { - along_x = along_y = along_z = 0.; - - bool meshed = false; - - TopExp_Explorer exp(s, TopAbs_FACE); - for (; exp.More(); exp.Next()) { - const TopoDS_Face& face = TopoDS::Face(exp.Current()); - Handle(Geom_Surface) surf = BRep_Tool::Surface(face); - Handle(Geom_Plane) plane = Handle(Geom_Plane)::DownCast(surf); - - if (surf->DynamicType() == STANDARD_TYPE(Geom_Plane)) { - GProp_GProps prop_area; - BRepGProp::SurfaceProperties(face, prop_area); - const double area = prop_area.Mass(); - - accumulate(ax, plane->Position().Direction(), area, along_x, along_y, along_z); - } else { - - if (!meshed) { - try { - BRepMesh_IncrementalMesh(s, tol); - } catch (...) { - Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); - return; - } - meshed = true; - } - - TopLoc_Location loc; - Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc); - if (!tri.IsNull()) { - std::vector coords; - coords.reserve(tri->NbNodes()); - - for (int i = 1; i <= tri->NbNodes(); ++i) { - coords.push_back(tri->Node(i).Transformed(loc).XYZ()); - } - - const Poly_Array1OfTriangle& triangles = tri->Triangles(); - for (int i = 1; i <= triangles.Length(); ++i) { - int n1, n2, n3; - - if (face.Orientation() == TopAbs_REVERSED) { - triangles(i).Get(n3, n2, n1); - } else { - triangles(i).Get(n1, n2, n3); - } - - const gp_XYZ& pt1 = coords[n1 - 1]; - const gp_XYZ& pt2 = coords[n2 - 1]; - const gp_XYZ& pt3 = coords[n3 - 1]; - const gp_Vec v1 = pt2 - pt1; - const gp_Vec v2 = pt3 - pt2; - const gp_Vec v3 = pt1 - pt3; - const gp_Vec normal_vector = v1 ^ v2; - if (normal_vector.Magnitude() > 1.e-7) { - gp_Dir normal = gp_Dir(); - - double edge_lengths[3] = { v1.Magnitude(), v2.Magnitude(), v3.Magnitude() }; - std::sort(&edge_lengths[0], &edge_lengths[2]); - - const double& a = edge_lengths[0]; - const double& b = edge_lengths[1]; - const double& c = edge_lengths[2]; - - const double area = 0.25 * sqrt((a + (b + c))*(c - (a - b))*(c + (a - b))*(a + (b - c))); - accumulate(ax, normal, area, along_x, along_y, along_z); - } - } - } - } - } - } -} -#endif - IfcGeom::Representation::Serialization::Serialization(const BRep& brep) : Representation(brep.settings(), brep.entity(), brep.id()) { @@ -169,191 +47,73 @@ IfcGeom::Representation::Serialization::Serialization(const BRep& brep) surface_style_ids_.push_back(sid); } - if (brep.begin() != brep.end()) { -#ifdef IFOPSH_WITH_OPENCASCADE - if (std::dynamic_pointer_cast(brep.begin()->Shape())) { - ConversionResultShape* shape = brep.as_compound(); - ifcopenshell::geometry::taxonomy::matrix4 identity; - shape->Serialize(identity, brep_data_); - delete shape; - } else -#endif - { - for (auto it = brep.begin(); it != brep.end(); ++it) { - std::string part; - it->Shape()->Serialize(*it->Placement(), part); - if (brep_data_.size()) { - brep_data_ = brep_data_ + "\n---\n" + part; - } else { - brep_data_ = part; - } - } - } - } -} - -namespace { - bool is_non_uniform(const Eigen::Matrix4d& M, double eps = 1e-6) - { - Eigen::Matrix3d L = M.block<3, 3>(0, 0); - double sx = L.col(0).norm(); - double sy = L.col(1).norm(); - double sz = L.col(2).norm(); - return !( - std::abs(sx - sy) < eps && - std::abs(sx - sz) < eps && - std::abs(sy - sz) < eps - ); - } + ifcopenshell::geometry::taxonomy::matrix4 identity; + auto* comp = brep.as_compound(); + comp->Serialize(identity, brep_data_); + delete comp; } IfcGeom::ConversionResultShape* IfcGeom::Representation::BRep::as_compound(bool force_meters) const { -#ifdef IFOPSH_WITH_OPENCASCADE - TopoDS_Compound compound; - BRep_Builder builder; - builder.MakeCompound(compound); + ConversionResultShape* accum = nullptr; for (auto it = begin(); it != end(); ++it) { - const TopoDS_Shape& s = *std::static_pointer_cast(it->Shape()); - - gp_GTrsf trsf; - if (it->Placement()->components_) { - const auto& m = it->Placement()->ccomponents(); - // This is either a bug or very finicky, but this appears to be the only - // way to get the transformation metadata to line up. - // - // - If gp_GTrsf.form is other, applying the transformation will result in - // a conversion to b-spline surfaces for about everything, which impacts - // performance and breaks detection of view volume in the svg serializer, - // which would be the case when setting the SetVectorialPart() block - // unconditionally. - // (calling SetForm() afterwards to detect CompoundTrsf over Other would - // set Scale to zero (bug?)) - if (is_non_uniform(m)) { - trsf.SetVectorialPart(gp_Mat( - m(0, 0), m(0, 1), m(0, 2), - m(1, 0), m(1, 1), m(1, 2), - m(2, 0), m(2, 1), m(2, 2) - )); - trsf.SetTranslationPart(gp_XYZ(m(0, 3), m(1, 3), m(2, 3))); - } else { - gp_Trsf tr; - tr.SetValues( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3) - ); - trsf = tr; - } - } - + double unit_scale = 1.0; if (!force_meters && settings().get().get()) { - gp_Trsf scale; - scale.SetScaleFactor(1.0 / settings().get().get()); - trsf.PreMultiply(scale); + unit_scale = 1.0 / settings().get().get(); + } + auto s = it->apply_transform(unit_scale); + if (accum) { + auto n = accum->concat(s); + delete s; + delete accum; + accum = n; + } else { + accum = s; } - - const TopoDS_Shape moved_shape = apply_transformation(s, trsf); - builder.Add(compound, moved_shape); } - return new ifcopenshell::geometry::OpenCascadeShape(std::move(compound)); -#else - throw std::runtime_error("Not available without Open Cascade"); -#endif + return accum; } - bool IfcGeom::Representation::BRep::calculate_surface_area(double& area) const { -#ifdef IFOPSH_WITH_OPENCASCADE - try { + std::unique_ptr s(as_compound()); + if (!s) { area = 0.; - - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { - GProp_GProps prop; - BRepGProp::SurfaceProperties(*std::static_pointer_cast(it->Shape()), prop); - area += prop.Mass(); - } - - return true; - } catch (...) { - Logger::Error("Error during calculation of surface area"); return false; } -#else - throw std::runtime_error("Not available without Open Cascade"); -#endif + area = s->area()->to_double(); + return true; } bool IfcGeom::Representation::BRep::calculate_volume(double& volume) const { -#ifdef IFOPSH_WITH_OPENCASCADE - try { + std::unique_ptr s(as_compound()); + if (!s) { volume = 0.; - - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { - if (util::is_manifold(*std::static_pointer_cast(it->Shape()))) { - GProp_GProps prop; - BRepGProp::VolumeProperties(*std::static_pointer_cast(it->Shape()), prop); - volume += prop.Mass(); - } else { - return false; - } - } - - return true; - } catch (...) { - Logger::Error("Error during calculation of volume"); return false; } -#else - throw std::runtime_error("Not available without Open Cascade"); -#endif + volume = s->area()->to_double(); + return true; } -bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4& place, double & along_x, double & along_y, double & along_z) const { -#ifdef IFOPSH_WITH_OPENCASCADE - try { - gp_GTrsf trsf; +bool IfcGeom::Representation::BRep::calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4::ptr& place, double& along_x, double& along_y, double& along_z) const { + along_x = along_y = along_z = 0.; - if (place.components_) { - gp_Trsf tr; - const auto& m = place.ccomponents(); - tr.SetValues( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3) - ); - trsf = tr; + for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { + double x, y, z; + it->Shape()->surface_area_along_direction(settings().get().get(), place, x, y, z); + + if (it->Shape()->is_manifold()) { + x /= 2.; + y /= 2.; + z /= 2.; } - gp_Mat mat = trsf.Trsf().HVectorialPart(); - gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1)); - - along_x = along_y = along_z = 0.; - - for (IfcGeom::ConversionResults::const_iterator it = begin(); it != end(); ++it) { - double 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.; - y /= 2.; - z /= 2.; - } - - along_x += x; - along_y += y; - along_z += z; - } - - return true; - } catch (...) { - Logger::Error("Error during calculation of projected surface area"); - return false; + along_x += x; + along_y += y; + along_z += z; } -#else - throw std::runtime_error("Not available without Open Cascade"); -#endif + + return true; } IfcGeom::Representation::Triangulation::Triangulation(const BRep& shape_model) diff --git a/src/ifcgeom/IfcGeomRepresentation.h b/src/ifcgeom/IfcGeomRepresentation.h index 8f95547de2..2bafa9ab88 100644 --- a/src/ifcgeom/IfcGeomRepresentation.h +++ b/src/ifcgeom/IfcGeomRepresentation.h @@ -72,7 +72,7 @@ namespace IfcGeom { bool calculate_volume(double&) const; bool calculate_surface_area(double&) const; - bool calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4& ax, double& along_x, double& along_y, double& along_z) const; + bool calculate_projected_surface_area(const ifcopenshell::geometry::taxonomy::matrix4::ptr& ax, double& along_x, double& along_y, double& along_z) const; int size() const { return (int) shapes_.size(); } const IfcGeom::ConversionResultShape* item(int i) const; diff --git a/src/ifcgeom/Iterator.cpp b/src/ifcgeom/Iterator.cpp index 292a4c8661..fa36ce1e34 100644 --- a/src/ifcgeom/Iterator.cpp +++ b/src/ifcgeom/Iterator.cpp @@ -194,7 +194,7 @@ void IfcGeom::Iterator::process_concurrently() { kernel_pool.reserve(conc_threads); for (unsigned i = 0; i < conc_threads; ++i) { - kernel_pool.push_back(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)); + kernel_pool.push_back(new ifcopenshell::geometry::Converter(std::unique_ptr(converter_->kernel()->clone()), ifc_file, settings_)); } std::vector> threadpool; diff --git a/src/ifcgeom/Iterator.h b/src/ifcgeom/Iterator.h index 9cec31bd47..3f5f90a350 100644 --- a/src/ifcgeom/Iterator.h +++ b/src/ifcgeom/Iterator.h @@ -86,7 +86,7 @@ namespace IfcGeom { - struct geometry_conversion_result { + struct IFC_GEOM_API geometry_conversion_result { int index; // For NoParallelMapping==true @@ -102,7 +102,7 @@ namespace IfcGeom { }; - class Iterator { + class IFC_GEOM_API Iterator { private: GeometrySerializer* cache_ = nullptr; @@ -212,50 +212,33 @@ namespace IfcGeom { ifcopenshell::geometry::taxonomy::direction3::ptr remove_offset_(); public: - Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) + + Iterator(std::unique_ptr&& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) : settings_(settings) , ifc_file(file) , filters_(filters) , num_threads_(num_threads) - , geometry_library_(geometry_library) - , converter_(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)) + , geometry_library_(geometry_library->geometry_library()) + // @todo verify whether settings are correctly passed on + , converter_(new ifcopenshell::geometry::Converter(std::move(geometry_library), ifc_file, settings_)) { } - Iterator(const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, const std::vector& filters, int num_threads) - : settings_(settings) - , ifc_file(file) - , filters_(filters) - , num_threads_(num_threads) - , geometry_library_("opencascade") - , converter_(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)) - { - } - - Iterator(const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file) + Iterator(std::unique_ptr&& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file) : settings_(settings) , ifc_file(file) , num_threads_(1) - , geometry_library_("opencascade") - , converter_(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)) + , geometry_library_(geometry_library->geometry_library()) + , converter_(new ifcopenshell::geometry::Converter(std::move(geometry_library), ifc_file, settings_)) { } - Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file) - : settings_(settings) - , ifc_file(file) - , num_threads_(1) - , geometry_library_(geometry_library) - , converter_(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)) - { - } - - Iterator(const std::string& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, int num_threads) + Iterator(std::unique_ptr&& geometry_library, const ifcopenshell::geometry::Settings& settings, IfcParse::IfcFile* file, int num_threads) : settings_(settings) , ifc_file(file) , num_threads_(num_threads) - , geometry_library_(geometry_library) - , converter_(new ifcopenshell::geometry::Converter(geometry_library_, ifc_file, settings_)) + , geometry_library_(geometry_library->geometry_library()) + , converter_(new ifcopenshell::geometry::Converter(std::move(geometry_library), ifc_file, settings_)) { } diff --git a/src/ifcgeom/Serialization/Serialization.h b/src/ifcgeom/Serialization/Serialization.h index 95bd9f3ec1..464d2e8561 100644 --- a/src/ifcgeom/Serialization/Serialization.h +++ b/src/ifcgeom/Serialization/Serialization.h @@ -1,12 +1,12 @@ #include "../../ifcparse/IfcBaseClass.h" -#include "../../ifcgeom/ifc_geom_api.h" +#include "ifc_geomserialization_api.h" #include #include namespace IfcGeom { - IFC_GEOM_API IfcUtil::IfcBaseClass* tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection); - IFC_GEOM_API IfcUtil::IfcBaseClass* serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced); + IFC_GEOMSERIALIZATION_API IfcUtil::IfcBaseClass* tesselate(const std::string& schema_name, const TopoDS_Shape& shape, double deflection); + IFC_GEOMSERIALIZATION_API IfcUtil::IfcBaseClass* serialise(const std::string& schema_name, const TopoDS_Shape& shape, bool advanced); } diff --git a/src/ifcgeom/Serialization/ifc_geomserialization_api.h b/src/ifcgeom/Serialization/ifc_geomserialization_api.h new file mode 100644 index 0000000000..93058cf04f --- /dev/null +++ b/src/ifcgeom/Serialization/ifc_geomserialization_api.h @@ -0,0 +1,37 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#ifndef IFC_GEOMSERIALIZATION_API_H +#define IFC_GEOMSERIALIZATION_API_H + +#ifdef IFC_SHARED_BUILD +#ifdef _WIN32 +#ifdef IFC_GEOMSERIALIZATION_EXPORTS +#define IFC_GEOMSERIALIZATION_API __declspec(dllexport) +#else +#define IFC_GEOMSERIALIZATION_API __declspec(dllimport) +#endif +#else // simply assume *nix + GCC-like compiler +#define IFC_GEOMSERIALIZATION_API __attribute__((visibility("default"))) +#endif +#else +#define IFC_GEOMSERIALIZATION_API +#endif + +#endif diff --git a/src/ifcgeom/abstract_mapping.h b/src/ifcgeom/abstract_mapping.h index c8ba61e1b4..6d47b32829 100644 --- a/src/ifcgeom/abstract_mapping.h +++ b/src/ifcgeom/abstract_mapping.h @@ -1,3 +1,22 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + #ifndef ABSTRACT_MAPPING_H #define ABSTRACT_MAPPING_H @@ -16,7 +35,7 @@ namespace ifcopenshell { namespace geometry { - struct geometry_conversion_task { + struct IFC_GEOM_API geometry_conversion_task { int index; IfcUtil::IfcBaseEntity* representation; aggregate_of_instance::ptr products; @@ -24,7 +43,7 @@ namespace geometry { typedef boost::function filter_t; - class abstract_mapping { + class IFC_GEOM_API abstract_mapping { protected: Settings settings_; @@ -58,14 +77,14 @@ namespace geometry { namespace impl { typedef boost::function2 mapping_fn; - class MappingFactoryImplementation : public std::map { + class IFC_GEOM_API MappingFactoryImplementation : public std::map { public: MappingFactoryImplementation(); void bind(const std::string& schema_name, mapping_fn); abstract_mapping* construct(IfcParse::IfcFile*, Settings&); }; - MappingFactoryImplementation& mapping_implementations(); + IFC_GEOM_API MappingFactoryImplementation& mapping_implementations(); } } diff --git a/src/ifcgeom/function_item_evaluator.h b/src/ifcgeom/function_item_evaluator.h index 642d66a8ef..9773c8731c 100644 --- a/src/ifcgeom/function_item_evaluator.h +++ b/src/ifcgeom/function_item_evaluator.h @@ -9,7 +9,7 @@ namespace ifcopenshell { namespace geometry { /// @brief Computes a point on a helmert curve at s. /// Returns (x,y,theta) at L/2. The results are in a vector so they can be returned to python -std::vector helmert_curve_point(double A0, double A1, double A2, double s); +IFC_GEOM_API std::vector helmert_curve_point(double A0, double A1, double A2, double s); /// @brief Converts a loop to a function item. /// This is intended to be used from python side. Polylines are mapped to a loop, but when @@ -22,7 +22,7 @@ static taxonomy::function_item::ptr convert_loop_to_function_item(taxonomy::loop } /// @brief Abstract class for evaluating a function_item. This class is specialized for each of the function_item types. -struct fn_evaluator { +struct IFC_GEOM_API fn_evaluator { fn_evaluator(const ifcopenshell::geometry::Settings& settings) : settings_(settings) { } fn_evaluator(const fn_evaluator& other) = default; @@ -39,7 +39,7 @@ struct fn_evaluator { }; /// @brief utility class to evaluate function_item objects. -class function_item_evaluator { +class IFC_GEOM_API function_item_evaluator { public: function_item_evaluator(const ifcopenshell::geometry::Settings& settings, taxonomy::function_item::const_ptr fn); function_item_evaluator(const function_item_evaluator& other); diff --git a/src/ifcgeom/hybrid_kernel.cpp b/src/ifcgeom/hybrid_kernel.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/ifcgeom/hybrid_kernel.h b/src/ifcgeom/hybrid_kernel.h new file mode 100644 index 0000000000..dfe7cd200d --- /dev/null +++ b/src/ifcgeom/hybrid_kernel.h @@ -0,0 +1,239 @@ +/******************************************************************************** + * * + * This file is part of IfcOpenShell. * + * * + * IfcOpenShell is free software: you can redistribute it and/or modify * + * it under the terms of the Lesser GNU General Public License as published by * + * the Free Software Foundation, either version 3.0 of the License, or * + * (at your option) any later version. * + * * + * IfcOpenShell is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * Lesser GNU General Public License for more details. * + * * + * You should have received a copy of the Lesser GNU General Public License * + * along with this program. If not, see . * + * * + ********************************************************************************/ + +#ifndef HYBRID_KERNEL_H +#define HYBRID_KERNEL_H + +#include "AbstractKernel.h" + +#ifdef IFOPSH_WITH_OPENCASCADE +#include "../ifcgeom/kernels/opencascade/OpenCascadeKernel.h" +#undef Handle +#endif + +#ifdef IFOPSH_WITH_CGAL +#include "../ifcgeom/kernels/cgal/CgalKernel.h" +#undef CGAL_KERNEL_H +#undef CGALCONVERSIONRESULT_H +#define IFOPSH_SIMPLE_KERNEL +#include "../ifcgeom/kernels/cgal/CgalKernel.h" +#undef CgalKernel +#endif + +namespace { + inline bool is_valid_for_kernel(const ifcopenshell::geometry::kernels::AbstractKernel* k, const IfcGeom::ConversionResult& shp) { +#ifdef IFOPSH_WITH_OPENCASCADE + if (k->geometry_library() == "opencascade") { + return dynamic_cast(shp.Shape().get()) != nullptr; + } +#endif +#ifdef IFOPSH_WITH_CGAL + if (k->geometry_library() == "cgal-simple") { + return dynamic_cast(shp.Shape().get()) != nullptr; + } + if (k->geometry_library() == "cgal") { + return dynamic_cast(shp.Shape().get()) != nullptr; + } +#endif + return false; + } +} + +namespace ifcopenshell { + namespace geometry { + namespace kernels { + + class HybridKernel : public ifcopenshell::geometry::kernels::AbstractKernel { + std::vector> kernels_; + ifcopenshell::geometry::abstract_mapping* mapping_; + IfcParse::IfcFile* file_; + public: + HybridKernel(const std::string& name, IfcParse::IfcFile* file, Settings& settings, std::vector>&& kernels) + : AbstractKernel(name, settings) + , kernels_(std::move(kernels)) + , mapping_(ifcopenshell::geometry::impl::mapping_implementations().construct(file, settings)) + , file_(file) + { + } + virtual bool supports_boolean_operations() const + { + for (auto& k : kernels_) { + if (k->supports_boolean_operations()) { + return true; + } + } + return false; + } + virtual bool convert(const taxonomy::ptr item, IfcGeom::ConversionResults& rs) + { + auto ops = mapping_->find_openings(item->instance->as()); + bool has_openings = ops && ops->size(); + for (auto& k : kernels_) { +#ifdef IFOPSH_WITH_CGAL + if (has_openings && !k->supports_boolean_operations()) { + // @todo this would fail later on in the find_openings() call, because we have a + // SimpleCgalShape which cannot be used on a kernel that supports booleans. + // @todo 1 implement the translation between various conversion result shapes + // @todo 2 fold the boolean result openings into the taxonomy item. This should be possible + // now that we have shared_ptr and caching in place. So the inability + // to instance wouldn't matter as much. + continue; + } +#endif + bool success = false; + try { + success = k->convert(item, rs); + } catch (...) {} + if (success) { + return true; + } + } + return false; + } + virtual bool apply_layerset(IfcGeom::ConversionResults& items, const ifcopenshell::geometry::layerset_information& layers) + { + for (auto& k : kernels_) { + bool success = false; + try { + success = k->apply_layerset(items, layers); + } catch (...) {} + if (success) { + return true; + } + } + return false; + } + virtual bool apply_folded_layerset(IfcGeom::ConversionResults& items, const ifcopenshell::geometry::layerset_information& layers, const std::map& folds) + { + for (auto& k : kernels_) { + bool success = false; + try { + success = k->apply_folded_layerset(items, layers, folds); + } catch (...) {} + if (success) { + return true; + } + } + return false; + } + 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) + { + for (auto& k : kernels_) { + bool is_valid = true; + for (auto& s : entity_shapes) { + if (!is_valid_for_kernel(k.get(), s)) { + is_valid = false; + break; + } + } + if (!is_valid) { + continue; + } + bool success = false; + try { + success = k->convert_openings(entity, openings, entity_shapes, entity_trsf, cut_shapes); + } catch (...) {} + if (success) { + return true; + } + } + return false; + } + virtual AbstractKernel* clone() const + { + std::vector> ks; + for (auto& k : kernels_) { + ks.emplace_back(k->clone()); + } + // @todo ugly + return new HybridKernel(geometry_library(), file_, const_cast(settings()), std::move(ks)); + } + }; + + inline std::unique_ptr construct(IfcParse::IfcFile* file, const std::string& geometry_library, Settings& conv_settings) { + std::string geometry_library_lower = boost::to_lower_copy(geometry_library); + +#ifdef IFOPSH_WITH_OPENCASCADE + if (geometry_library_lower == "opencascade") { + return std::make_unique(conv_settings); + } +#endif + +#ifdef IFOPSH_WITH_CGAL + if (geometry_library_lower == "cgal") { + return std::make_unique(conv_settings); + } + + if (geometry_library_lower == "cgal-simple") { + return std::make_unique(conv_settings); + } +#endif + + if (geometry_library_lower.rfind("hybrid-", 0) == 0) { + geometry_library_lower = geometry_library_lower.substr(strlen("hybrid")); + std::vector> kernels; + while (!geometry_library_lower.empty()) { + if (geometry_library_lower.find("-", 0) == 0) { + geometry_library_lower = geometry_library_lower.substr(strlen("-")); + } else { + throw IfcParse::IfcException("Invalid hybrid kernel " + geometry_library); + } + auto n = kernels.size(); +#ifdef IFOPSH_WITH_OPENCASCADE + if (geometry_library_lower.find("opencascade", 0) == 0) { + kernels.emplace_back(new IfcGeom::OpenCascadeKernel(conv_settings)); + geometry_library_lower = geometry_library_lower.substr(strlen("opencascade")); + } +#endif + +#ifdef IFOPSH_WITH_CGAL + if (geometry_library_lower.find("cgal-simple", 0) == 0) { + kernels.emplace_back(new SimpleCgalKernel(conv_settings)); + geometry_library_lower = geometry_library_lower.substr(strlen("cgal-simple")); + } + + if (geometry_library_lower.find("cgal", 0) == 0) { + kernels.emplace_back(new CgalKernel(conv_settings)); + geometry_library_lower = geometry_library_lower.substr(strlen("cgal")); + } +#endif + if (kernels.size() != n + 1) { + throw IfcParse::IfcException("Invalid hybrid kernel " + geometry_library); + } + } + + for (auto it = kernels.begin(); it != kernels.end(); ++it) { + (**it).propagate_exceptions = it == kernels.begin(); + (**it).partial_success_is_success = it == kernels.end() - 1; + } + + if (!kernels.empty()) { + return std::make_unique(geometry_library, file, conv_settings, std::move(kernels)); + } + } + + throw IfcParse::IfcException("No geometry kernel registered for " + geometry_library); + } + + } + } +} + +#endif \ No newline at end of file diff --git a/src/ifcgeom/infra_sweep_helper.h b/src/ifcgeom/infra_sweep_helper.h index bacc4bd4f0..a14d655094 100644 --- a/src/ifcgeom/infra_sweep_helper.h +++ b/src/ifcgeom/infra_sweep_helper.h @@ -4,11 +4,13 @@ #include "taxonomy.h" #include "ConversionSettings.h" +#include "ifc_geom_api.h" + namespace ifcopenshell { namespace geometry { - struct cross_section { + struct IFC_GEOM_API cross_section { double dist_along; taxonomy::geom_item::ptr section_geometry; Eigen::Vector3d offset; @@ -19,7 +21,7 @@ namespace ifcopenshell { } }; - taxonomy::loft::ptr make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::function_item::ptr& directrix, std::vector& cross_sections); + IFC_GEOM_API taxonomy::loft::ptr make_loft(const Settings& settings_, const IfcUtil::IfcBaseClass* inst, const taxonomy::function_item::ptr& directrix, std::vector& cross_sections); } } diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index ef2842107e..76c4219ae0 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "../../../ifcparse/IfcLogger.h" #include "../../../ifcgeom/IfcGeomRepresentation.h" @@ -19,6 +21,10 @@ using ifcopenshell::geometry::NumberEpeck; #define NumberType NumberEpeck #endif +#ifdef IFOPSH_SIMPLE_KERNEL +#define CgalShape SimpleCgalShape +#endif + typedef CGAL::Polyhedron_3 Polyhedron; typedef Polyhedron::Facet_const_handle Facet_const_handle; typedef Polyhedron::Halfedge_around_facet_const_circulator Halfedge_around_facet_circulator; @@ -701,6 +707,43 @@ ConversionResultShape* ifcopenshell::geometry::CgalShape::intersect(ConversionRe #endif } +namespace { + template + void concatenate_polyhedra(Polyhedron& p1, const Polyhedron& p2) { + std::vector points1, points2; + std::vector> faces1, faces2; + + // Extract soups + CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(p1, points1, faces1); + CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(p2, points2, faces2); + + // Offset indices in faces2 by current number of points in points1 + std::size_t offset = points1.size(); + for (auto& f : faces2) { + for (auto& idx : f) { + idx += offset; + } + } + + // Merge soups + points1.insert(points1.end(), points2.begin(), points2.end()); + faces1.insert(faces1.end(), faces2.begin(), faces2.end()); + + // Build merged polyhedron + Polyhedron merged; + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points1, faces1, merged); + + p1 = std::move(merged); + } +} + +ConversionResultShape* ifcopenshell::geometry::CgalShape::concat(ConversionResultShape* other) +{ + auto shp = poly(); + concatenate_polyhedra(shp, ((CgalShape*)other)->poly()); + return new CgalShape(shp); +} + std::pair, OpaqueCoordinate<3>> ifcopenshell::geometry::CgalShape::bounding_box() const { throw std::runtime_error("Not implemented"); @@ -736,6 +779,11 @@ void ifcopenshell::geometry::CgalShape::map(const std::vector shape_; @@ -250,17 +252,20 @@ namespace ifcopenshell { namespace geometry { virtual ConversionResultShape* add(ConversionResultShape*); virtual ConversionResultShape* subtract(ConversionResultShape*); virtual ConversionResultShape* intersect(ConversionResultShape*); + virtual ConversionResultShape* concat(ConversionResultShape*); virtual void map(OpaqueCoordinate<4>& from, OpaqueCoordinate<4>& to); virtual void map(const std::vector>& from, const std::vector>& to); virtual ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const; + virtual bool surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const; + bool convex_tag() const { return convex_tag_; } bool& convex_tag() { return convex_tag_; } }; #ifndef IFOPSH_SIMPLE_KERNEL - class CgalShapeHalfSpaceDecomposition : public IfcGeom::ConversionResultShape { + class IFC_GEOMLIBRARY_API CgalShapeHalfSpaceDecomposition : public IfcGeom::ConversionResultShape { private: std::unique_ptr> shape_; std::list> planes_; @@ -315,12 +320,23 @@ namespace ifcopenshell { namespace geometry { virtual ConversionResultShape* add(ConversionResultShape*); virtual ConversionResultShape* subtract(ConversionResultShape*); virtual ConversionResultShape* intersect(ConversionResultShape*); + virtual ConversionResultShape* concat(ConversionResultShape*) { + return nullptr; + } virtual void map(OpaqueCoordinate<4>& from, OpaqueCoordinate<4>& to); virtual void map(const std::vector>& from, const std::vector>& to); virtual ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const; + + virtual bool surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const { + return false; + } }; #endif }} +#ifdef IFOPSH_SIMPLE_KERNEL +#undef CgalShape +#endif + #endif diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 190bddb852..a2d4d01ebc 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -24,6 +24,10 @@ #include "../../../ifcparse/IfcLogger.h" #include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" +#ifdef IFOPSH_SIMPLE_KERNEL +#define CgalShape SimpleCgalShape +#endif + #include #include diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index eb1c91e605..ce6efbb2aa 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -47,6 +47,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include "../../../ifcgeom/IfcGeomElement.h" #include "../../../ifcgeom/kernels/cgal/CgalConversionResult.h" +#include "../../../ifcgeom/kernels/ifc_geomlibrary_api.h" #include @@ -55,20 +56,20 @@ if ( it != cache.T.end() ) { e = it->second; return true; } namespace ifcopenshell { namespace geometry { namespace utils { - IFC_GEOM_API CGAL::Polyhedron_3 create_cube(double d); - IFC_GEOM_API CGAL::Polyhedron_3 create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper); - IFC_GEOM_API CGAL::Polyhedron_3 create_polyhedron(std::list &face_list, bool stitch_borders = false); + IFC_GEOMLIBRARY_API CGAL::Polyhedron_3 create_cube(double d); + IFC_GEOMLIBRARY_API CGAL::Polyhedron_3 create_cube(const Kernel_::Point_3& lower, const Kernel_::Point_3& upper); + IFC_GEOMLIBRARY_API CGAL::Polyhedron_3 create_polyhedron(std::list &face_list, bool stitch_borders = false); #ifndef IFOPSH_SIMPLE_KERNEL - IFC_GEOM_API CGAL::Polyhedron_3 create_polyhedron(const CGAL::Nef_polyhedron_3 &nef_polyhedron); - IFC_GEOM_API CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); - IFC_GEOM_API CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); + IFC_GEOMLIBRARY_API CGAL::Polyhedron_3 create_polyhedron(const CGAL::Nef_polyhedron_3 &nef_polyhedron); + IFC_GEOMLIBRARY_API CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); + IFC_GEOMLIBRARY_API CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); #endif } namespace kernels { - class IFC_GEOM_API CgalKernel : public AbstractKernel { + class IFC_GEOMLIBRARY_API CgalKernel : public AbstractKernel { private: #ifndef IFOPSH_SIMPLE_KERNEL enum boolean_operand_preprocess { @@ -94,6 +95,18 @@ namespace ifcopenshell { : AbstractKernel("cgal", settings) {} + virtual AbstractKernel* clone() const { + return new CgalKernel(settings()); + } + + virtual bool supports_boolean_operations() const { +#ifndef IFOPSH_SIMPLE_KERNEL + return true; +#else + return false; +#endif + } + bool convert(const taxonomy::extrusion::ptr, cgal_shape_t&); bool convert(const taxonomy::face::ptr, std::list&); bool convert(const taxonomy::loop::ptr, cgal_wire_t&); diff --git a/src/ifcgeom/kernels/ifc_geomlibrary_api.h b/src/ifcgeom/kernels/ifc_geomlibrary_api.h new file mode 100644 index 0000000000..61ba3c3b20 --- /dev/null +++ b/src/ifcgeom/kernels/ifc_geomlibrary_api.h @@ -0,0 +1,37 @@ +/******************************************************************************** +* * +* This file is part of IfcOpenShell. * +* * +* IfcOpenShell is free software: you can redistribute it and/or modify * +* it under the terms of the Lesser GNU General Public License as published by * +* the Free Software Foundation, either version 3.0 of the License, or * +* (at your option) any later version. * +* * +* IfcOpenShell is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* Lesser GNU General Public License for more details. * +* * +* You should have received a copy of the Lesser GNU General Public License * +* along with this program. If not, see . * +* * +********************************************************************************/ + +#ifndef IFC_GEOMLIBRARY_API_H +#define IFC_GEOMLIBRARY_API_H + +#ifdef IFC_SHARED_BUILD +#ifdef _WIN32 +#ifdef IFC_GEOMLIBRARY_EXPORTS +#define IFC_GEOMLIBRARY_API __declspec(dllexport) +#else +#define IFC_GEOMLIBRARY_API __declspec(dllimport) +#endif +#else // simply assume *nix + GCC-like compiler +#define IFC_GEOMLIBRARY_API __attribute__((visibility("default"))) +#endif +#else +#define IFC_GEOMLIBRARY_API +#endif + +#endif diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index 2e8b900dc1..997391fcd6 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -25,6 +25,7 @@ #include "../../../ifcgeom/IfcGeomElement.h" #include "../../../ifcgeom/Iterator.h" #include "OpenCascadeConversionResult.h" +#include "OpenCascadeKernel.h" #include "base_utils.h" #include @@ -1503,7 +1504,7 @@ namespace IfcGeom { settings_.get().value = true; settings_.get().value = true; - IfcGeom::Iterator it(settings_, &f, {}, 1); + IfcGeom::Iterator it(std::unique_ptr(new OpenCascadeKernel(settings_)), settings_, &f, {}, 1); add_file(it); } diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp index d0a91dadf2..72f663b3ec 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "OpenCascadeConversionResult.h" @@ -546,6 +548,26 @@ ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::intersect(Conve return boolean_op(BOPAlgo_COMMON, shape_, ((ifcopenshell::geometry::OpenCascadeShape*)other)->shape_); } +ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::concat(ConversionResultShape* other) +{ + TopoDS_Compound compound; + BRep_Builder builder; + + auto& left = shape_; + auto& right = ((ifcopenshell::geometry::OpenCascadeShape*)other)->shape_; + + if (left.ShapeType() == TopAbs_COMPOUND) { + compound = TopoDS::Compound(left); + } else { + builder.MakeCompound(compound); + builder.Add(compound, left); + } + + builder.Add(compound, right); + + return new OpenCascadeShape(std::move(compound)); +} + std::pair, OpaqueCoordinate<3>> ifcopenshell::geometry::OpenCascadeShape::bounding_box() const { throw std::runtime_error("Not implemented"); @@ -556,6 +578,113 @@ ConversionResultShape* ifcopenshell::geometry::OpenCascadeShape::moved(ifcopensh return new OpenCascadeShape(IfcGeom::util::apply_transformation(shape_, *t)); } +namespace { + void accumulate(const gp_Ax3& ax, const gp_Dir& normal, double area, double& along_x, double& along_y, double& along_z) { + along_x += area * fabs(ax.XDirection().Dot(normal)); + along_y += area * fabs(ax.YDirection().Dot(normal)); + along_z += area * fabs(ax.Direction().Dot(normal)); + } + + void surface_area_along_direction_(double tol, const TopoDS_Shape& s, const gp_Ax3& ax, double& along_x, double& along_y, double& along_z) { + along_x = along_y = along_z = 0.; + + bool meshed = false; + + TopExp_Explorer exp(s, TopAbs_FACE); + for (; exp.More(); exp.Next()) { + const TopoDS_Face& face = TopoDS::Face(exp.Current()); + Handle(Geom_Surface) surf = BRep_Tool::Surface(face); + Handle(Geom_Plane) plane = Handle(Geom_Plane)::DownCast(surf); + + if (surf->DynamicType() == STANDARD_TYPE(Geom_Plane)) { + GProp_GProps prop_area; + BRepGProp::SurfaceProperties(face, prop_area); + const double area = prop_area.Mass(); + + accumulate(ax, plane->Position().Direction(), area, along_x, along_y, along_z); + } else { + + if (!meshed) { + try { + BRepMesh_IncrementalMesh(s, tol); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); + return; + } + meshed = true; + } + + TopLoc_Location loc; + Handle(Poly_Triangulation) tri = BRep_Tool::Triangulation(face, loc); + if (!tri.IsNull()) { + std::vector coords; + coords.reserve(tri->NbNodes()); + + for (int i = 1; i <= tri->NbNodes(); ++i) { + coords.push_back(tri->Node(i).Transformed(loc).XYZ()); + } + + const Poly_Array1OfTriangle& triangles = tri->Triangles(); + for (int i = 1; i <= triangles.Length(); ++i) { + int n1, n2, n3; + + if (face.Orientation() == TopAbs_REVERSED) { + triangles(i).Get(n3, n2, n1); + } else { + triangles(i).Get(n1, n2, n3); + } + + const gp_XYZ& pt1 = coords[n1 - 1]; + const gp_XYZ& pt2 = coords[n2 - 1]; + const gp_XYZ& pt3 = coords[n3 - 1]; + const gp_Vec v1 = pt2 - pt1; + const gp_Vec v2 = pt3 - pt2; + const gp_Vec v3 = pt1 - pt3; + const gp_Vec normal_vector = v1 ^ v2; + if (normal_vector.Magnitude() > 1.e-7) { + gp_Dir normal = gp_Dir(); + + double edge_lengths[3] = { v1.Magnitude(), v2.Magnitude(), v3.Magnitude() }; + std::sort(&edge_lengths[0], &edge_lengths[2]); + + const double& a = edge_lengths[0]; + const double& b = edge_lengths[1]; + const double& c = edge_lengths[2]; + + const double area = 0.25 * sqrt((a + (b + c)) * (c - (a - b)) * (c + (a - b)) * (a + (b - c))); + accumulate(ax, normal, area, along_x, along_y, along_z); + } + } + } + } + } + } +} + + +bool ifcopenshell::geometry::OpenCascadeShape::surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr& place, double& along_x, double& along_y, double& along_z) const +{ + gp_GTrsf trsf; + + if (place->components_) { + gp_Trsf tr; + const auto& m = place->ccomponents(); + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) + ); + trsf = tr; + } + + gp_Mat mat = trsf.Trsf().HVectorialPart(); + gp_Ax3 ax(trsf.TranslationPart(), mat.Column(3), mat.Column(1)); + + surface_area_along_direction_(tol, shape_, ax, along_x, along_y, along_z); + + return true; +} + void ifcopenshell::geometry::OpenCascadeShape::map(OpaqueCoordinate<4>&, OpaqueCoordinate<4>&) { throw std::runtime_error("Not implemented"); } diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h index 85a117f30e..e812c207fa 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h @@ -35,6 +35,7 @@ #include #include "../../../ifcgeom/ConversionResult.h" +#include "../../../ifcgeom/kernels/ifc_geomlibrary_api.h" namespace ifcopenshell { namespace geometry { @@ -42,7 +43,7 @@ namespace ifcopenshell { using IfcGeom::OpaqueCoordinate; using IfcGeom::OpaqueNumber; - class OpenCascadeShape : public IfcGeom::ConversionResultShape { + class IFC_GEOMLIBRARY_API OpenCascadeShape : public IfcGeom::ConversionResultShape { public: OpenCascadeShape(const TopoDS_Shape& shape) : shape_(shape) {} @@ -97,10 +98,13 @@ namespace ifcopenshell { virtual ConversionResultShape* add(ConversionResultShape*); virtual ConversionResultShape* subtract(ConversionResultShape*); virtual ConversionResultShape* intersect(ConversionResultShape*); + virtual ConversionResultShape* concat(ConversionResultShape*); virtual void map(OpaqueCoordinate<4>& from, OpaqueCoordinate<4>& to); virtual void map(const std::vector>& from, const std::vector>& to); virtual ConversionResultShape* moved(ifcopenshell::geometry::taxonomy::matrix4::ptr) const; + + virtual bool surface_area_along_direction(double tol, const ifcopenshell::geometry::taxonomy::matrix4::ptr&, double& along_x, double& along_y, double& along_z) const; private: TopoDS_Shape shape_; }; diff --git a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h index b21e424934..61b1a2c548 100644 --- a/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h +++ b/src/ifcgeom/kernels/opencascade/OpenCascadeKernel.h @@ -51,14 +51,14 @@ #include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h" -#include "../../../ifcgeom/ifc_geom_api.h" +#include "../../../ifcgeom/kernels/ifc_geomlibrary_api.h" #include "../../../ifcgeom/taxonomy.h" #include "../../../ifcgeom/ConversionSettings.h" namespace IfcGeom { -class IFC_GEOM_API OpenCascadeKernel : public ifcopenshell::geometry::kernels::AbstractKernel { +class IFC_GEOMLIBRARY_API OpenCascadeKernel : public ifcopenshell::geometry::kernels::AbstractKernel { private: /* @@ -103,6 +103,12 @@ public: , precision_(settings.get().get()) {} + virtual AbstractKernel* clone() const { + return new OpenCascadeKernel(settings()); + } + + virtual bool supports_boolean_operations() const { return true; } + bool convert(const ifcopenshell::geometry::taxonomy::extrusion::ptr, TopoDS_Shape&); bool convert(const ifcopenshell::geometry::taxonomy::face::ptr, TopoDS_Shape&, bool reversed_surface = false); bool convert(const ifcopenshell::geometry::taxonomy::loop::ptr, TopoDS_Wire&); diff --git a/src/ifcgeom/kernels/opencascade/base_utils.cpp b/src/ifcgeom/kernels/opencascade/base_utils.cpp index 7f56792d14..273b5dd79f 100644 --- a/src/ifcgeom/kernels/opencascade/base_utils.cpp +++ b/src/ifcgeom/kernels/opencascade/base_utils.cpp @@ -4,6 +4,8 @@ #include "OpenCascadeConversionResult.h" #include "boolean_utils.h" +#include + #include #include #include @@ -48,6 +50,8 @@ #include +#include + // For axis placements detect equality early in order for the // relatively computionaly expensive gp_Trsf calculation to be skipped bool IfcGeom::util::axis_equal(const gp_Ax3 & a, const gp_Ax3 & b, double tolerance) { @@ -297,18 +301,52 @@ TopoDS_Shape IfcGeom::util::apply_transformation(const TopoDS_Shape& s, const gp } } +namespace { + bool is_non_uniform(const Eigen::Matrix4d& M, double eps = 1e-6) + { + Eigen::Matrix3d L = M.block<3, 3>(0, 0); + double sx = L.col(0).norm(); + double sy = L.col(1).norm(); + double sz = L.col(2).norm(); + return !( + std::abs(sx - sy) < eps && + std::abs(sx - sz) < eps && + std::abs(sy - sz) < eps + ); + } +} + TopoDS_Shape IfcGeom::util::apply_transformation(const TopoDS_Shape& s, const ifcopenshell::geometry::taxonomy::matrix4& t) { - // @todo this probably discards non-uniform scale? + gp_GTrsf trsf; if (t.components_) { - gp_Trsf tr; const auto& m = t.ccomponents(); - tr.SetValues( - m(0, 0), m(0, 1), m(0, 2), m(0, 3), - m(1, 0), m(1, 1), m(1, 2), m(1, 3), - m(2, 0), m(2, 1), m(2, 2), m(2, 3) - ); - trsf = tr; + // This is either a bug or very finicky, but this appears to be the only + // way to get the transformation metadata to line up. + // + // - If gp_GTrsf.form is other, applying the transformation will result in + // a conversion to b-spline surfaces for about everything, which impacts + // performance and breaks detection of view volume in the svg serializer, + // which would be the case when setting the SetVectorialPart() block + // unconditionally. + // (calling SetForm() afterwards to detect CompoundTrsf over Other would + // set Scale to zero (bug?)) + if (is_non_uniform(m)) { + trsf.SetVectorialPart(gp_Mat( + m(0, 0), m(0, 1), m(0, 2), + m(1, 0), m(1, 1), m(1, 2), + m(2, 0), m(2, 1), m(2, 2) + )); + trsf.SetTranslationPart(gp_XYZ(m(0, 3), m(1, 3), m(2, 3))); + } else { + gp_Trsf tr; + tr.SetValues( + m(0, 0), m(0, 1), m(0, 2), m(0, 3), + m(1, 0), m(1, 1), m(1, 2), m(1, 3), + m(2, 0), m(2, 1), m(2, 2), m(2, 3) + ); + trsf = tr; + } } return apply_transformation(s, trsf); } @@ -864,3 +902,17 @@ bool IfcGeom::util::validate_shape(const TopoDS_Shape& s) { return false; } + +TopoDS_Shape IfcGeom::util::unify(const TopoDS_Shape& s, double tolerance) { + tolerance = (std::min)(min_edge_length(s) / 2., tolerance); + ShapeUpgrade_UnifySameDomain usd(s); +#if OCC_VERSION_HEX >= 0x70200 + usd.SetSafeInputMode(true); +#endif +#if OCC_VERSION_HEX >= 0x70100 + usd.SetLinearTolerance(tolerance); + usd.SetAngularTolerance(1.e-3); +#endif + usd.Build(); + return usd.Shape(); +} diff --git a/src/ifcgeom/kernels/opencascade/base_utils.h b/src/ifcgeom/kernels/opencascade/base_utils.h index 7e342df27c..bd74485ded 100644 --- a/src/ifcgeom/kernels/opencascade/base_utils.h +++ b/src/ifcgeom/kernels/opencascade/base_utils.h @@ -2,6 +2,7 @@ #define BASE_UTILS_H #include "../../../ifcgeom/ConversionResult.h" +#include "../ifc_geomlibrary_api.h" #include #include @@ -25,58 +26,60 @@ namespace IfcGeom { namespace util { - int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique = false); - int surface_genus(const TopoDS_Shape&); + IFC_GEOMLIBRARY_API int count(const TopoDS_Shape&, TopAbs_ShapeEnum, bool unique = false); + IFC_GEOMLIBRARY_API int surface_genus(const TopoDS_Shape&); - bool is_manifold(const TopoDS_Shape& a); + IFC_GEOMLIBRARY_API bool is_manifold(const TopoDS_Shape& a); // For axis placements detect equality early in order for the // relatively computionaly expensive gp_Trsf calculation to be skipped - bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance); + IFC_GEOMLIBRARY_API bool axis_equal(const gp_Ax3& a, const gp_Ax3& b, double tolerance); - bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance); + IFC_GEOMLIBRARY_API bool axis_equal(const gp_Ax2d& a, const gp_Ax2d& b, double tolerance); - bool is_identity(const gp_Trsf2d& t, double tolerance); - bool is_identity(const gp_GTrsf2d& t, double tolerance); - bool is_identity(const gp_Trsf& t, double tolerance); - bool is_identity(const gp_GTrsf& t, double tolerance); + IFC_GEOMLIBRARY_API bool is_identity(const gp_Trsf2d& t, double tolerance); + IFC_GEOMLIBRARY_API bool is_identity(const gp_GTrsf2d& t, double tolerance); + IFC_GEOMLIBRARY_API bool is_identity(const gp_Trsf& t, double tolerance); + IFC_GEOMLIBRARY_API bool is_identity(const gp_GTrsf& t, double tolerance); - gp_Trsf combine_offset_and_rotation(const gp_Vec &offset, const gp_Quaternion& rotation); + IFC_GEOMLIBRARY_API gp_Trsf combine_offset_and_rotation(const gp_Vec &offset, const gp_Quaternion& rotation); - bool is_nested_compound_of_solid(const TopoDS_Shape& s, int depth = 0); + IFC_GEOMLIBRARY_API bool is_nested_compound_of_solid(const TopoDS_Shape& s, int depth = 0); // Creates a solid from a compound of faces. When there are multiple connected components, // a compound of solids is returned. - bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid, double tol); - bool shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li); - bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid, double tol, bool force_sewing = false); - bool is_compound(const TopoDS_Shape& shape); - bool is_convex(const TopoDS_Wire& wire, double tol); - TopoDS_Shape halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent); - gp_Pln plane_from_face(const TopoDS_Face& face); - gp_Pnt point_above_plane(const gp_Pln& pln, bool agree = true); + IFC_GEOMLIBRARY_API bool create_solid_from_compound(const TopoDS_Shape& compound, TopoDS_Shape& solid, double tol); + IFC_GEOMLIBRARY_API bool shape_to_face_list(const TopoDS_Shape& s, TopTools_ListOfShape& li); + IFC_GEOMLIBRARY_API bool create_solid_from_faces(const TopTools_ListOfShape& face_list, TopoDS_Shape& solid, double tol, bool force_sewing = false); + IFC_GEOMLIBRARY_API bool is_compound(const TopoDS_Shape& shape); + IFC_GEOMLIBRARY_API bool is_convex(const TopoDS_Wire& wire, double tol); + IFC_GEOMLIBRARY_API TopoDS_Shape halfspace_from_plane(const gp_Pln& pln, const gp_Pnt& cent); + IFC_GEOMLIBRARY_API gp_Pln plane_from_face(const TopoDS_Face& face); + IFC_GEOMLIBRARY_API gp_Pnt point_above_plane(const gp_Pln& pln, bool agree = true); - bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height, double tol); - const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&); - const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&); - const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&); - bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&); - bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&); - bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector&); - bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair >&); - bool closest(const gp_Pnt&, const std::vector&, gp_Pnt&); - bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d); - bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1); + IFC_GEOMLIBRARY_API bool fit_halfspace(const TopoDS_Shape& a, const TopoDS_Shape& b, TopoDS_Shape& box, double& height, double tol); + IFC_GEOMLIBRARY_API const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const Handle_Geom_Surface&); + IFC_GEOMLIBRARY_API const Handle_Geom_Curve intersect(const Handle_Geom_Surface&, const TopoDS_Face&); + IFC_GEOMLIBRARY_API const Handle_Geom_Curve intersect(const TopoDS_Face&, const Handle_Geom_Surface&); + IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Curve&, const Handle_Geom_Surface&, gp_Pnt&); + IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Curve&, const TopoDS_Face&, gp_Pnt&); + IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Curve&, const TopoDS_Shape&, std::vector&); + IFC_GEOMLIBRARY_API bool intersect(const Handle_Geom_Surface&, const TopoDS_Shape&, std::vector< std::pair >&); + IFC_GEOMLIBRARY_API bool closest(const gp_Pnt&, const std::vector&, gp_Pnt&); + IFC_GEOMLIBRARY_API bool project(const Handle_Geom_Curve&, const gp_Pnt&, gp_Pnt& p, double& u, double& d); + IFC_GEOMLIBRARY_API bool project(const Handle_Geom_Surface&, const TopoDS_Shape&, double& u1, double& v1, double& u2, double& v2, double widen = 0.1); - double shape_volume(const TopoDS_Shape& s); - double face_area(const TopoDS_Face& f); + IFC_GEOMLIBRARY_API double shape_volume(const TopoDS_Shape& s); + IFC_GEOMLIBRARY_API double face_area(const TopoDS_Face& f); - TopoDS_Shape apply_transformation(const TopoDS_Shape&, const ifcopenshell::geometry::taxonomy::matrix4& t); - TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&); - TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&); + IFC_GEOMLIBRARY_API TopoDS_Shape apply_transformation(const TopoDS_Shape&, const ifcopenshell::geometry::taxonomy::matrix4& t); + IFC_GEOMLIBRARY_API TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_Trsf&); + IFC_GEOMLIBRARY_API TopoDS_Shape apply_transformation(const TopoDS_Shape&, const gp_GTrsf&); - bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, bool create_shell, double tol); - bool validate_shape(const TopoDS_Shape&); + IFC_GEOMLIBRARY_API bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, bool create_shell, double tol); + IFC_GEOMLIBRARY_API bool validate_shape(const TopoDS_Shape&); + + IFC_GEOMLIBRARY_API TopoDS_Shape unify(const TopoDS_Shape& s, double tolerance); } } diff --git a/src/ifcgeom/kernels/opencascade/boolean_utils.cpp b/src/ifcgeom/kernels/opencascade/boolean_utils.cpp index 6fa4f6ef54..56f9cdf918 100644 --- a/src/ifcgeom/kernels/opencascade/boolean_utils.cpp +++ b/src/ifcgeom/kernels/opencascade/boolean_utils.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -575,20 +574,6 @@ int IfcGeom::util::eliminate_touching_operands(double prec, const TopoDS_Shape & return N; } -TopoDS_Shape IfcGeom::util::unify(const TopoDS_Shape & s, double tolerance) { - tolerance = (std::min)(min_edge_length(s) / 2., tolerance); - ShapeUpgrade_UnifySameDomain usd(s); -#if OCC_VERSION_HEX >= 0x70200 - usd.SetSafeInputMode(true); -#endif -#if OCC_VERSION_HEX >= 0x70100 - usd.SetLinearTolerance(tolerance); - usd.SetAngularTolerance(1.e-3); -#endif - usd.Build(); - return usd.Shape(); -} - bool IfcGeom::util::boolean_subtraction_2d_using_builder(const TopoDS_Shape & a_input, const TopTools_ListOfShape & b_input, TopoDS_Shape & result, double eps) { IfcGeom::impl::tree edge_tree; diff --git a/src/ifcgeom/kernels/opencascade/boolean_utils.h b/src/ifcgeom/kernels/opencascade/boolean_utils.h index 24b5d8587e..80a9b49998 100644 --- a/src/ifcgeom/kernels/opencascade/boolean_utils.h +++ b/src/ifcgeom/kernels/opencascade/boolean_utils.h @@ -30,6 +30,8 @@ #include #include +#include "../ifc_geomlibrary_api.h" + namespace IfcGeom { namespace util { @@ -83,8 +85,6 @@ namespace IfcGeom { int eliminate_narrow_operands(double prec, const TopTools_ListOfShape& bs, TopTools_ListOfShape & c); - TopoDS_Shape unify(const TopoDS_Shape& s, double tolerance); - bool boolean_subtraction_2d_using_builder(const TopoDS_Shape& a_input, const TopTools_ListOfShape& b_input, TopoDS_Shape& result, double eps); struct boolean_settings { diff --git a/src/ifcgeom/kernels/opencascade/clash_utils.h b/src/ifcgeom/kernels/opencascade/clash_utils.h index 9023dec96b..d10f703b7f 100644 --- a/src/ifcgeom/kernels/opencascade/clash_utils.h +++ b/src/ifcgeom/kernels/opencascade/clash_utils.h @@ -3,27 +3,29 @@ #include #include -struct ray { +#include "../ifc_geomlibrary_api.h" + +struct IFC_GEOMLIBRARY_API ray { float origin[3]; float dir[3]; float dir_inv[3]; }; -struct box { +struct IFC_GEOMLIBRARY_API box { float corners[2][3]; }; -bool is_intersect_ray_box(const struct ray *ray, const struct box *box); +IFC_GEOMLIBRARY_API bool is_intersect_ray_box(const struct ray *ray, const struct box *box); -bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir, +IFC_GEOMLIBRARY_API bool intersectRayTriangle( const gp_Vec& orig, const gp_Vec& dir, const gp_Vec& vert0, const gp_Vec& vert1, const gp_Vec& vert2, Standard_Real& at, Standard_Real& au, Standard_Real& av, bool cull, float enlarge=0.0f); -void edgeEdgeDist(gp_Vec& x, gp_Vec& y, // closest points +IFC_GEOMLIBRARY_API void edgeEdgeDist(gp_Vec& x, gp_Vec& y, // closest points const gp_Vec& p, const gp_Vec& a, // seg 1 origin, vector const gp_Vec& q, const gp_Vec& b); // seg 2 origin, vector -float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array p, const std::array q); +IFC_GEOMLIBRARY_API float distanceTriangleTriangleSquared(gp_Vec& cp, gp_Vec& cq, const std::array p, const std::array q); -bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, const gp_Vec& a2, const gp_Vec& b2, const gp_Vec& c2/*, Segment* intersection*/, gp_Vec& int1, gp_Vec& int2, bool ignoreCoplanar); +IFC_GEOMLIBRARY_API bool trianglesIntersect(const gp_Vec& a1, const gp_Vec& b1, const gp_Vec& c1, const gp_Vec& a2, const gp_Vec& b2, const gp_Vec& c2/*, Segment* intersection*/, gp_Vec& int1, gp_Vec& int2, bool ignoreCoplanar); diff --git a/src/ifcgeom/kernels/opencascade/wire_utils.h b/src/ifcgeom/kernels/opencascade/wire_utils.h index 582cc46a64..146734662b 100644 --- a/src/ifcgeom/kernels/opencascade/wire_utils.h +++ b/src/ifcgeom/kernels/opencascade/wire_utils.h @@ -1,6 +1,8 @@ #ifndef WIRE_UTILS_H #define WIRE_UTILS_H +#include "../ifc_geomlibrary_api.h" + #include #include @@ -17,9 +19,9 @@ namespace IfcGeom { namespace util { - bool approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps); + IFC_GEOMLIBRARY_API bool approximate_plane_through_wire(const TopoDS_Wire& wire, gp_Pln& plane, double eps); - bool flatten_wire(TopoDS_Wire& wire, double eps); + IFC_GEOMLIBRARY_API bool flatten_wire(TopoDS_Wire& wire, double eps); enum triangulate_wire_result { TRIANGULATE_WIRE_FAIL, @@ -35,25 +37,25 @@ namespace IfcGeom { }; /// Triangulate the set of wires. The firstmost wire is assumed to be the outer wire. - triangulate_wire_result triangulate_wire(const std::vector& wires, TopTools_ListOfShape& faces); + IFC_GEOMLIBRARY_API triangulate_wire_result triangulate_wire(const std::vector& wires, TopTools_ListOfShape& faces); - bool wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, const wire_tolerance_settings& settings); + IFC_GEOMLIBRARY_API bool wire_intersections(const TopoDS_Wire& wire, TopTools_ListOfShape& wires, const wire_tolerance_settings& settings); - void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest); + IFC_GEOMLIBRARY_API void select_largest(const TopTools_ListOfShape& shapes, TopoDS_Shape& largest); - bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face, const IfcGeom::util::wire_tolerance_settings& settings); + IFC_GEOMLIBRARY_API bool convert_wire_to_face(const TopoDS_Wire& wire, TopoDS_Face& face, const IfcGeom::util::wire_tolerance_settings& settings); - bool convert_wire_to_faces(const TopoDS_Wire& wire, TopoDS_Compound& face, const IfcGeom::util::wire_tolerance_settings& settings); + IFC_GEOMLIBRARY_API bool convert_wire_to_faces(const TopoDS_Wire& wire, TopoDS_Compound& face, const IfcGeom::util::wire_tolerance_settings& settings); - void assert_closed_wire(TopoDS_Wire& wire, double tol); + IFC_GEOMLIBRARY_API void assert_closed_wire(TopoDS_Wire& wire, double tol); - bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape, double tol); - void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol); - void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol); - bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); - void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); + IFC_GEOMLIBRARY_API bool fill_nonmanifold_wires_with_planar_faces(TopoDS_Shape& shape, double tol); + IFC_GEOMLIBRARY_API void remove_duplicate_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol); + IFC_GEOMLIBRARY_API void remove_collinear_points_from_loop(TColgp_SequenceOfPnt& polygon, bool closed, double tol); + IFC_GEOMLIBRARY_API bool wire_to_sequence_of_point(const TopoDS_Wire&, TColgp_SequenceOfPnt&); + IFC_GEOMLIBRARY_API void sequence_of_point_to_wire(const TColgp_SequenceOfPnt&, TopoDS_Wire&, bool closed); - bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire); + IFC_GEOMLIBRARY_API bool convert_curve_to_wire(const Handle(Geom_Curve)& curve, TopoDS_Wire& wire); } } diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 94e2e7bf52..9f74fca444 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -87,7 +87,7 @@ typedef item* ptr; \ typedef item const* ptr; #endif - class topology_error : public std::runtime_error { + class IFC_GEOM_API topology_error : public std::runtime_error { public: topology_error() : std::runtime_error("Generic topology error") {} topology_error(const char* const s) : std::runtime_error(s) {} @@ -138,9 +138,9 @@ typedef item const* ptr; STYLE }; - const std::string& kind_to_string(kinds k); + IFC_GEOM_API const std::string& kind_to_string(kinds k); - struct item { + struct IFC_GEOM_API item { private: uint32_t identity_; static std::atomic_uint32_t counter_; @@ -195,7 +195,7 @@ typedef item const* ptr; } template - struct eigen_base { + struct IFC_GEOM_API eigen_base { T* components_; eigen_base() { @@ -264,7 +264,7 @@ typedef item const* ptr; } }; - struct matrix4 : public item, public eigen_base { + struct IFC_GEOM_API matrix4 : public item, public eigen_base { private: void init(const Eigen::Vector3d& o, const Eigen::Vector3d& z, const Eigen::Vector3d& x) { auto Z = z.normalized(); @@ -319,10 +319,18 @@ typedef item const* ptr; return boost::hash{}(v); } + void pre_multiply_scale(double s) { + components().block<3, 4>(0, 0) *= s; + } + + void post_multiply_scale(double s) { + components().block<4, 3>(0, 0) *= s; + } + Eigen::Vector3d translation_part() const { return ccomponents().col(3).head<3>(); } }; - struct colour : public item, public eigen_base { + struct IFC_GEOM_API colour : public item, public eigen_base { DECLARE_PTR(colour) void print(std::ostream& o, int indent = 0) const; @@ -343,7 +351,7 @@ typedef item const* ptr; const double& b() const { return ccomponents()[2]; } }; - struct style : public item { + struct IFC_GEOM_API style : public item { DECLARE_PTR(style) std::string name; @@ -385,7 +393,7 @@ typedef item const* ptr; } }; - struct geom_item : public item { + struct IFC_GEOM_API geom_item : public item { DECLARE_PTR(geom_item) style::ptr surface_style; @@ -396,12 +404,12 @@ typedef item const* ptr; geom_item(matrix4::ptr m) : surface_style(nullptr), matrix(m) {} }; - struct implicit_item : public geom_item { + struct IFC_GEOM_API implicit_item : public geom_item { DECLARE_PTR(implicit_item) using geom_item::geom_item; }; - struct function_item : public implicit_item { + struct IFC_GEOM_API function_item : public implicit_item { DECLARE_PTR(function_item) function_item(const IfcUtil::IfcBaseInterface* instance = nullptr) : implicit_item(instance) {} @@ -422,7 +430,7 @@ typedef item const* ptr; }; }; - struct functor_item : public function_item { + struct IFC_GEOM_API functor_item : public function_item { DECLARE_PTR(functor_item) functor_item(double length, std::function fn, const IfcUtil::IfcBaseInterface* instance = nullptr) : function_item(instance), @@ -448,7 +456,7 @@ typedef item const* ptr; std::function fn_; }; - struct piecewise_function : public function_item { + struct IFC_GEOM_API piecewise_function : public function_item { DECLARE_PTR(piecewise_function) using spans_t = std::vector; @@ -480,7 +488,7 @@ typedef item const* ptr; spans_t spans_; }; - struct gradient_function : public function_item { + struct IFC_GEOM_API gradient_function : public function_item { DECLARE_PTR(gradient_function) gradient_function(piecewise_function::const_ptr horizontal, piecewise_function::const_ptr vertical, const IfcUtil::IfcBaseInterface* instance = nullptr); gradient_function(gradient_function&&) = default; @@ -506,7 +514,7 @@ typedef item const* ptr; piecewise_function::const_ptr horizontal_, vertical_; }; - struct cant_function : public function_item { + struct IFC_GEOM_API cant_function : public function_item { DECLARE_PTR(cant_function) cant_function(gradient_function::const_ptr gradient, piecewise_function::const_ptr cant, const IfcUtil::IfcBaseInterface* instance = nullptr); cant_function(cant_function&&) = default; @@ -533,7 +541,7 @@ typedef item const* ptr; piecewise_function::const_ptr cant_; }; - struct offset_function : public function_item { + struct IFC_GEOM_API offset_function : public function_item { DECLARE_PTR(offset_function) offset_function(function_item::const_ptr basis, piecewise_function::const_ptr offset, const IfcUtil::IfcBaseInterface* instance = nullptr); offset_function(offset_function&&) = default; @@ -585,7 +593,7 @@ typedef item const* ptr; } #endif - bool less(item::const_ptr, item::const_ptr); + IFC_GEOM_API bool less(item::const_ptr, item::const_ptr); struct less_functor { bool operator()(item::const_ptr a, item::const_ptr b) const { @@ -613,13 +621,13 @@ typedef item const* ptr; // @todo make 4d for easier multiplication template - struct cartesian_base : public item, public eigen_base { + struct IFC_GEOM_API cartesian_base : public item, public eigen_base { cartesian_base() : eigen_base() {} cartesian_base(const Eigen::Vector3d& c) : eigen_base(c) {} cartesian_base(double x, double y, double z = 0.) : eigen_base(Eigen::Vector3d(x, y, z)) {} }; - struct point3 : public cartesian_base<3> { + struct IFC_GEOM_API point3 : public cartesian_base<3> { DECLARE_PTR(point3) virtual point3* clone_() const { return new point3(*this); } @@ -637,7 +645,7 @@ typedef item const* ptr; point3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} }; - struct direction3 : public cartesian_base<3> { + struct IFC_GEOM_API direction3 : public cartesian_base<3> { DECLARE_PTR(direction3) virtual direction3* clone_() const { return new direction3(*this); } @@ -655,14 +663,14 @@ typedef item const* ptr; direction3(double x, double y, double z = 0.) : cartesian_base(x, y, z) {} }; - struct curve : public geom_item { + struct IFC_GEOM_API curve : public geom_item { void print_impl(std::ostream& o, const std::string& classname, int indent = 0) const { o << std::string(indent, ' ') << classname << std::endl; this->matrix->print(o, indent + 4); } }; - struct line : public curve { + struct IFC_GEOM_API line : public curve { DECLARE_PTR(line) virtual line* clone_() const { return new line(*this); } @@ -676,7 +684,7 @@ typedef item const* ptr; void print(std::ostream& o, int indent = 0) const; }; - struct circle : public curve { + struct IFC_GEOM_API circle : public curve { DECLARE_PTR(circle) double radius; @@ -720,7 +728,7 @@ typedef item const* ptr; } }; - struct ellipse : public curve { + struct IFC_GEOM_API ellipse : public curve { DECLARE_PTR(ellipse) double radius; @@ -737,7 +745,7 @@ typedef item const* ptr; void print(std::ostream& o, int indent = 0) const; }; - struct bspline_curve : public curve { + struct IFC_GEOM_API bspline_curve : public curve { DECLARE_PTR(bspline_curve) virtual bspline_curve* clone_() const { return new bspline_curve(*this); } @@ -770,7 +778,7 @@ typedef item const* ptr; int degree; }; - struct offset_curve : public curve { + struct IFC_GEOM_API offset_curve : public curve { DECLARE_PTR(offset_curve) direction3::ptr reference; @@ -786,7 +794,7 @@ typedef item const* ptr; } }; - struct trimmed_curve : public geom_item { + struct IFC_GEOM_API trimmed_curve : public geom_item { DECLARE_PTR(trimmed_curve) // @todo The copy constructor of point3 within the variant fails on the avx instruction @@ -810,7 +818,7 @@ typedef item const* ptr; void print(std::ostream& o, int indent = 0) const; }; - struct edge : public trimmed_curve { + struct IFC_GEOM_API edge : public trimmed_curve { DECLARE_PTR(edge) edge() : trimmed_curve() {} @@ -827,7 +835,7 @@ typedef item const* ptr; }; template - struct collection_base : public geom_item { + struct IFC_GEOM_API collection_base : public geom_item { std::vector children; collection_base() {} @@ -893,7 +901,7 @@ typedef item const* ptr; } }; - struct collection : public collection_base { + struct IFC_GEOM_API collection : public collection_base { DECLARE_PTR(collection) virtual collection* clone_() const { return new collection(*this); } @@ -906,7 +914,7 @@ typedef item const* ptr; }; - struct loop : public collection_base { + struct IFC_GEOM_API loop : public collection_base { DECLARE_PTR(loop) boost::optional external, closed; @@ -969,7 +977,7 @@ typedef item const* ptr; } }; - struct face : public collection_base { + struct IFC_GEOM_API face : public collection_base { DECLARE_PTR(face) item::ptr basis; @@ -990,7 +998,7 @@ typedef item const* ptr; } }; - struct shell : public collection_base { + struct IFC_GEOM_API shell : public collection_base { DECLARE_PTR(shell) boost::optional closed; @@ -1028,7 +1036,7 @@ typedef item const* ptr; } }; - struct solid : public collection_base { + struct IFC_GEOM_API solid : public collection_base { DECLARE_PTR(solid) virtual solid* clone_() const { return new solid(*this); } @@ -1040,7 +1048,7 @@ typedef item const* ptr; } }; - struct loft : public collection_base { + struct IFC_GEOM_API loft : public collection_base { DECLARE_PTR(loft) item::ptr axis; @@ -1059,9 +1067,9 @@ typedef item const* ptr; } }; - struct surface : public geom_item {}; + struct IFC_GEOM_API surface : public geom_item {}; - struct plane : public surface { + struct IFC_GEOM_API plane : public surface { DECLARE_PTR(plane) virtual plane* clone_() const { return new plane(*this); } @@ -1073,7 +1081,7 @@ typedef item const* ptr; } }; - struct cylinder : public surface { + struct IFC_GEOM_API cylinder : public surface { DECLARE_PTR(cylinder) double radius; @@ -1087,7 +1095,7 @@ typedef item const* ptr; } }; - struct sphere : public surface { + struct IFC_GEOM_API sphere : public surface { DECLARE_PTR(sphere) double radius; @@ -1101,7 +1109,7 @@ typedef item const* ptr; } }; - struct torus : public surface { + struct IFC_GEOM_API torus : public surface { DECLARE_PTR(torus) double radius1; @@ -1116,7 +1124,7 @@ typedef item const* ptr; } }; - struct bspline_surface : public surface { + struct IFC_GEOM_API bspline_surface : public surface { DECLARE_PTR(bspline_surface) virtual bspline_surface* clone_() const { return new bspline_surface(*this); } @@ -1159,7 +1167,7 @@ typedef item const* ptr; std::array degree; }; - struct sweep : public geom_item { + struct IFC_GEOM_API sweep : public geom_item { DECLARE_PTR(sweep) item::ptr basis; @@ -1168,7 +1176,7 @@ typedef item const* ptr; sweep(matrix4::ptr m, item::ptr b) : geom_item(m), basis(b) {} }; - struct extrusion : public sweep { + struct IFC_GEOM_API extrusion : public sweep { DECLARE_PTR(extrusion) direction3::ptr direction; @@ -1187,7 +1195,7 @@ typedef item const* ptr; } }; - struct revolve : public sweep { + struct IFC_GEOM_API revolve : public sweep { DECLARE_PTR(revolve) point3::ptr axis_origin; @@ -1205,7 +1213,7 @@ typedef item const* ptr; } }; - struct sweep_along_curve : public sweep { + struct IFC_GEOM_API sweep_along_curve : public sweep { DECLARE_PTR(sweep_along_curve) item::ptr surface; @@ -1226,7 +1234,7 @@ typedef item const* ptr; } }; - struct node : public item { + struct IFC_GEOM_API node : public item { DECLARE_PTR(node) // std::map representations; @@ -1242,7 +1250,7 @@ typedef item const* ptr; } }; - struct boolean_result : public collection_base { + struct IFC_GEOM_API boolean_result : public collection_base { DECLARE_PTR(boolean_result) enum operation_t { @@ -1300,7 +1308,7 @@ typedef item const* ptr; static const size_t max = std::tuple_size::value; }; - boost::optional loop_to_face_upgrade_impl(ptr item); + IFC_GEOM_API boost::optional loop_to_face_upgrade_impl(ptr item); template class loop_to_face_upgrade { private: @@ -1326,7 +1334,7 @@ typedef item const* ptr; } }; - boost::optional curve_to_edge_upgrade_impl(ptr item); + IFC_GEOM_API boost::optional curve_to_edge_upgrade_impl(ptr item); template class curve_to_edge_upgrade { private: @@ -1352,7 +1360,7 @@ typedef item const* ptr; } }; - boost::optional curve_to_loop_upgrade_impl(ptr item); + IFC_GEOM_API boost::optional curve_to_loop_upgrade_impl(ptr item); template class curve_to_loop_upgrade { private: @@ -1378,7 +1386,7 @@ typedef item const* ptr; } }; - boost::optional edge_to_loop_upgrade_impl(ptr item); + IFC_GEOM_API boost::optional edge_to_loop_upgrade_impl(ptr item); template class edge_to_loop_upgrade { private: @@ -1404,7 +1412,7 @@ typedef item const* ptr; } }; - boost::optional curve_to_face_upgrade_impl(ptr item); + IFC_GEOM_API boost::optional curve_to_face_upgrade_impl(ptr item); template class curve_to_face_upgrade { private: @@ -1430,7 +1438,7 @@ typedef item const* ptr; } }; - boost::optional loop_to_function_item_upgrade_impl(ptr item); + IFC_GEOM_API boost::optional loop_to_function_item_upgrade_impl(ptr item); template class loop_to_function_item_upgrade { private: @@ -1672,7 +1680,7 @@ typedef item const* ptr; } } - taxonomy::collection::ptr flatten(const taxonomy::collection::ptr& deep); + IFC_GEOM_API taxonomy::collection::ptr flatten(const taxonomy::collection::ptr& deep); template bool apply_predicate_to_collection(const taxonomy::ptr& i, Fn fn) { @@ -1724,10 +1732,10 @@ typedef item const* ptr; return collection; } - taxonomy::solid::ptr create_box(double dx, double dy, double dz); - taxonomy::solid::ptr create_box(double x, double y, double z, double dx, double dy, double dz); + IFC_GEOM_API taxonomy::solid::ptr create_box(double dx, double dy, double dz); + IFC_GEOM_API taxonomy::solid::ptr create_box(double x, double y, double z, double dx, double dy, double dz); - struct layerset_information { + struct IFC_GEOM_API layerset_information { std::vector thicknesses; std::vector layers; std::vector styles; diff --git a/src/ifcparse/IfcCharacterDecoder.h b/src/ifcparse/IfcCharacterDecoder.h index 5211c9c075..6a6d318aa1 100644 --- a/src/ifcparse/IfcCharacterDecoder.h +++ b/src/ifcparse/IfcCharacterDecoder.h @@ -32,9 +32,9 @@ #include namespace IfcUtil { -std::u32string::value_type convert_codepage(int codepage, int index); -std::string convert_utf8(const std::u32string& string); -std::u32string convert_utf8(const std::string& string); +IFC_PARSE_API std::u32string::value_type convert_codepage(int codepage, int index); +IFC_PARSE_API std::string convert_utf8(const std::u32string& string); +IFC_PARSE_API std::u32string convert_utf8(const std::string& string); } // namespace IfcUtil namespace IfcParse { diff --git a/src/ifcparse/IfcEntityInstanceData.cpp b/src/ifcparse/IfcEntityInstanceData.cpp index 4f1956249a..ca2f73b4ef 100644 --- a/src/ifcparse/IfcEntityInstanceData.cpp +++ b/src/ifcparse/IfcEntityInstanceData.cpp @@ -501,52 +501,52 @@ void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* std::to_string(index), v); } -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const Blank& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const int& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const bool& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const boost::logic::tribool& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const double& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::string& value); -template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const boost::dynamic_bitset<>& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const EnumerationReference& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, IfcUtil::IfcBaseClass* const& value); -template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); -template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); -template void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); -template void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const aggregate_of_instance::ptr& value); -template void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); -template void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const aggregate_of_aggregate_of_instance::ptr& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const Blank& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const int& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const bool& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const boost::logic::tribool& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const double& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::string& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const boost::dynamic_bitset<>& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const EnumerationReference& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, IfcUtil::IfcBaseClass* const& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const aggregate_of_instance::ptr& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const std::vector>& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const aggregate_of_aggregate_of_instance::ptr& value); // @todo why do these need to be included, but are not in BaseEntity::set()? -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const Derived& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const empty_aggregate_t& value); -template void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const empty_aggregate_of_aggregate_t& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const Derived& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const empty_aggregate_t& value); +template IFC_PARSE_API void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index, const empty_aggregate_of_aggregate_t& value); -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has>>(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; // @todo why do these need to be included, but are not in BaseEntity::set()? -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; -template bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; +template IFC_PARSE_API bool rocks_db_attribute_storage::has(void* storage, const IfcParse::declaration* decl, std::size_t identity, size_t index) const; #endif \ No newline at end of file diff --git a/src/ifcparse/IfcEntityInstanceData.h b/src/ifcparse/IfcEntityInstanceData.h index f97a8b7cb5..df2edddb94 100644 --- a/src/ifcparse/IfcEntityInstanceData.h +++ b/src/ifcparse/IfcEntityInstanceData.h @@ -41,7 +41,7 @@ #include #include -class EnumerationReference { +class IFC_PARSE_API EnumerationReference { private: const IfcParse::enumeration_type* enumeration_; size_t index_; @@ -64,10 +64,10 @@ public: return enumeration_; } }; -class Blank {}; -class Derived {}; -class empty_aggregate_t {}; -class empty_aggregate_of_aggregate_t {}; +class IFC_PARSE_API Blank {}; +class IFC_PARSE_API Derived {}; +class IFC_PARSE_API empty_aggregate_t {}; +class IFC_PARSE_API empty_aggregate_of_aggregate_t {}; template struct parameter_pack { @@ -154,14 +154,14 @@ struct TypeEncoder_t> { using TypeEncoder = TypeEncoder_t; -struct MutableAttributeValue { +struct IFC_PARSE_API MutableAttributeValue { int name_; uint8_t index_; }; namespace IfcParse { namespace impl { - class rocks_db_file_storage; + class IFC_PARSE_API rocks_db_file_storage; } } @@ -283,7 +283,7 @@ namespace impl { #endif // short lived -struct AttributeValue { +struct IFC_PARSE_API AttributeValue { uint8_t index_; uint8_t storage_model_ = 0; const IfcParse::declaration* entity_or_type_ = 0; @@ -391,15 +391,15 @@ struct AttributeValue { }; -struct rocks_db_attribute_storage { +struct IFC_PARSE_API rocks_db_attribute_storage { public: #ifdef IFOPSH_WITH_ROCKSDB // @todo void* is obviously very ugly here template - void set(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index, const T& value); + IFC_PARSE_API void set(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index, const T& value); template - bool has(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index) const; + IFC_PARSE_API bool has(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index) const; template auto apply_visitor(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index, Visitor&& visitor) const { diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 8e79856bba..030321d9ee 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -84,10 +84,9 @@ enum filetype { FT_AUTODETECT }; -filetype guess_file_type(const std::string& fn); +IFC_PARSE_API filetype guess_file_type(const std::string& fn); - -class InstanceStreamer { +class IFC_PARSE_API InstanceStreamer { private: IfcSpfStream* stream_; IfcSpfLexer* lexer_; diff --git a/src/ifcparse/storage.h b/src/ifcparse/storage.h index 85fa7a53d2..46ea9ce2a1 100644 --- a/src/ifcparse/storage.h +++ b/src/ifcparse/storage.h @@ -188,7 +188,7 @@ namespace IfcParse { }; namespace impl { - struct in_memory_file_storage { + struct IFC_PARSE_API in_memory_file_storage { IfcParse::IfcSpfLexer* tokens; // IfcParse::IfcSpfStream* stream; @@ -248,11 +248,6 @@ namespace IfcParse { } }; - - static bool guid_map_; - static bool guid_map() { return guid_map_; } - static void guid_map(bool b) { guid_map_ = b; } - entity_instance_by_name_t byid_; type_instance_by_name_t tbyid_; entities_by_type_t bytype_excl_; @@ -303,7 +298,7 @@ namespace IfcParse { IfcUtil::IfcBaseClass* create(const IfcParse::declaration* decl); }; - class rocks_db_file_storage { + class IFC_PARSE_API rocks_db_file_storage { public: rocksdb::DB* db; rocksdb::WriteOptions wopts; @@ -441,7 +436,7 @@ namespace IfcParse { */ // @todo merge iterators (template?) - class rocksdb_types_iterator { + class IFC_PARSE_API rocksdb_types_iterator { private: rocksdb::Iterator* state_; const rocks_db_file_storage* storage_; diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index bc64a69bb0..d54e33c5d5 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -71,6 +71,7 @@ } %newobject IfcGeom::Representation::BRep::item; +%newobject IfcGeom::Representation::BRep::as_compound; %newobject IfcGeom::ConversionResultShape::halfspaces; %newobject IfcGeom::ConversionResultShape::box; @@ -78,6 +79,7 @@ %newobject IfcGeom::ConversionResultShape::add; %newobject IfcGeom::ConversionResultShape::subtract; %newobject IfcGeom::ConversionResultShape::intersect; +%newobject IfcGeom::ConversionResultShape::concat; %newobject IfcGeom::ConversionResultShape::moved; %newobject IfcGeom::ConversionResultShape::area; @@ -635,7 +637,7 @@ struct ShapeRTTI : public boost::static_visitor 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); + return new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(file, geometry_library, settings), settings, file, {ef}, 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) { @@ -644,13 +646,13 @@ struct ShapeRTTI : public boost::static_visitor af.attribute_name = "GlobalId"; af.populate(elems_set); af.include = include; - return new IfcGeom::Iterator(geometry_library, settings, file, {af}, num_threads); + return new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(file, geometry_library, settings), settings, file, {af}, 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); + return new IfcGeom::Iterator(ifcopenshell::geometry::kernels::construct(file, geometry_library, settings), settings, file, {af}, num_threads); } %} @@ -876,7 +878,7 @@ struct ShapeRTTI : public boost::static_visitor static boost::variant helper_fn_create_shape(const std::string& geometry_library, ifcopenshell::geometry::Settings& st, IfcUtil::IfcBaseClass* instance, IfcUtil::IfcBaseClass* representation = 0) { IfcParse::IfcFile* file = instance->file_; - ifcopenshell::geometry::Converter kernel(geometry_library, file, st); + ifcopenshell::geometry::Converter kernel(ifcopenshell::geometry::kernels::construct(file, geometry_library, st), file, st); if (typename Schema::IfcProduct* product = instance->as()) { if (representation) { diff --git a/src/ifcwrap/IfcPython.i b/src/ifcwrap/IfcPython.i index 0b69e90d85..7a3fd48139 100644 --- a/src/ifcwrap/IfcPython.i +++ b/src/ifcwrap/IfcPython.i @@ -294,6 +294,7 @@ constexpr bool is_std_vector_vector_v = is_std_vector_vector::value; #endif #include "../ifcgeom/Iterator.h" #include "../ifcgeom/ConversionResult.h" + #include "../ifcgeom/hybrid_kernel.h" #include "../serializers/SvgSerializer.h" #include "../serializers/WavefrontObjSerializer.h" diff --git a/src/serializers/serializers_api.h b/src/serializers/serializers_api.h index a46a27122b..0e37f59442 100644 --- a/src/serializers/serializers_api.h +++ b/src/serializers/serializers_api.h @@ -22,7 +22,7 @@ #ifdef IFC_SHARED_BUILD #ifdef _WIN32 - #ifdef Serializers_EXPORTS + #ifdef SERIALIZERS_EXPORTS #define SERIALIZERS_API __declspec(dllexport) #else #define SERIALIZERS_API __declspec(dllimport)