mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-06 07:51:47 +00:00
First slice plug-in refactor
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,9 +24,9 @@ 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}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
throw ifcopenshell::exception("No geometry serialization available for " + schema_name);
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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)(®istry);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
)
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user