First slice plug-in refactor

This commit is contained in:
Thomas Krijnen
2026-04-14 13:50:23 +02:00
parent 2018bcb3c1
commit aa10784154
31 changed files with 958 additions and 322 deletions
+9 -1
View File
@@ -28,6 +28,8 @@
#include "../ifcgeom/ConversionSettings.h"
#include "../ifcgeom/abstract_mapping.h"
#include <string_view>
static const double ALMOST_ZERO = 1.e-9;
template <typename T>
@@ -79,6 +81,12 @@ namespace ifcopenshell {
const std::string& geometry_library() const {
return geometry_library_;
}
virtual std::string_view backend_id() const {
return geometry_library_;
}
virtual bool accepts(const IfcGeom::ConversionResultShape& shape) const {
return shape.backend_id() == backend_id();
}
virtual bool supports_boolean_operations() const = 0;
@@ -238,4 +246,4 @@ namespace {
};
}
#endif
#endif
+4 -3
View File
@@ -14,6 +14,7 @@ file(GLOB SCHEMA_AGNOSTIC_CPP_FILES *.cpp)
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES})
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
add_library(geometry ALIAS IfcGeom)
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if(UNIX)
@@ -23,11 +24,11 @@ endif()
find_package(Eigen3 REQUIRED)
if(WASM_BUILD)
target_link_libraries(IfcGeom ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
target_link_libraries(IfcGeom plugin ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
else()
target_link_libraries(IfcGeom IfcParse ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
target_link_libraries(IfcGeom plugin IfcParse ${kernel_libraries} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
endif()
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
DESTINATION ${INCLUDEDIR}/ifcgeom
)
)
+2
View File
@@ -25,6 +25,7 @@
#include "../ifcgeom/taxonomy.h"
#include <memory>
#include <string_view>
#include <vector>
#include <unordered_map>
@@ -253,6 +254,7 @@ namespace IfcGeom {
class IFC_GEOM_API ConversionResultShape {
public:
virtual std::string_view backend_id() const = 0;
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, Representation::Triangulation* t, int item_id, int surface_style_id) const = 0;
IfcGeom::Representation::Triangulation* Triangulate(const ifcopenshell::geometry::Settings& settings) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const = 0;
+3 -3
View File
@@ -103,7 +103,7 @@ class SerializerSettings : public SettingsContainer <
}
}
class stream_or_filename {
class IFC_GEOM_API stream_or_filename {
private:
std::shared_ptr<std::ofstream> ofs_;
std::shared_ptr<std::ostringstream> oss_;
@@ -139,7 +139,7 @@ public:
}
};
class GeometrySerializer : public Serializer {
class IFC_GEOM_API GeometrySerializer : public Serializer {
public:
enum read_type { READ_BREP, READ_TRIANGULATION };
@@ -175,7 +175,7 @@ protected:
ifcopenshell::geometry::SerializerSettings settings_;
};
class WriteOnlyGeometrySerializer : public GeometrySerializer {
class IFC_GEOM_API WriteOnlyGeometrySerializer : public GeometrySerializer {
public:
WriteOnlyGeometrySerializer(const ifcopenshell::geometry::Settings& geometry_settings, const ifcopenshell::geometry::SerializerSettings& settings) : GeometrySerializer(geometry_settings, settings) {}
+3 -2
View File
@@ -1,8 +1,9 @@
add_subdirectory(schema)
add_library(geometry_serializer STATIC Serialization.cpp)
add_library(geometry_serializer Serialization.cpp)
add_library(opencascade_geometry_ifc_writer ALIAS geometry_serializer)
set_target_properties(geometry_serializer PROPERTIES COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS")
target_link_libraries(geometry_serializer ${geometry_serializer_libraries} IfcParse)
target_link_libraries(geometry_serializer plugin ${geometry_serializer_libraries} IfcParse)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer" ${geometry_serializer_libraries})
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
+90 -41
View File
@@ -1,59 +1,108 @@
#include "Serialization.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include "../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
#include "../../ifcparse/file.h"
#define EXTERNAL_DEFS_1(r, data, elem) \
express::Base BOOST_PP_CAT(tesselate_Ifc, elem)(ifcopenshell::file&, const TopoDS_Shape& shape, double deflection);
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define EXTERNAL_DEFS_2(r, data, elem) \
express::Base BOOST_PP_CAT(serialise_Ifc, elem)(ifcopenshell::file&, const TopoDS_Shape& shape, bool advanced);
#include <mutex>
#define CONDITIONAL_CALL(r, data, elem) \
if (schema_name_lower == BOOST_PP_STRINGIZE(BOOST_PP_CAT(elem,))) { \
return BOOST_PP_CAT(METHOD_NAME, elem)(f, shape, arg_2); \
namespace {
std::string writer_schema_key(const std::string& schema_name) {
return boost::to_upper_copy(schema_name);
}
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_1, , SCHEMA_SEQ);
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS_2, , SCHEMA_SEQ);
ifcopenshell::plugin::module builtin_writer_module(const std::string& schema_name) {
ifcopenshell::plugin::metadata metadata;
metadata.kind_ = ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer;
metadata.id = "geometry.ifc_writer." + boost::to_lower_copy(schema_name);
metadata.schema = schema_name;
return ifcopenshell::plugin::module::builtin(metadata);
}
#define METHOD_NAME tesselate_Ifc
const ifcopenshell::geometry::OpenCascadeShape& require_opencascade_shape(const IfcGeom::ConversionResultShape& shape) {
const auto* oc_shape = dynamic_cast<const ifcopenshell::geometry::OpenCascadeShape*>(&shape);
if (!oc_shape) {
throw ifcopenshell::exception("OpenCascade geometry IFC writer requires an opencascade conversion result shape");
}
return *oc_shape;
}
express::Base IfcGeom::tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double arg_2) {
auto schema_name = f.schema()->name();
template <express::Base(*Fn)(ifcopenshell::file&, const TopoDS_Shape&, bool)>
express::Base serialise_adapter(ifcopenshell::file& f, const IfcGeom::ConversionResultShape& shape, bool advanced) {
return Fn(f, require_opencascade_shape(shape).shape(), advanced);
}
// @todo an ugly hack to guarantee schemas are initialised.
// @todo is this still needed? parsing a file should have initialized the schemas already.
try {
ifcopenshell::schema_by_name("IFC2X3");
} catch (ifcopenshell::exception&) {}
const std::string schema_name_lower = boost::to_lower_copy(schema_name.substr(3));
BOOST_PP_SEQ_FOR_EACH(CONDITIONAL_CALL, , SCHEMA_SEQ);
throw ifcopenshell::exception("No geometry serialization available for " + schema_name);
template <express::Base(*Fn)(ifcopenshell::file&, const TopoDS_Shape&, double)>
express::Base tesselate_adapter(ifcopenshell::file& f, const IfcGeom::ConversionResultShape& shape, double deflection) {
return Fn(f, require_opencascade_shape(shape).shape(), deflection);
}
}
#undef METHOD_NAME
#define METHOD_NAME serialise_Ifc
#define EXTERNAL_TESSELATE(r, data, elem) \
express::Base BOOST_PP_CAT(tesselate_Ifc, elem)(ifcopenshell::file&, const TopoDS_Shape& shape, double deflection);
express::Base IfcGeom::serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool arg_2) {
auto schema_name = f.schema()->name();
#define EXTERNAL_SERIALISE(r, data, elem) \
express::Base BOOST_PP_CAT(serialise_Ifc, elem)(ifcopenshell::file&, const TopoDS_Shape& shape, bool advanced);
// @todo an ugly hack to guarantee schemas are initialised.
try {
ifcopenshell::schema_by_name("IFC2X3");
} catch (ifcopenshell::exception&) {}
#define BIND_WRITER(r, data, elem) \
registry.bind(BOOST_PP_STRINGIZE(BOOST_PP_CAT(Ifc, elem)), \
&serialise_adapter<BOOST_PP_CAT(serialise_Ifc, elem)>, \
&tesselate_adapter<BOOST_PP_CAT(tesselate_Ifc, elem)>, \
builtin_writer_module(BOOST_PP_STRINGIZE(BOOST_PP_CAT(Ifc, elem))));
const std::string schema_name_lower = boost::to_lower_copy(schema_name.substr(3));
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_TESSELATE, , SCHEMA_SEQ)
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_SERIALISE, , SCHEMA_SEQ)
BOOST_PP_SEQ_FOR_EACH(CONDITIONAL_CALL, , SCHEMA_SEQ);
IfcGeom::opencascade_geometry_ifc_writer_registry& IfcGeom::opencascade_geometry_ifc_writer_registry_instance() {
static opencascade_geometry_ifc_writer_registry registry;
static std::once_flag once;
std::call_once(once, []() {
BOOST_PP_SEQ_FOR_EACH(BIND_WRITER, , SCHEMA_SEQ)
});
return registry;
}
throw ifcopenshell::exception("No geometry serialization available for " + schema_name);
}
void IfcGeom::opencascade_geometry_ifc_writer_registry::bind(const std::string& schema_name, serialise_fn serialise, tesselate_fn tesselate, const ifcopenshell::plugin::module& module) {
entry entry;
entry.serialise_ = serialise;
entry.tesselate_ = tesselate;
entry.module_ = module;
entries_[writer_schema_key(schema_name)] = entry;
}
express::Base IfcGeom::opencascade_geometry_ifc_writer_registry::tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection) const {
const auto iter = entries_.find(writer_schema_key(f.schema()->name()));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
}
return iter->second.tesselate_(f, shape, deflection);
}
express::Base IfcGeom::opencascade_geometry_ifc_writer_registry::serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced) const {
const auto iter = entries_.find(writer_schema_key(f.schema()->name()));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
}
return iter->second.serialise_(f, shape, advanced);
}
express::Base IfcGeom::tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection) {
return opencascade_geometry_ifc_writer_registry_instance().tesselate(f, shape, deflection);
}
express::Base IfcGeom::serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced) {
return opencascade_geometry_ifc_writer_registry_instance().serialise(f, shape, advanced);
}
express::Base IfcGeom::tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection) {
ifcopenshell::geometry::OpenCascadeShape converted(shape);
return tesselate(f, converted, deflection);
}
express::Base IfcGeom::serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced) {
ifcopenshell::geometry::OpenCascadeShape converted(shape);
return serialise(f, converted, advanced);
}
+38 -1
View File
@@ -1,12 +1,49 @@
#ifndef IFC_GEOM_SERIALIZATION_H
#define IFC_GEOM_SERIALIZATION_H
#include "../../ifcparse/express.h"
#include "../../plugin/plugin.h"
#include "../../ifcgeom/ConversionResult.h"
#include "ifc_geomserialization_api.h"
#include <TopoDS_Shape.hxx>
#include <boost/function.hpp>
#include <map>
#include <string>
class TopoDS_Shape;
namespace ifcopenshell {
class file;
}
namespace IfcGeom {
class IFC_GEOMSERIALIZATION_API opencascade_geometry_ifc_writer_registry {
public:
typedef boost::function3<express::Base, ifcopenshell::file&, const ConversionResultShape&, double> tesselate_fn;
typedef boost::function3<express::Base, ifcopenshell::file&, const ConversionResultShape&, bool> serialise_fn;
void bind(const std::string& schema_name, serialise_fn serialise, tesselate_fn tesselate, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
express::Base tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection) const;
express::Base serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced) const;
private:
struct entry {
serialise_fn serialise_;
tesselate_fn tesselate_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
};
IFC_GEOMSERIALIZATION_API opencascade_geometry_ifc_writer_registry& opencascade_geometry_ifc_writer_registry_instance();
IFC_GEOMSERIALIZATION_API express::Base tesselate(ifcopenshell::file& f, const ConversionResultShape& shape, double deflection);
IFC_GEOMSERIALIZATION_API express::Base serialise(ifcopenshell::file& f, const ConversionResultShape& shape, bool advanced);
IFC_GEOMSERIALIZATION_API express::Base tesselate(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection);
IFC_GEOMSERIALIZATION_API express::Base serialise(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced);
} // namespace IfcGeom
#endif
+3 -2
View File
@@ -20,9 +20,10 @@
#ifndef SERIALIZER_H
#define SERIALIZER_H
#include "ifc_geom_api.h"
#include "../ifcparse/file.h"
class Serializer {
class IFC_GEOM_API Serializer {
public:
virtual ~Serializer() {}
@@ -32,4 +33,4 @@ public:
virtual void setFile(ifcopenshell::file*) = 0;
};
#endif
#endif
+59 -26
View File
@@ -4,47 +4,80 @@
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <mutex>
#ifndef SCHEMA_SEQ
static_assert(false, "A boost preprocessor sequence of schema identifiers is needed for this file to compile.");
#endif
// Declares the schema-based external kernel initialization routines:
// - extern void init_MappingImplementation_Ifc2x3(IfcGeom::impl::mapping_registry*);
// - ...
#define EXTERNAL_DEFS(r, data, elem) \
extern void BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(ifcopenshell::geometry::impl::mapping_registry*);
// Declares the schema-based external iterator initialization routines:
// - init_MappingImplementation_Ifc2x3(this);
// - ...
#define CALL_DEFS(r, data, elem) \
BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(&registry);
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS, , SCHEMA_SEQ)
namespace {
std::string mapping_key(const std::string& schema_name) {
return boost::to_lower_copy(schema_name);
}
ifcopenshell::plugin::module builtin_mapping_module(const std::string& schema_name) {
ifcopenshell::plugin::metadata metadata;
metadata.kind_ = ifcopenshell::plugin::kind::mapping;
metadata.id = "geometry.mapping." + boost::to_lower_copy(schema_name);
metadata.schema = schema_name;
return ifcopenshell::plugin::module::builtin(metadata);
}
}
ifcopenshell::geometry::impl::mapping_registry& ifcopenshell::geometry::impl::mapping_registry_instance() {
static mapping_registry registry;
static std::once_flag once;
std::call_once(once, []() {
BOOST_PP_SEQ_FOR_EACH(CALL_DEFS, , SCHEMA_SEQ)
});
return registry;
}
void ifcopenshell::geometry::impl::mapping_registry::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn, const plugin::module& module) {
auto& entry = entries_[mapping_key(schema_name)];
entry.fn_ = fn;
entry.module_ = module.meta().id.empty() ? builtin_mapping_module(schema_name) : module;
}
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::mapping_registry::construct(ifcopenshell::file* file, Settings& s) {
const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name());
const auto it = entries_.find(schema_name_lower);
if (it == entries_.end()) {
throw ifcopenshell::exception("No geometry mapping registered for " + schema_name_lower);
}
auto new_mapping = it->second.fn_(file, s);
new_mapping->initialize_settings();
return new_mapping;
}
ifcopenshell::geometry::impl::MappingFactoryImplementation& ifcopenshell::geometry::impl::mapping_implementations() {
static MappingFactoryImplementation impl;
return impl;
}
// Declares the schema-based external kernel initialization routines:
// - extern void init_MappingImplementation_Ifc2x3(IfcGeom::impl::MappingFactoryImplementation*);
// - ...
#define EXTERNAL_DEFS(r, data, elem) \
extern void BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(ifcopenshell::geometry::impl::MappingFactoryImplementation*);
// Declares the schema-based external iterator initialization routines:
// - init_MappingImplementation_Ifc2x3(this);
// - ...
#define CALL_DEFS(r, data, elem) \
BOOST_PP_CAT(init_MappingImplementation_Ifc, elem)(this);
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS, , SCHEMA_SEQ)
ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplementation() {
BOOST_PP_SEQ_FOR_EACH(CALL_DEFS, , SCHEMA_SEQ)
mapping_registry_instance();
}
void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
this->insert(std::make_pair(schema_name_lower, fn));
mapping_registry_instance().bind(schema_name, fn, builtin_mapping_module(schema_name));
}
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(ifcopenshell::file* file, Settings& s) {
const std::string schema_name_lower = boost::to_lower_copy(file->schema()->name());
std::map<std::string, ifcopenshell::geometry::impl::mapping_fn>::const_iterator it;
it = this->find(schema_name_lower);
if (it == end()) {
throw ifcopenshell::exception("No geometry mapping registered for " + schema_name_lower);
}
auto new_mapping = it->second(file, s);
new_mapping->initialize_settings();
return new_mapping;
return mapping_registry_instance().construct(file, s);
}
+18 -1
View File
@@ -23,6 +23,7 @@
#include "../ifcparse/express.h"
#include "../ifcgeom/taxonomy.h"
#include "../ifcgeom/ConversionSettings.h"
#include "../plugin/plugin.h"
#include <boost/function.hpp>
@@ -79,7 +80,23 @@ namespace geometry {
namespace impl {
typedef boost::function2<abstract_mapping*, ifcopenshell::file*, Settings&> mapping_fn;
class IFC_GEOM_API MappingFactoryImplementation : public std::map<std::string, mapping_fn> {
class IFC_GEOM_API mapping_registry {
public:
void bind(const std::string& schema_name, mapping_fn fn, const plugin::module& module = plugin::module());
abstract_mapping* construct(ifcopenshell::file* file, Settings& settings);
private:
struct entry {
mapping_fn fn_;
plugin::module module_;
};
std::map<std::string, entry> entries_;
};
IFC_GEOM_API mapping_registry& mapping_registry_instance();
class IFC_GEOM_API MappingFactoryImplementation {
public:
MappingFactoryImplementation();
void bind(const std::string& schema_name, mapping_fn);
+2 -132
View File
@@ -21,52 +21,7 @@
#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
#ifdef IFOPSH_WITH_MANIFOLD
#include "../ifcgeom/kernels/manifold/ManifoldKernel.h"
#endif
#include "../ifcgeom/kernels/passthrough/PassthroughKernel.h"
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<ifcopenshell::geometry::OpenCascadeShape*>(shp.Shape().get()) != nullptr;
}
#endif
#ifdef IFOPSH_WITH_CGAL
if (k->geometry_library() == "cgal-simple") {
return dynamic_cast<ifcopenshell::geometry::SimpleCgalShape*>(shp.Shape().get()) != nullptr;
}
if (k->geometry_library() == "cgal") {
return dynamic_cast<ifcopenshell::geometry::CgalShape*>(shp.Shape().get()) != nullptr;
}
#endif
#ifdef IFOPSH_WITH_MANIFOLD
if (k->geometry_library() == "manifold") {
return dynamic_cast<ifcopenshell::geometry::ManifoldShape*>(shp.Shape().get()) != nullptr;
}
#endif
if (k->geometry_library() == "passthrough") {
return dynamic_cast<ifcopenshell::geometry::PassthroughShape*>(shp.Shape().get()) != nullptr;
}
return false;
}
}
#include "kernel_registry.h"
namespace ifcopenshell {
namespace geometry {
@@ -154,7 +109,7 @@ namespace ifcopenshell {
for (auto& k : kernels_) {
bool is_valid = true;
for (auto& s : entity_shapes) {
if (!is_valid_for_kernel(k.get(), s)) {
if (!k->accepts(*s.Shape())) {
is_valid = false;
break;
}
@@ -182,91 +137,6 @@ namespace ifcopenshell {
return new HybridKernel(geometry_library(), file_, const_cast<Settings&>(settings()), std::move(ks));
}
};
inline std::unique_ptr<AbstractKernel> construct(ifcopenshell::file* 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<IfcGeom::OpenCascadeKernel>(conv_settings);
}
#endif
#ifdef IFOPSH_WITH_CGAL
if (geometry_library_lower == "cgal") {
return std::make_unique<CgalKernel>(conv_settings);
}
if (geometry_library_lower == "cgal-simple") {
return std::make_unique<SimpleCgalKernel>(conv_settings);
}
#endif
#ifdef IFOPSH_WITH_MANIFOLD
if (geometry_library_lower == "manifold") {
return std::make_unique<ManifoldKernel>(conv_settings);
}
#endif
if (geometry_library_lower == "passthrough") {
return std::make_unique<PassthroughKernel>(conv_settings);
}
if (geometry_library_lower.rfind("hybrid-", 0) == 0) {
geometry_library_lower = geometry_library_lower.substr(strlen("hybrid"));
std::vector<std::unique_ptr<AbstractKernel>> kernels;
while (!geometry_library_lower.empty()) {
if (geometry_library_lower.find("-", 0) == 0) {
geometry_library_lower = geometry_library_lower.substr(strlen("-"));
} else {
throw ifcopenshell::exception("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
#ifdef IFOPSH_WITH_MANIFOLD
if (geometry_library_lower.find("manifold", 0) == 0) {
kernels.emplace_back(new ManifoldKernel(conv_settings));
geometry_library_lower = geometry_library_lower.substr(strlen("manifold"));
}
#endif
if (geometry_library_lower.find("passthrough", 0) == 0) {
kernels.emplace_back(new PassthroughKernel(conv_settings));
geometry_library_lower = geometry_library_lower.substr(strlen("passthrough"));
}
if (kernels.size() != n + 1) {
throw ifcopenshell::exception("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<HybridKernel>(geometry_library, file, conv_settings, std::move(kernels));
}
}
throw ifcopenshell::exception("No geometry kernel registered for " + geometry_library);
}
}
}
}
+174
View File
@@ -0,0 +1,174 @@
/********************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#include "kernel_registry.h"
#include "../ifcgeom/hybrid_kernel.h"
#include "../ifcparse/file.h"
#include <boost/algorithm/string.hpp>
#include <cstring>
#include <mutex>
#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
#undef IFOPSH_SIMPLE_KERNEL
#endif
#ifdef IFOPSH_WITH_MANIFOLD
#include "../ifcgeom/kernels/manifold/ManifoldKernel.h"
#endif
#include "../ifcgeom/kernels/passthrough/PassthroughKernel.h"
namespace {
std::string kernel_key(const std::string& backend_id) {
return boost::to_lower_copy(backend_id);
}
ifcopenshell::plugin::module builtin_kernel_module(const std::string& backend_id) {
ifcopenshell::plugin::metadata metadata;
metadata.kind_ = ifcopenshell::plugin::kind::kernel;
metadata.id = "geometry.kernel." + kernel_key(backend_id);
return ifcopenshell::plugin::module::builtin(metadata);
}
void register_builtin_kernels(ifcopenshell::geometry::kernels::kernel_registry& registry) {
#ifdef IFOPSH_WITH_OPENCASCADE
ifcopenshell::geometry::kernels::kernel_info opencascade_info;
opencascade_info.backend_id = "opencascade";
opencascade_info.supports_boolean_operations = true;
registry.bind(opencascade_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new IfcGeom::OpenCascadeKernel(settings); }, builtin_kernel_module("opencascade"));
#endif
#ifdef IFOPSH_WITH_CGAL
ifcopenshell::geometry::kernels::kernel_info cgal_info;
cgal_info.backend_id = "cgal";
cgal_info.supports_boolean_operations = true;
registry.bind(cgal_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::CgalKernel(settings); }, builtin_kernel_module("cgal"));
ifcopenshell::geometry::kernels::kernel_info cgal_simple_info;
cgal_simple_info.backend_id = "cgal-simple";
cgal_simple_info.supports_boolean_operations = false;
registry.bind(cgal_simple_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::SimpleCgalKernel(settings); }, builtin_kernel_module("cgal-simple"));
#endif
#ifdef IFOPSH_WITH_MANIFOLD
ifcopenshell::geometry::kernels::kernel_info manifold_info;
manifold_info.backend_id = "manifold";
manifold_info.supports_boolean_operations = true;
registry.bind(manifold_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::ManifoldKernel(settings); }, builtin_kernel_module("manifold"));
#endif
ifcopenshell::geometry::kernels::kernel_info passthrough_info;
passthrough_info.backend_id = "passthrough";
passthrough_info.supports_boolean_operations = false;
registry.bind(passthrough_info, [](ifcopenshell::file*, ifcopenshell::geometry::Settings& settings) { return new ifcopenshell::geometry::kernels::PassthroughKernel(settings); }, builtin_kernel_module("passthrough"));
}
}
void ifcopenshell::geometry::kernels::kernel_registry::bind(const kernel_info& info, create_fn create, const plugin::module& module) {
entry entry;
entry.info_ = info;
entry.create_ = create;
entry.module_ = module;
entries_[kernel_key(info.backend_id)] = entry;
}
bool ifcopenshell::geometry::kernels::kernel_registry::has(const std::string& backend_id) const {
return entries_.find(kernel_key(backend_id)) != entries_.end();
}
std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel> ifcopenshell::geometry::kernels::kernel_registry::create(const std::string& backend_id, ifcopenshell::file* file, Settings& settings) const {
const auto iter = entries_.find(kernel_key(backend_id));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry kernel registered for " + backend_id);
}
return std::unique_ptr<AbstractKernel>(iter->second.create_(file, settings));
}
std::vector<ifcopenshell::geometry::kernels::kernel_info> ifcopenshell::geometry::kernels::kernel_registry::kernels() const {
std::vector<kernel_info> result;
for (const auto& pair : entries_) {
result.push_back(pair.second.info_);
}
return result;
}
ifcopenshell::geometry::kernels::kernel_registry& ifcopenshell::geometry::kernels::kernel_registry_instance() {
static kernel_registry registry;
static std::once_flag once;
std::call_once(once, register_builtin_kernels, std::ref(registry));
return registry;
}
std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel> ifcopenshell::geometry::kernels::construct(ifcopenshell::file* file, const std::string& geometry_library, Settings& settings) {
auto geometry_library_lower = boost::to_lower_copy(geometry_library);
auto& registry = kernel_registry_instance();
if (registry.has(geometry_library_lower)) {
return registry.create(geometry_library_lower, file, settings);
}
if (geometry_library_lower.rfind("hybrid-", 0) == 0) {
geometry_library_lower = geometry_library_lower.substr(strlen("hybrid"));
std::vector<std::unique_ptr<AbstractKernel>> kernels;
while (!geometry_library_lower.empty()) {
if (geometry_library_lower.find("-", 0) == 0) {
geometry_library_lower = geometry_library_lower.substr(strlen("-"));
} else {
throw ifcopenshell::exception("Invalid hybrid kernel " + geometry_library);
}
std::string matched_backend_id;
for (const auto& info : registry.kernels()) {
const auto backend_id = kernel_key(info.backend_id);
if (geometry_library_lower.rfind(backend_id, 0) == 0 && backend_id.size() > matched_backend_id.size()) {
matched_backend_id = backend_id;
}
}
if (matched_backend_id.empty()) {
throw ifcopenshell::exception("Invalid hybrid kernel " + geometry_library);
}
kernels.push_back(registry.create(matched_backend_id, file, settings));
geometry_library_lower = geometry_library_lower.substr(matched_backend_id.size());
}
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<HybridKernel>(geometry_library, file, settings, std::move(kernels));
}
}
throw ifcopenshell::exception("No geometry kernel registered for " + geometry_library);
}
+70
View File
@@ -0,0 +1,70 @@
/********************************************************************************
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef KERNEL_REGISTRY_H
#define KERNEL_REGISTRY_H
#include "../ifcgeom/AbstractKernel.h"
#include "../plugin/plugin.h"
#include <boost/function.hpp>
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace ifcopenshell {
class file;
namespace geometry {
namespace kernels {
struct IFC_GEOM_API kernel_info {
std::string backend_id;
bool supports_boolean_operations = false;
};
class IFC_GEOM_API kernel_registry {
public:
typedef boost::function2<AbstractKernel*, ifcopenshell::file*, Settings&> create_fn;
void bind(const kernel_info& info, create_fn create, const plugin::module& module = plugin::module());
bool has(const std::string& backend_id) const;
std::unique_ptr<AbstractKernel> create(const std::string& backend_id, ifcopenshell::file* file, Settings& settings) const;
std::vector<kernel_info> kernels() const;
private:
struct entry {
kernel_info info_;
create_fn create_;
plugin::module module_;
};
std::map<std::string, entry> entries_;
};
IFC_GEOM_API kernel_registry& kernel_registry_instance();
IFC_GEOM_API std::unique_ptr<AbstractKernel> construct(ifcopenshell::file* file, const std::string& geometry_library, Settings& settings);
}
}
}
#endif
@@ -208,6 +208,13 @@ namespace ifcopenshell { namespace geometry {
operator const cgal_shape_t& () const { to_poly(); return *shape_; }
const cgal_shape_t& poly() const { to_poly(); return *shape_; }
virtual std::string_view backend_id() const {
#ifdef IFOPSH_SIMPLE_KERNEL
return "cgal-simple";
#else
return "cgal";
#endif
}
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
@@ -284,6 +291,13 @@ namespace ifcopenshell { namespace geometry {
shape_.reset(new halfspace_tree_plane<Kernel_>(shape));
planes_.push_back(shape);
}
virtual std::string_view backend_id() const {
#ifdef IFOPSH_SIMPLE_KERNEL
return "cgal-simple";
#else
return "cgal";
#endif
}
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
@@ -26,6 +26,7 @@ public:
const std::vector<ManifoldPart>& parts() const { return parts_; }
std::optional<manifold::Manifold> as_manifold() const;
virtual std::string_view backend_id() const { return "manifold"; }
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
@@ -52,6 +52,7 @@ namespace ifcopenshell {
const TopoDS_Shape& shape() const { return shape_; }
operator const TopoDS_Shape& () { return shape_; }
virtual std::string_view backend_id() const { return "opencascade"; }
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
@@ -113,4 +114,4 @@ namespace ifcopenshell {
}
}
#endif
#endif
@@ -22,6 +22,7 @@ public:
explicit PassthroughShape(std::vector<PassthroughPart>&& parts);
const std::vector<PassthroughPart>& parts() const { return parts_; }
virtual std::string_view backend_id() const { return "passthrough"; }
virtual void Triangulate(ifcopenshell::geometry::Settings settings, const ifcopenshell::geometry::taxonomy::matrix4& place, IfcGeom::Representation::Triangulation* t, int item_id, int surface_style_id) const;
virtual void Serialize(const ifcopenshell::geometry::taxonomy::matrix4& place, std::string&) const;
+1 -1
View File
@@ -39,7 +39,7 @@ namespace {
};
}
void MAKE_INIT_FN(MappingImplementation)(ifcopenshell::geometry::impl::MappingFactoryImplementation* mapping) {
void MAKE_INIT_FN(MappingImplementation)(ifcopenshell::geometry::impl::mapping_registry* mapping) {
static const std::string schema_name = STRINGIFY(IfcSchema);
POSTFIX_SCHEMA(factory_t) factory;
mapping->bind(schema_name, factory);
+1 -1
View File
@@ -590,7 +590,7 @@ const std::string& ifcopenshell::geometry::taxonomy::kind_to_string(kinds k) {
return values[k];
}
std::atomic_uint32_t item::counter_(0);
IFC_GEOM_API std::atomic_uint32_t item::counter_(0);
void ifcopenshell::geometry::taxonomy::item::print(std::ostream& o, int indent) const {
o << std::string(indent, ' ') << kind_to_string(kind()) << std::endl;