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
+2
View File
@@ -562,6 +562,8 @@ if(NOT Boost_VERSION LESS 105800)
add_definitions(-DBOOST_OPTIONAL_USE_OLD_DEFINITION_OF_NONE)
endif()
add_subdirectory(../src/plugin plugin)
add_subdirectory(../src/ifcparse ifcparse)
set(IFCOPENSHELL_LIBRARIES IfcParse)
+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;
+3 -2
View File
@@ -34,6 +34,7 @@ list(APPEND IFCPARSE_CPP_FILES
set(IFCPARSE_FILES ${IFCPARSE_CPP_FILES} ${IFCPARSE_H_FILES})
add_library(IfcParse ${IFCPARSE_FILES})
add_library(parse ALIAS IfcParse)
set_target_properties(IfcParse PROPERTIES COMPILE_FLAGS -DIFC_PARSE_EXPORTS VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
if(IFCXML_SUPPORT)
@@ -49,9 +50,9 @@ if(IFCXML_SUPPORT)
endif()
if(WASM_BUILD)
target_link_libraries(IfcParse ${BCRYPT_LIBRARIES})
target_link_libraries(IfcParse plugin ${BCRYPT_LIBRARIES})
else()
target_link_libraries(IfcParse ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES})
target_link_libraries(IfcParse plugin ${Boost_LIBRARIES} ${BCRYPT_LIBRARIES})
endif()
# CMake installation targets
+3 -2
View File
@@ -25,11 +25,12 @@
********************************************************************************/
#include <string>
#include "ifc_parse_api.h"
#include "macros.h"
#if defined(IFCOPENSHELL_BRANCH) && defined(IFCOPENSHELL_COMMIT)
const char *IFCOPENSHELL_VERSION = STRINGIFY(IFCOPENSHELL_BRANCH) "-" STRINGIFY(IFCOPENSHELL_COMMIT);
IFC_PARSE_API const char *IFCOPENSHELL_VERSION = STRINGIFY(IFCOPENSHELL_BRANCH) "-" STRINGIFY(IFCOPENSHELL_COMMIT);
#else
const char *IFCOPENSHELL_VERSION = "0.8.0";
IFC_PARSE_API const char *IFCOPENSHELL_VERSION = "0.8.0";
#endif
+4 -1
View File
@@ -43,7 +43,7 @@
#include <vector>
extern const char *IFCOPENSHELL_VERSION;
extern IFC_PARSE_API const char *IFCOPENSHELL_VERSION;
namespace ifcopenshell {
@@ -59,6 +59,9 @@ class IFC_PARSE_API spf_lexer {
mutable size_t pool_index = 0;
public:
spf_lexer(const spf_lexer&) = delete;
spf_lexer& operator=(const spf_lexer&) = delete;
std::string& get_temp_string() const;
void reset_pool() const {
pool_index = 0;
+110 -100
View File
@@ -22,6 +22,7 @@
#include "express.h"
#include <map>
#include <mutex>
#ifdef HAS_SCHEMA_2x3
#include "schemas/Ifc2x3.h"
@@ -128,7 +129,60 @@ ifcopenshell::entity::~entity() {
delete inverse_attribute;
}
}
static std::map<std::string, const ifcopenshell::schema_definition*> schemas;
namespace {
std::string schema_key(const std::string& schema_name) {
return boost::to_upper_copy(schema_name);
}
ifcopenshell::plugin::module builtin_schema_module(const std::string& schema_name) {
ifcopenshell::plugin::metadata metadata;
metadata.kind_ = ifcopenshell::plugin::kind::parse_schema;
metadata.id = "parse.schema." + boost::to_lower_copy(schema_name);
metadata.schema = schema_name;
return ifcopenshell::plugin::module::builtin(metadata);
}
void register_builtin_schemas(ifcopenshell::schema_registry& registry) {
registry.bind("HEADER_SECTION_SCHEMA", &Header_section_schema::get_schema, &Header_section_schema::clear_schema, builtin_schema_module("HEADER_SECTION_SCHEMA"));
#ifdef HAS_SCHEMA_2x3
registry.bind("IFC2X3", &Ifc2x3::get_schema, &Ifc2x3::clear_schema, builtin_schema_module("IFC2X3"));
#endif
#ifdef HAS_SCHEMA_4
registry.bind("IFC4", &Ifc4::get_schema, &Ifc4::clear_schema, builtin_schema_module("IFC4"));
#endif
#ifdef HAS_SCHEMA_4x1
registry.bind("IFC4X1", &Ifc4x1::get_schema, &Ifc4x1::clear_schema, builtin_schema_module("IFC4X1"));
#endif
#ifdef HAS_SCHEMA_4x2
registry.bind("IFC4X2", &Ifc4x2::get_schema, &Ifc4x2::clear_schema, builtin_schema_module("IFC4X2"));
#endif
#ifdef HAS_SCHEMA_4x3_rc1
registry.bind("IFC4X3_RC1", &Ifc4x3_rc1::get_schema, &Ifc4x3_rc1::clear_schema, builtin_schema_module("IFC4X3_RC1"));
#endif
#ifdef HAS_SCHEMA_4x3_rc2
registry.bind("IFC4X3_RC2", &Ifc4x3_rc2::get_schema, &Ifc4x3_rc2::clear_schema, builtin_schema_module("IFC4X3_RC2"));
#endif
#ifdef HAS_SCHEMA_4x3_rc3
registry.bind("IFC4X3_RC3", &Ifc4x3_rc3::get_schema, &Ifc4x3_rc3::clear_schema, builtin_schema_module("IFC4X3_RC3"));
#endif
#ifdef HAS_SCHEMA_4x3_rc4
registry.bind("IFC4X3_RC4", &Ifc4x3_rc4::get_schema, &Ifc4x3_rc4::clear_schema, builtin_schema_module("IFC4X3_RC4"));
#endif
#ifdef HAS_SCHEMA_4x3
registry.bind("IFC4X3", &Ifc4x3::get_schema, &Ifc4x3::clear_schema, builtin_schema_module("IFC4X3"));
#endif
#ifdef HAS_SCHEMA_4x3_tc1
registry.bind("IFC4X3_TC1", &Ifc4x3_tc1::get_schema, &Ifc4x3_tc1::clear_schema, builtin_schema_module("IFC4X3_TC1"));
#endif
#ifdef HAS_SCHEMA_4x3_add1
registry.bind("IFC4X3_ADD1", &Ifc4x3_add1::get_schema, &Ifc4x3_add1::clear_schema, builtin_schema_module("IFC4X3_ADD1"));
#endif
#ifdef HAS_SCHEMA_4x3_add2
registry.bind("IFC4X3_ADD2", &Ifc4x3_add2::get_schema, &Ifc4x3_add2::clear_schema, builtin_schema_module("IFC4X3_ADD2"));
#endif
}
}
ifcopenshell::schema_definition::schema_definition(const std::string& name, const std::vector<const declaration*>& declarations)
: name_(name)
@@ -151,7 +205,7 @@ ifcopenshell::schema_definition::schema_definition(const std::string& name, cons
entities_.push_back((**it).as_entity());
}
}
schemas[name_] = this;
register_schema(this);
}
ifcopenshell::schema_definition::~schema_definition() {
@@ -161,111 +215,67 @@ ifcopenshell::schema_definition::~schema_definition() {
}
void ifcopenshell::register_schema(schema_definition* schema) {
schemas.insert({boost::to_upper_copy(schema->name()), schema});
schema_registry_instance().bind(schema);
}
ifcopenshell::schema_registry& ifcopenshell::schema_registry_instance() {
static schema_registry registry;
static std::once_flag once;
std::call_once(once, register_builtin_schemas, std::ref(registry));
return registry;
}
void ifcopenshell::schema_registry::bind(const std::string& schema_name, get_schema_fn get, clear_schema_fn clear, const plugin::module& module) {
auto& entry = entries_[schema_key(schema_name)];
entry.get_ = get;
entry.clear_ = clear;
entry.module_ = module;
}
void ifcopenshell::schema_registry::bind(schema_definition* schema) {
auto& entry = entries_[schema_key(schema->name())];
entry.schema_ = schema;
}
const ifcopenshell::schema_definition* ifcopenshell::schema_registry::get(const std::string& schema_name) {
auto iter = entries_.find(schema_key(schema_name));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No schema named " + schema_name);
}
if (!iter->second.schema_ && iter->second.get_) {
iter->second.schema_ = &iter->second.get_();
}
if (!iter->second.schema_) {
throw ifcopenshell::exception("No schema named " + schema_name);
}
return iter->second.schema_;
}
std::vector<std::string> ifcopenshell::schema_registry::names() const {
std::vector<std::string> names;
for (const auto& pair : entries_) {
names.push_back(pair.first);
}
return names;
}
void ifcopenshell::schema_registry::clear() {
for (auto& pair : entries_) {
if (pair.second.clear_) {
pair.second.clear_();
}
pair.second.schema_ = nullptr;
}
}
const ifcopenshell::schema_definition* ifcopenshell::schema_by_name(const std::string& name) {
// TODO: initialize automatically somehow
Header_section_schema::get_schema();
#ifdef HAS_SCHEMA_2x3
Ifc2x3::get_schema();
#endif
#ifdef HAS_SCHEMA_4
Ifc4::get_schema();
#endif
#ifdef HAS_SCHEMA_4x1
Ifc4x1::get_schema();
#endif
#ifdef HAS_SCHEMA_4x2
Ifc4x2::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc1
Ifc4x3_rc1::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc2
Ifc4x3_rc2::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc3
Ifc4x3_rc3::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc4
Ifc4x3_rc4::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3
Ifc4x3::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_tc1
Ifc4x3_tc1::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_add1
Ifc4x3_add1::get_schema();
#endif
#ifdef HAS_SCHEMA_4x3_add2
Ifc4x3_add2::get_schema();
#endif
std::map<std::string, const ifcopenshell::schema_definition*>::const_iterator iter = schemas.find(boost::to_upper_copy(name));
if (iter == schemas.end()) {
throw ifcopenshell::exception("No schema named " + name);
}
return iter->second;
return schema_registry_instance().get(name);
}
std::vector<std::string> ifcopenshell::schema_names() {
// Load schema modules
try {
ifcopenshell::schema_by_name("IFC2X3");
} catch (ifcopenshell::exception&) {
}
// Populate vector with map keys
std::vector<std::string> return_value;
for (auto& pair : schemas) {
return_value.push_back(pair.first);
}
return return_value;
return schema_registry_instance().names();
}
void ifcopenshell::clear_schemas() {
#ifdef HAS_SCHEMA_2x3
Ifc2x3::clear_schema();
#endif
#ifdef HAS_SCHEMA_4
Ifc4::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x1
Ifc4x1::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x2
Ifc4x2::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc1
Ifc4x3_rc1::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc2
Ifc4x3_rc2::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc3
Ifc4x3_rc3::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_rc4
Ifc4x3_rc4::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3
Ifc4x3::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_tc1
Ifc4x3_tc1::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_add1
Ifc4x3_add1::clear_schema();
#endif
#ifdef HAS_SCHEMA_4x3_add2
Ifc4x3_add2::clear_schema();
#endif
Header_section_schema::clear_schema();
// Schemas are owned by their respective modules in a unique_ptr, so just clear the map
schemas.clear();
schema_registry_instance().clear();
}
+26
View File
@@ -21,11 +21,13 @@
#define IFCSCHEMA_H
#include "exception.h"
#include "../plugin/plugin.h"
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <cctype>
#include <iterator>
#include <map>
#include <string>
#include <vector>
#include <optional>
@@ -497,6 +499,30 @@ class IFC_PARSE_API schema_definition {
const std::string& name() const { return name_; }
};
class IFC_PARSE_API schema_registry {
public:
typedef const schema_definition& (*get_schema_fn)();
typedef void (*clear_schema_fn)();
void bind(const std::string& schema_name, get_schema_fn get, clear_schema_fn clear, const plugin::module& module = plugin::module());
void bind(schema_definition* schema);
const schema_definition* get(const std::string& schema_name);
std::vector<std::string> names() const;
void clear();
private:
struct entry {
const schema_definition* schema_ = nullptr;
get_schema_fn get_ = nullptr;
clear_schema_fn clear_ = nullptr;
plugin::module module_;
};
std::map<std::string, entry> entries_;
};
IFC_PARSE_API schema_registry& schema_registry_instance();
IFC_PARSE_API const schema_definition* schema_by_name(const std::string& schema_name);
IFC_PARSE_API std::vector<std::string> schema_names();
+22
View File
@@ -0,0 +1,22 @@
file(GLOB PLUGIN_H_FILES *.h)
file(GLOB PLUGIN_CPP_FILES *.cpp)
add_library(plugin ${PLUGIN_CPP_FILES} ${PLUGIN_H_FILES})
set_target_properties(plugin PROPERTIES
COMPILE_FLAGS "-DPLUGIN_EXPORTS"
VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
target_compile_definitions(plugin PRIVATE
BOOST_DLL_USE_STD_FS
PLUGIN_IFCOPENSHELL_VERSION="${PROJECT_VERSION}"
)
target_link_libraries(plugin PRIVATE ${Boost_LIBRARIES})
install(TARGETS plugin)
install(FILES ${PLUGIN_H_FILES}
DESTINATION ${INCLUDEDIR}/plugin
)
+154
View File
@@ -0,0 +1,154 @@
/********************************************************************************
* *
* 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 "plugin.h"
#include <boost/dll/shared_library.hpp>
#include <sstream>
#include <stdexcept>
namespace {
using plugin_abi_fn = ifcopenshell::plugin::abi_info(*)();
using plugin_metadata_fn = ifcopenshell::plugin::metadata(*)();
std::string compiler_id() {
#if defined(_MSC_VER)
return "msvc";
#elif defined(__clang__)
return "clang";
#elif defined(__GNUC__)
return "gcc";
#else
return "unknown";
#endif
}
std::string compiler_version() {
#if defined(_MSC_FULL_VER)
return std::to_string(_MSC_FULL_VER);
#elif defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__)
return std::to_string(__clang_major__) + "." + std::to_string(__clang_minor__) + "." + std::to_string(__clang_patchlevel__);
#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
return std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + std::to_string(__GNUC_PATCHLEVEL__);
#else
return "unknown";
#endif
}
bool is_debug_build() {
#if defined(NDEBUG)
return false;
#else
return true;
#endif
}
}
struct ifcopenshell::plugin::module::data {
metadata metadata_;
std::filesystem::path path_;
std::shared_ptr<boost::dll::shared_library> library_;
};
ifcopenshell::plugin::module::module()
: data_(std::make_shared<data>())
{}
ifcopenshell::plugin::module::module(const metadata& metadata)
: data_(std::make_shared<data>())
{
data_->metadata_ = metadata;
}
ifcopenshell::plugin::module::module(std::shared_ptr<data> data)
: data_(std::move(data))
{}
ifcopenshell::plugin::module ifcopenshell::plugin::module::builtin(const metadata& metadata) {
return module(metadata);
}
const ifcopenshell::plugin::metadata& ifcopenshell::plugin::module::meta() const {
return data_->metadata_;
}
const std::filesystem::path& ifcopenshell::plugin::module::path() const {
return data_->path_;
}
bool ifcopenshell::plugin::module::is_dynamic() const {
return data_->library_ != nullptr;
}
bool ifcopenshell::plugin::module::is_loaded() const {
return data_->library_ && data_->library_->is_loaded();
}
ifcopenshell::plugin::manager::manager() = default;
void ifcopenshell::plugin::manager::add_search_path(const std::filesystem::path& path) {
search_paths_.push_back(path);
}
const std::vector<std::filesystem::path>& ifcopenshell::plugin::manager::search_paths() const {
return search_paths_;
}
ifcopenshell::plugin::module ifcopenshell::plugin::manager::load(const std::filesystem::path& path) const {
auto library = std::make_shared<boost::dll::shared_library>(path, boost::dll::load_mode::default_mode);
auto abi = library->get_alias<plugin_abi_fn>("ifcopenshell_plugin_abi_v1")();
validate_abi(abi);
auto metadata = library->get_alias<plugin_metadata_fn>("ifcopenshell_plugin_metadata_v1")();
auto data = std::make_shared<module::data>();
data->metadata_ = metadata;
data->path_ = path;
data->library_ = std::move(library);
return module(data);
}
ifcopenshell::plugin::abi_info ifcopenshell::plugin::host_abi() {
abi_info abi;
abi.debug_build = is_debug_build();
abi.compiler_id = compiler_id();
abi.compiler_version = compiler_version();
abi.ifcopenshell_version = PLUGIN_IFCOPENSHELL_VERSION;
return abi;
}
void ifcopenshell::plugin::validate_abi(const abi_info& abi) {
const auto host = host_abi();
if (abi.plugin_api_version == host.plugin_api_version &&
abi.pointer_size == host.pointer_size &&
abi.debug_build == host.debug_build &&
abi.compiler_id == host.compiler_id &&
abi.compiler_version == host.compiler_version) {
return;
}
std::ostringstream stream;
stream << "Incompatible plugin ABI";
stream << " (plugin api " << abi.plugin_api_version << ", host api " << host.plugin_api_version << ")";
stream << " (plugin compiler " << abi.compiler_id << " " << abi.compiler_version;
stream << ", host compiler " << host.compiler_id << " " << host.compiler_version << ")";
stream << " (plugin pointer size " << abi.pointer_size << ", host pointer size " << host.pointer_size << ")";
stream << " (plugin debug " << abi.debug_build << ", host debug " << host.debug_build << ")";
throw std::runtime_error(stream.str());
}
+99
View File
@@ -0,0 +1,99 @@
/********************************************************************************
* *
* 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 IFCOPENSHELL_PLUGIN_H
#define IFCOPENSHELL_PLUGIN_H
#include "plugin_api.h"
#include <cstdint>
#include <filesystem>
#include <memory>
#include <string>
#include <vector>
namespace ifcopenshell {
namespace plugin {
enum class kind {
parse_schema,
mapping,
kernel,
document_serializer,
geometry_serializer,
opencascade_geometry_ifc_writer
};
struct PLUGIN_API abi_info {
uint32_t plugin_api_version = 1;
uint32_t pointer_size = sizeof(void*);
bool debug_build = false;
std::string compiler_id;
std::string compiler_version;
std::string ifcopenshell_version;
};
struct PLUGIN_API metadata {
kind kind_ = kind::kernel;
std::string id;
std::string schema;
std::string format;
};
class PLUGIN_API module {
public:
module();
explicit module(const metadata& metadata);
static module builtin(const metadata& metadata);
const metadata& meta() const;
const std::filesystem::path& path() const;
bool is_dynamic() const;
bool is_loaded() const;
private:
struct data;
std::shared_ptr<data> data_;
explicit module(std::shared_ptr<data> data);
friend class manager;
};
class PLUGIN_API manager {
public:
manager();
void add_search_path(const std::filesystem::path& path);
const std::vector<std::filesystem::path>& search_paths() const;
module load(const std::filesystem::path& path) const;
private:
std::vector<std::filesystem::path> search_paths_;
};
PLUGIN_API abi_info host_abi();
PLUGIN_API void validate_abi(const abi_info& abi);
}
}
#endif
+37
View File
@@ -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 <http://www.gnu.org/licenses/>. *
* *
********************************************************************************/
#ifndef PLUGIN_API_H
#define PLUGIN_API_H
#ifdef IFC_SHARED_BUILD
#ifdef _WIN32
#ifdef PLUGIN_EXPORTS
#define PLUGIN_API __declspec(dllexport)
#else
#define PLUGIN_API __declspec(dllimport)
#endif
#else
#define PLUGIN_API __attribute__((visibility("default")))
#endif
#else
#define PLUGIN_API
#endif
#endif
+2 -1
View File
@@ -5,6 +5,7 @@ file(GLOB SERIALIZERS_CPP_FILES *.cpp)
set(SERIALIZERS_FILES ${SERIALIZERS_H_FILES} ${SERIALIZERS_CPP_FILES})
add_library(Serializers ${SERIALIZERS_FILES})
add_library(serialization ALIAS Serializers)
set_target_properties(Serializers PROPERTIES COMPILE_FLAGS "-DSERIALIZERS_EXPORTS" VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
set(SERIALIZER_SCHEMA_LIBRARIES Serializers ${SERIALIZER_SCHEMA_LIBRARIES} PARENT_SCOPE)
@@ -20,7 +21,7 @@ endif()
target_link_libraries(Serializers
PRIVATE
${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}
IfcGeom ${OpenCASCADE_LIBRARIES} ${kernel_libraries} IfcParse
IfcGeom ${OpenCASCADE_LIBRARIES} IfcParse
)
install(TARGETS Serializers)
@@ -5,7 +5,7 @@ set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES})
foreach(schema ${SCHEMA_VERSIONS})
add_library(Serializers_ifc${schema} OBJECT ${SERIALIZERS_S_FILES})
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} Serializers_ifc${schema})
set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
set_target_properties(Serializers_ifc${schema} PROPERTIES COMPILE_FLAGS "-DSERIALIZERS_EXPORTS -DIfcSchema=Ifc${schema}")
if(WASM_BUILD)
target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES})
else()