Continue work on plug-in and tests

This commit is contained in:
Thomas Krijnen
2026-05-06 21:17:25 +02:00
parent 4670715ef3
commit 98ff457fd6
61 changed files with 16000 additions and 16377 deletions
+3 -1
View File
@@ -11,7 +11,9 @@ set(SERIALIZER_RUNTIME_CPP_FILES
set(SCHEMA_AGNOSTIC_FILES ${SCHEMA_AGNOSTIC_H_FILES} ${SCHEMA_AGNOSTIC_CPP_FILES} ${SERIALIZER_RUNTIME_CPP_FILES})
add_library(IfcGeom ${SCHEMA_AGNOSTIC_FILES})
add_library(geometry ALIAS IfcGeom)
set_target_properties(IfcGeom PROPERTIES
OUTPUT_NAME "ifcopenshell.geometry"
)
set_target_properties(IfcGeom PROPERTIES COMPILE_FLAGS -DIFC_GEOM_EXPORTS)
if (NOT CREATE_BUNDLE)
set_target_properties(IfcGeom PROPERTIES VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
+10 -6
View File
@@ -6,8 +6,6 @@
#include <boost/algorithm/string/case_conv.hpp>
#include <mutex>
namespace {
std::string writer_schema_key(const std::string& schema_name) {
return boost::to_upper_copy(schema_name);
@@ -16,8 +14,6 @@ namespace {
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, load_opencascade_geometry_ifc_writer_plugins, std::ref(registry));
return registry;
}
@@ -30,7 +26,11 @@ void IfcGeom::opencascade_geometry_ifc_writer_registry::bind(const std::string&
}
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()));
auto iter = entries_.find(writer_schema_key(f.schema()->name()));
if (iter == entries_.end()) {
load_opencascade_geometry_ifc_writer_plugin(const_cast<opencascade_geometry_ifc_writer_registry&>(*this), f.schema()->name());
iter = entries_.find(writer_schema_key(f.schema()->name()));
}
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
}
@@ -38,7 +38,11 @@ express::Base IfcGeom::opencascade_geometry_ifc_writer_registry::tesselate(ifcop
}
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()));
auto iter = entries_.find(writer_schema_key(f.schema()->name()));
if (iter == entries_.end()) {
load_opencascade_geometry_ifc_writer_plugin(const_cast<opencascade_geometry_ifc_writer_registry&>(*this), f.schema()->name());
iter = entries_.find(writer_schema_key(f.schema()->name()));
}
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry serialization available for " + f.schema()->name());
}
@@ -55,3 +55,25 @@ void IfcGeom::load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_
register_plugin(registry, module);
}
}
bool IfcGeom::load_opencascade_geometry_ifc_writer_plugin(opencascade_geometry_ifc_writer_registry& registry, const std::string& schema_name) {
ifcopenshell::plugin::manager manager;
manager.add_search_path(opencascade_geometry_ifc_writer_plugin_directory());
const auto expected_schema = boost::to_upper_copy(schema_name);
const auto basename = std::string(opencascade_geometry_ifc_writer_plugin_prefix) + boost::to_lower_copy(schema_name);
for (const auto& path : manager.discover_exact(basename)) {
auto module = manager.load(path);
if (module.meta().kind_ != ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer ||
module.meta().schema != expected_schema) {
continue;
}
auto register_plugin = module.get_alias<register_opencascade_geometry_ifc_writer_plugin_fn>(opencascade_geometry_ifc_writer_plugin_registration_symbol());
register_plugin(registry, module);
return true;
}
return false;
}
@@ -32,6 +32,7 @@ IFC_GEOMSERIALIZATION_API const char* opencascade_geometry_ifc_writer_plugin_reg
IFC_GEOMSERIALIZATION_API ifcopenshell::plugin::metadata opencascade_geometry_ifc_writer_plugin_metadata(const std::string& schema_name);
IFC_GEOMSERIALIZATION_API std::filesystem::path opencascade_geometry_ifc_writer_plugin_directory();
IFC_GEOMSERIALIZATION_API void load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_ifc_writer_registry& registry);
IFC_GEOMSERIALIZATION_API bool load_opencascade_geometry_ifc_writer_plugin(opencascade_geometry_ifc_writer_registry& registry, const std::string& schema_name);
}
@@ -2,10 +2,10 @@ if (NOT WASM_BUILD)
foreach(schema ${SCHEMA_VERSIONS})
add_library(geometry_serializer_ifc${schema} SHARED Serialization.cpp plugin.cpp)
target_link_libraries(geometry_serializer_ifc${schema} PRIVATE plugin geometry_serializer IfcGeom IfcParse ${OpenCASCADE_LIBRARIES})
target_link_libraries(geometry_serializer_ifc${schema} PRIVATE plugin geometry_serializer IfcGeom IfcParse parse_schema_ifc${schema} ${OpenCASCADE_LIBRARIES})
set_target_properties(geometry_serializer_ifc${schema} PROPERTIES
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
OUTPUT_NAME "geometry.serialization.ifc${schema}"
OUTPUT_NAME "ifcopenshell.geometry.serialization.ifc${schema}"
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
)
+5 -4
View File
@@ -4,7 +4,6 @@
#include "../ifcgeom/mapping_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <mutex>
namespace {
std::string mapping_key(const std::string& schema_name) {
@@ -15,8 +14,6 @@ namespace {
ifcopenshell::geometry::impl::mapping_registry& ifcopenshell::geometry::impl::mapping_registry_instance() {
static mapping_registry registry;
static std::once_flag once;
std::call_once(once, load_mapping_plugins, std::ref(registry));
return registry;
}
@@ -28,7 +25,11 @@ void ifcopenshell::geometry::impl::mapping_registry::bind(const std::string& sch
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);
auto it = entries_.find(schema_name_lower);
if (it == entries_.end()) {
load_mapping_plugin(*this, file->schema()->name());
it = entries_.find(schema_name_lower);
}
if (it == entries_.end()) {
throw ifcopenshell::exception("No geometry mapping registered for " + schema_name_lower);
}
+31
View File
@@ -19,10 +19,19 @@
#include "kernel_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <algorithm>
#include <stdexcept>
namespace {
constexpr const char* kernel_plugin_prefix = "geometry.kernel.";
std::string kernel_plugin_name(const std::string& backend_id) {
auto name = boost::to_lower_copy(backend_id);
name.erase(std::remove(name.begin(), name.end(), '-'), name.end());
return name;
}
}
const char* ifcopenshell::geometry::kernels::kernel_plugin_registration_symbol() {
@@ -54,3 +63,25 @@ void ifcopenshell::geometry::kernels::load_kernel_plugins(kernel_registry& regis
register_plugin(registry, module);
}
}
bool ifcopenshell::geometry::kernels::load_kernel_plugin(kernel_registry& registry, const std::string& backend_id) {
plugin::manager manager;
manager.add_search_path(kernel_plugin_directory());
const auto plugin_name = kernel_plugin_name(backend_id);
const auto basename = std::string(kernel_plugin_prefix) + plugin_name;
for (const auto& path : manager.discover_exact(basename)) {
auto module = manager.load(path);
if (module.meta().kind_ != plugin::kind::kernel ||
module.meta().id != basename) {
continue;
}
auto register_plugin = module.get_alias<register_kernel_plugin_fn>(kernel_plugin_registration_symbol());
register_plugin(registry, module);
return registry.has(backend_id);
}
return false;
}
+1
View File
@@ -34,6 +34,7 @@ namespace ifcopenshell {
IFC_GEOM_API ifcopenshell::plugin::metadata kernel_plugin_metadata(const std::string& plugin_name);
IFC_GEOM_API std::filesystem::path kernel_plugin_directory();
IFC_GEOM_API void load_kernel_plugins(kernel_registry& registry);
IFC_GEOM_API bool load_kernel_plugin(kernel_registry& registry, const std::string& backend_id);
}
}
+19 -3
View File
@@ -25,8 +25,9 @@
#include <boost/algorithm/string.hpp>
#include <algorithm>
#include <cstring>
#include <mutex>
#include <vector>
namespace {
std::string kernel_key(const std::string& backend_id) {
@@ -65,8 +66,6 @@ std::vector<ifcopenshell::geometry::kernels::kernel_info> ifcopenshell::geometry
ifcopenshell::geometry::kernels::kernel_registry& ifcopenshell::geometry::kernels::kernel_registry_instance() {
static kernel_registry registry;
static std::once_flag once;
std::call_once(once, load_kernel_plugins, std::ref(registry));
return registry;
}
@@ -74,6 +73,9 @@ std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel> ifcopenshell::g
auto geometry_library_lower = boost::to_lower_copy(geometry_library);
auto& registry = kernel_registry_instance();
if (!registry.has(geometry_library_lower)) {
load_kernel_plugin(registry, geometry_library_lower);
}
if (registry.has(geometry_library_lower)) {
return registry.create(geometry_library_lower, file, settings);
}
@@ -88,6 +90,20 @@ std::unique_ptr<ifcopenshell::geometry::kernels::AbstractKernel> ifcopenshell::g
throw ifcopenshell::exception("Invalid hybrid kernel " + geometry_library);
}
std::vector<std::string> candidates;
candidates.push_back(geometry_library_lower);
for (auto pos = geometry_library_lower.find('-'); pos != std::string::npos; pos = geometry_library_lower.find('-', pos + 1)) {
candidates.push_back(geometry_library_lower.substr(0, pos));
}
std::sort(candidates.begin(), candidates.end(), [](const auto& a, const auto& b) {
return a.size() > b.size();
});
for (const auto& candidate : candidates) {
if (!registry.has(candidate) && load_kernel_plugin(registry, candidate)) {
break;
}
}
std::string matched_backend_id;
for (const auto& info : registry.kernels()) {
const auto backend_id = kernel_key(info.backend_id);
+3 -3
View File
@@ -31,7 +31,7 @@ foreach(kernel ${GEOMETRY_KERNELS})
set_target_properties(${KERNEL_TARGET} PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS"
OUTPUT_NAME "geometry.kernel.${kernel}"
OUTPUT_NAME "ifcopenshell.geometry.kernel.${kernel}"
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
)
@@ -50,7 +50,7 @@ foreach(kernel ${GEOMETRY_KERNELS})
set_target_properties(${KERNEL_TARGET_SIMPLE} PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS -DIFOPSH_SIMPLE_KERNEL -DCGAL_HAS_THREADS"
OUTPUT_NAME "geometry.kernel.cgalsimple"
OUTPUT_NAME "ifcopenshell.geometry.kernel.cgalsimple"
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
)
@@ -76,7 +76,7 @@ foreach(kernel ${GEOMETRY_KERNELS})
)
set_target_properties(${TREE_TARGET} PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS"
OUTPUT_NAME "geometry.tree.opencascade.${tree_backend}"
OUTPUT_NAME "ifcopenshell.geometry.tree.opencascade.${tree_backend}"
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
)
+11 -2
View File
@@ -17,14 +17,23 @@ foreach(schema ${SCHEMA_VERSIONS})
add_library(geometry_mapping_ifc${schema} SHARED ${IFCGEOM_FILES})
set_target_properties(geometry_mapping_ifc${schema} PROPERTIES
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
OUTPUT_NAME "geometry.mapping.ifc${schema}"
OUTPUT_NAME "ifcopenshell.geometry.mapping.ifc${schema}"
RUNTIME_OUTPUT_DIRECTORY "${mapping_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${mapping_plugin_runtime_dir}"
)
ifcopenshell_wasm_plugin_link_options(geometry_mapping_ifc${schema} ifcopenshell_register_mapping_plugin_v1)
if(WASM_BUILD)
target_link_options(geometry_mapping_ifc${schema} PRIVATE "SHELL:-s ERROR_ON_UNDEFINED_SYMBOLS=0")
endif()
target_link_libraries(geometry_mapping_ifc${schema} PRIVATE ${plugin_when_not_wasm} IfcGeom IfcParse Eigen3::Eigen)
if(NOT WASM_BUILD)
set(schema_plugin_library parse_schema_ifc${schema})
else()
set(schema_plugin_library)
endif()
target_link_libraries(geometry_mapping_ifc${schema} PRIVATE ${plugin_when_not_wasm} IfcGeom IfcParse ${schema_plugin_library} Eigen3::Eigen)
list(APPEND mapping_libraries geometry_mapping_ifc${schema})
+22
View File
@@ -55,3 +55,25 @@ void ifcopenshell::geometry::impl::load_mapping_plugins(mapping_registry& regist
register_plugin(registry, module);
}
}
bool ifcopenshell::geometry::impl::load_mapping_plugin(mapping_registry& registry, const std::string& schema_name) {
plugin::manager manager;
manager.add_search_path(mapping_plugin_directory());
const auto expected_schema = boost::to_upper_copy(schema_name);
const auto basename = std::string(mapping_plugin_prefix) + boost::to_lower_copy(schema_name);
for (const auto& path : manager.discover_exact(basename)) {
auto module = manager.load(path);
if (module.meta().kind_ != plugin::kind::mapping ||
module.meta().schema != expected_schema) {
continue;
}
auto register_plugin = module.get_alias<register_mapping_plugin_fn>(mapping_plugin_registration_symbol());
register_plugin(registry, module);
return true;
}
return false;
}
+1
View File
@@ -34,6 +34,7 @@ namespace ifcopenshell {
IFC_GEOM_API ifcopenshell::plugin::metadata mapping_plugin_metadata(const std::string& schema_name);
IFC_GEOM_API std::filesystem::path mapping_plugin_directory();
IFC_GEOM_API void load_mapping_plugins(mapping_registry& registry);
IFC_GEOM_API bool load_mapping_plugin(mapping_registry& registry, const std::string& schema_name);
}
}
+24
View File
@@ -19,6 +19,8 @@
#include "tree_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace {
constexpr const char* tree_plugin_prefix = "geometry.tree.";
}
@@ -52,3 +54,25 @@ void ifcopenshell::geometry::trees::load_tree_plugins(tree_registry& registry) {
register_plugin(registry, module);
}
}
bool ifcopenshell::geometry::trees::load_tree_plugin(tree_registry& registry, const std::string& backend_id) {
plugin::manager manager;
manager.add_search_path(tree_plugin_directory());
const auto plugin_name = boost::to_lower_copy(backend_id);
const auto basename = std::string(tree_plugin_prefix) + plugin_name;
for (const auto& path : manager.discover_exact(basename)) {
auto module = manager.load(path);
if (module.meta().kind_ != plugin::kind::tree ||
module.meta().id != basename) {
continue;
}
auto register_plugin = module.get_alias<register_tree_plugin_fn>(tree_plugin_registration_symbol());
register_plugin(registry, module);
return registry.has(backend_id);
}
return false;
}
+1
View File
@@ -34,6 +34,7 @@ namespace ifcopenshell {
IFC_GEOM_API ifcopenshell::plugin::metadata tree_plugin_metadata(const std::string& plugin_name);
IFC_GEOM_API std::filesystem::path tree_plugin_directory();
IFC_GEOM_API void load_tree_plugins(tree_registry& registry);
IFC_GEOM_API bool load_tree_plugin(tree_registry& registry, const std::string& backend_id);
}
}
+5 -5
View File
@@ -24,8 +24,6 @@
#include <boost/algorithm/string.hpp>
#include <mutex>
namespace {
std::string tree_key(const std::string& backend_id) {
return boost::to_lower_copy(backend_id);
@@ -134,11 +132,13 @@ std::unique_ptr<ifcopenshell::geometry::trees::abstract_tree> ifcopenshell::geom
ifcopenshell::geometry::trees::tree_registry& ifcopenshell::geometry::trees::tree_registry_instance() {
static tree_registry registry;
static std::once_flag once;
std::call_once(once, load_tree_plugins, std::ref(registry));
return registry;
}
std::unique_ptr<ifcopenshell::geometry::trees::abstract_tree> ifcopenshell::geometry::trees::construct(const std::string& backend_id) {
return tree_registry_instance().create(backend_id);
auto& registry = tree_registry_instance();
if (!registry.has(backend_id)) {
load_tree_plugin(registry, backend_id);
}
return registry.create(backend_id);
}