tree and document plug-ins

This commit is contained in:
Thomas Krijnen
2026-04-17 11:24:09 +02:00
parent 3824e7b449
commit d2cc66fdf0
60 changed files with 2207 additions and 766 deletions
-1
View File
@@ -595,7 +595,6 @@ endif(BUILD_IFCGEOM)
if(BUILD_CONVERT OR BUILD_IFCPYTHON)
add_subdirectory(../src/serializers serializers)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} ${SERIALIZER_SCHEMA_LIBRARIES})
endif(BUILD_CONVERT OR BUILD_IFCPYTHON)
if(BUILD_CONVERT)
+3
View File
@@ -2,5 +2,8 @@
add_executable(IfcConvert IfcConvert.cpp)
target_link_libraries(IfcConvert IfcGeom IfcParse Serializers ${OpenCASCADE_LIBRARIES} ${Boost_LIBRARIES} ${HDF5_LIBRARIES} ${USD_LIBRARIES})
if(kernel_libraries OR mapping_libraries OR document_serializer_libraries)
add_dependencies(IfcConvert ${kernel_libraries} ${mapping_libraries} ${document_serializer_libraries})
endif()
install(TARGETS IfcConvert)
+5 -2
View File
@@ -1,4 +1,5 @@
add_subdirectory(mapping)
set(mapping_libraries ${mapping_libraries} PARENT_SCOPE)
# IfcGeom (schema agnostic)
file(GLOB SCHEMA_AGNOSTIC_H_FILES *.h)
@@ -18,16 +19,18 @@ find_package(Eigen3 REQUIRED)
add_subdirectory(kernels)
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
set(tree_libraries ${tree_libraries} PARENT_SCOPE)
if(WASM_BUILD)
target_link_libraries(IfcGeom plugin ${Boost_LIBRARIES} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
target_link_libraries(IfcGeom plugin ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
else()
target_link_libraries(IfcGeom plugin IfcParse ${Boost_LIBRARIES} ${mapping_libraries} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
target_link_libraries(IfcGeom plugin IfcParse ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} "Eigen3::Eigen")
endif()
if((BUILD_CONVERT OR BUILD_IFCPYTHON) AND WITH_OPENCASCADE)
add_subdirectory(Serialization)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
endif()
install(FILES ${SCHEMA_AGNOSTIC_H_FILES}
+39 -1
View File
@@ -58,6 +58,7 @@ struct EdgeKey {
}
};
#ifndef SWIG
namespace std {
template <>
struct hash<EdgeKey> {
@@ -66,6 +67,7 @@ namespace std {
}
};
}
#endif
namespace IfcGeom {
@@ -73,6 +75,7 @@ namespace IfcGeom {
class IFC_GEOM_API Triangulation;
}
#ifndef SWIG
template <typename T>
constexpr T add_(T a, T b) {
return a + b;
@@ -107,6 +110,7 @@ namespace IfcGeom {
constexpr T negate_(T a) {
return -a;
}
#endif
class IFC_GEOM_API OpaqueNumber {
public:
@@ -126,6 +130,7 @@ namespace IfcGeom {
};
// @todo this can simply be a template class, to remove the need for the NumberEpeck in CGAL kernel.
#ifndef SWIG
class IFC_GEOM_API NumberNativeDouble : public OpaqueNumber {
private:
double value_;
@@ -189,7 +194,24 @@ namespace IfcGeom {
return new NumberNativeDouble(value_);
}
};
#else
class IFC_GEOM_API NumberNativeDouble : public OpaqueNumber {
public:
NumberNativeDouble(double v);
virtual double to_double() const;
virtual std::string to_string() const;
virtual OpaqueNumber* operator+(OpaqueNumber* other) const;
virtual OpaqueNumber* operator-(OpaqueNumber* other) const;
virtual OpaqueNumber* operator*(OpaqueNumber* other) const;
virtual OpaqueNumber* operator/(OpaqueNumber* other) const;
virtual bool operator==(OpaqueNumber* other) const;
virtual bool operator<(OpaqueNumber* other) const;
virtual OpaqueNumber* operator-() const;
virtual OpaqueNumber* clone() const;
};
#endif
#ifndef SWIG
template <size_t N>
struct IFC_GEOM_API OpaqueCoordinate {
private:
@@ -251,10 +273,25 @@ namespace IfcGeom {
}
}
};
#else
template <size_t N>
struct IFC_GEOM_API OpaqueCoordinate {
OpaqueCoordinate();
OpaqueCoordinate(const OpaqueCoordinate& other);
OpaqueCoordinate& operator=(const OpaqueCoordinate& other);
~OpaqueCoordinate();
OpaqueNumber* get(size_t i) const;
void set(size_t i, OpaqueNumber* n);
};
#endif
class IFC_GEOM_API ConversionResultShape {
public:
#ifdef SWIG
virtual std::string backend_id() const = 0;
#else
virtual std::string_view backend_id() const = 0;
#endif
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;
@@ -346,7 +383,7 @@ namespace IfcGeom {
typedef std::vector<ConversionResult> ConversionResults;
#ifndef SWIG
namespace util {
// @todo this is now moved to occt kernel, do we need something similar in cgal?
// bool flatten_shape_list(const IfcGeom::ConversionResults& shapes, TopoDS_Shape& result, bool fuse, double tol);
@@ -424,6 +461,7 @@ namespace IfcGeom {
return loops;
}
}
#endif
}
#endif
+11 -6
View File
@@ -1,15 +1,20 @@
set(geometry_serialization_plugin_runtime_dir "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
add_subdirectory(schema)
add_library(geometry_serializer Serialization.cpp)
add_library(geometry_serializer Serialization.cpp opencascade_geometry_ifc_writer_plugin.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 plugin ${geometry_serializer_libraries} IfcGeom IfcParse)
set_target_properties(geometry_serializer PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS"
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
)
target_link_libraries(geometry_serializer plugin IfcGeom IfcParse ${OpenCASCADE_LIBRARIES})
target_link_libraries(geometry_serializer geometry_kernel_opencascade)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer" ${geometry_serializer_libraries})
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} "geometry_serializer")
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
file(GLOB IFCGEOM_SERIALIZATION_H_FILE *.h)
install(FILES ${IFCGEOM_SERIALIZATION_H_FILE}
install(FILES Serialization.h
DESTINATION ${INCLUDEDIR}/ifcgeom/Serialization
)
+3 -47
View File
@@ -1,11 +1,10 @@
#include "Serialization.h"
#include "opencascade_geometry_ifc_writer_plugin.h"
#include "../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
#include "../../ifcparse/file.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <mutex>
@@ -13,55 +12,12 @@ namespace {
std::string writer_schema_key(const std::string& schema_name) {
return boost::to_upper_copy(schema_name);
}
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);
}
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;
}
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);
}
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);
}
}
#define EXTERNAL_TESSELATE(r, data, elem) \
express::Base BOOST_PP_CAT(tesselate_Ifc, elem)(ifcopenshell::file&, const TopoDS_Shape& shape, double deflection);
#define EXTERNAL_SERIALISE(r, data, elem) \
express::Base BOOST_PP_CAT(serialise_Ifc, elem)(ifcopenshell::file&, const TopoDS_Shape& shape, bool advanced);
#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))));
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_TESSELATE, , SCHEMA_SEQ)
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_SERIALISE, , 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)
});
std::call_once(once, load_opencascade_geometry_ifc_writer_plugins, std::ref(registry));
return registry;
}
@@ -69,7 +25,7 @@ void IfcGeom::opencascade_geometry_ifc_writer_registry::bind(const std::string&
entry entry;
entry.serialise_ = serialise;
entry.tesselate_ = tesselate;
entry.module_ = module;
entry.module_ = module.meta().id.empty() ? ifcopenshell::plugin::module(opencascade_geometry_ifc_writer_plugin_metadata(schema_name)) : module;
entries_[writer_schema_key(schema_name)] = entry;
}
@@ -20,7 +20,9 @@
#ifndef IFC_GEOMSERIALIZATION_API_H
#define IFC_GEOMSERIALIZATION_API_H
#ifdef _WIN32
#ifdef SWIG
#define IFC_GEOMSERIALIZATION_API
#elif defined(_WIN32)
#ifdef IFC_GEOMSERIALIZATION_EXPORTS
#define IFC_GEOMSERIALIZATION_API __declspec(dllexport)
#else
@@ -0,0 +1,57 @@
/********************************************************************************
* *
* 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 "opencascade_geometry_ifc_writer_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace {
constexpr const char* opencascade_geometry_ifc_writer_plugin_prefix = "geometry.serialization.";
}
const char* IfcGeom::opencascade_geometry_ifc_writer_plugin_registration_symbol() {
return "ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1";
}
ifcopenshell::plugin::metadata IfcGeom::opencascade_geometry_ifc_writer_plugin_metadata(const std::string& schema_name) {
ifcopenshell::plugin::metadata metadata;
metadata.kind_ = ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer;
metadata.id = opencascade_geometry_ifc_writer_plugin_prefix + boost::to_lower_copy(schema_name);
metadata.schema = boost::to_upper_copy(schema_name);
return metadata;
}
std::filesystem::path IfcGeom::opencascade_geometry_ifc_writer_plugin_directory() {
return ifcopenshell::plugin::module_directory(reinterpret_cast<const void*>(&IfcGeom::load_opencascade_geometry_ifc_writer_plugins));
}
void IfcGeom::load_opencascade_geometry_ifc_writer_plugins(opencascade_geometry_ifc_writer_registry& registry) {
ifcopenshell::plugin::manager manager;
manager.add_search_path(opencascade_geometry_ifc_writer_plugin_directory());
for (const auto& path : manager.discover(opencascade_geometry_ifc_writer_plugin_prefix)) {
auto module = manager.load(path);
if (module.meta().kind_ != ifcopenshell::plugin::kind::opencascade_geometry_ifc_writer) {
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);
}
}
@@ -0,0 +1,38 @@
/********************************************************************************
* *
* 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_OPENCASCADE_GEOMETRY_IFC_WRITER_PLUGIN_H
#define IFCOPENSHELL_OPENCASCADE_GEOMETRY_IFC_WRITER_PLUGIN_H
#include "Serialization.h"
#include <filesystem>
namespace IfcGeom {
typedef void register_opencascade_geometry_ifc_writer_plugin_fn(opencascade_geometry_ifc_writer_registry&, const ifcopenshell::plugin::module&);
IFC_GEOMSERIALIZATION_API const char* opencascade_geometry_ifc_writer_plugin_registration_symbol();
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);
}
#endif
@@ -1,7 +1,12 @@
foreach(schema ${SCHEMA_VERSIONS})
add_library(geometry_serializer_ifc${schema} STATIC Serialization.cpp)
target_link_libraries(geometry_serializer_ifc${schema} ${OpenCASCADE_LIBRARIES})
set_target_properties(geometry_serializer_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOMSERIALIZATION_EXPORTS -DIfcSchema=Ifc${schema}")
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})
set_target_properties(geometry_serializer_ifc${schema} PROPERTIES
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
OUTPUT_NAME "geometry.serialization.ifc${schema}"
RUNTIME_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${geometry_serialization_plugin_runtime_dir}"
)
list(APPEND geometry_serializer_libraries geometry_serializer_ifc${schema})
endforeach()
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
@@ -0,0 +1,69 @@
/********************************************************************************
* *
* 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 "../opencascade_geometry_ifc_writer_plugin.h"
#include "../../../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
#include "../../../ifcparse/exception.h"
#include "../../../ifcparse/macros.h"
#include <boost/dll/alias.hpp>
express::Base POSTFIX_SCHEMA(serialise)(ifcopenshell::file& f, const TopoDS_Shape& shape, bool advanced);
express::Base POSTFIX_SCHEMA(tesselate)(ifcopenshell::file& f, const TopoDS_Shape& shape, double deflection);
namespace {
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 serialise_adapter(ifcopenshell::file& f, const IfcGeom::ConversionResultShape& shape, bool advanced) {
return POSTFIX_SCHEMA(serialise)(f, require_opencascade_shape(shape).shape(), advanced);
}
express::Base tesselate_adapter(ifcopenshell::file& f, const IfcGeom::ConversionResultShape& shape, double deflection) {
return POSTFIX_SCHEMA(tesselate)(f, require_opencascade_shape(shape).shape(), deflection);
}
}
namespace IfcGeom {
namespace opencascade_geometry_ifc_writer_plugin {
ifcopenshell::plugin::abi_info plugin_abi() {
return ifcopenshell::plugin::host_abi();
}
ifcopenshell::plugin::metadata plugin_metadata() {
return opencascade_geometry_ifc_writer_plugin_metadata(STRINGIFY(IfcSchema));
}
void register_plugin(opencascade_geometry_ifc_writer_registry& registry, const ifcopenshell::plugin::module& module) {
registry.bind(STRINGIFY(IfcSchema), &serialise_adapter, &tesselate_adapter, module);
}
}
}
BOOST_DLL_ALIAS(IfcGeom::opencascade_geometry_ifc_writer_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(IfcGeom::opencascade_geometry_ifc_writer_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(IfcGeom::opencascade_geometry_ifc_writer_plugin::register_plugin, ifcopenshell_register_opencascade_geometry_ifc_writer_plugin_v1)
+5 -33
View File
@@ -1,57 +1,29 @@
#include "abstract_mapping.h"
#include "../ifcparse/file.h"
#include "../ifcgeom/mapping_plugin.h"
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/algorithm/string/case_conv.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)
});
std::call_once(once, load_mapping_plugins, std::ref(registry));
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;
entry.module_ = module.meta().id.empty() ? plugin::module(mapping_plugin_metadata(schema_name)) : module;
}
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::mapping_registry::construct(ifcopenshell::file* file, Settings& s) {
@@ -75,7 +47,7 @@ ifcopenshell::geometry::impl::MappingFactoryImplementation::MappingFactoryImplem
}
void ifcopenshell::geometry::impl::MappingFactoryImplementation::bind(const std::string& schema_name, ifcopenshell::geometry::impl::mapping_fn fn) {
mapping_registry_instance().bind(schema_name, fn, builtin_mapping_module(schema_name));
mapping_registry_instance().bind(schema_name, fn, plugin::module(mapping_plugin_metadata(schema_name)));
}
ifcopenshell::geometry::abstract_mapping* ifcopenshell::geometry::impl::MappingFactoryImplementation::construct(ifcopenshell::file* file, Settings& s) {
+2 -2
View File
@@ -82,13 +82,13 @@ namespace geometry {
class IFC_GEOM_API mapping_registry {
public:
void bind(const std::string& schema_name, mapping_fn fn, const plugin::module& module = plugin::module());
void bind(const std::string& schema_name, mapping_fn fn, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
abstract_mapping* construct(ifcopenshell::file* file, Settings& settings);
private:
struct entry {
mapping_fn fn_;
plugin::module module_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
+3 -1
View File
@@ -20,7 +20,9 @@
#ifndef IFC_GEOM_API_H
#define IFC_GEOM_API_H
#ifdef _WIN32
#ifdef SWIG
#define IFC_GEOM_API
#elif defined(_WIN32)
#ifdef IFC_GEOM_EXPORTS
#define IFC_GEOM_API __declspec(dllexport)
#else
+1 -30
View File
@@ -19,12 +19,6 @@
#include "kernel_plugin.h"
#ifndef _WIN32
#include <dlfcn.h>
#else
#include <windows.h>
#endif
#include <stdexcept>
namespace {
@@ -43,30 +37,7 @@ ifcopenshell::plugin::metadata ifcopenshell::geometry::kernels::kernel_plugin_me
}
std::filesystem::path ifcopenshell::geometry::kernels::kernel_plugin_directory() {
#ifdef _WIN32
HMODULE module_handle = nullptr;
if (!GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(&ifcopenshell::geometry::kernels::load_kernel_plugins),
&module_handle)) {
throw std::runtime_error("Unable to resolve IfcGeom module path");
}
wchar_t buffer[MAX_PATH];
const DWORD length = GetModuleFileNameW(module_handle, buffer, MAX_PATH);
if (length == 0) {
throw std::runtime_error("Unable to read IfcGeom module filename");
}
return std::filesystem::path(std::wstring(buffer, length)).parent_path();
#else
Dl_info info;
if (dladdr(reinterpret_cast<const void*>(&ifcopenshell::geometry::kernels::load_kernel_plugins), &info) == 0 || !info.dli_fname) {
throw std::runtime_error("Unable to resolve IfcGeom module path");
}
return std::filesystem::path(info.dli_fname).parent_path();
#endif
return plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::geometry::kernels::load_kernel_plugins));
}
void ifcopenshell::geometry::kernels::load_kernel_plugins(kernel_registry& registry) {
+2 -2
View File
@@ -28,10 +28,10 @@ namespace ifcopenshell {
namespace geometry {
namespace kernels {
typedef void register_kernel_plugin_fn(kernel_registry&, const plugin::module&);
typedef void register_kernel_plugin_fn(kernel_registry&, const ifcopenshell::plugin::module&);
IFC_GEOM_API const char* kernel_plugin_registration_symbol();
IFC_GEOM_API plugin::metadata kernel_plugin_metadata(const std::string& plugin_name);
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);
+2 -2
View File
@@ -45,7 +45,7 @@ namespace ifcopenshell {
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());
void bind(const kernel_info& info, create_fn create, const ifcopenshell::plugin::module& module = ifcopenshell::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;
@@ -54,7 +54,7 @@ namespace ifcopenshell {
struct entry {
kernel_info info_;
create_fn create_;
plugin::module module_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
+24
View File
@@ -6,6 +6,12 @@ foreach(kernel ${GEOMETRY_KERNELS})
string(TOUPPER ${kernel} KERNEL_UPPER)
file(GLOB IFCGEOM_H_FILES ${kernel}/*.h)
file(GLOB IFCGEOM_CPP_FILES ${kernel}/*.cpp)
if(${kernel} STREQUAL "opencascade")
list(REMOVE_ITEM IFCGEOM_CPP_FILES
${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/tree_brep_plugin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/${kernel}/tree_trianglebvh_plugin.cpp
)
endif()
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES})
set(KERNEL_TARGET "geometry_kernel_${kernel}")
@@ -37,6 +43,23 @@ foreach(kernel ${GEOMETRY_KERNELS})
install(TARGETS ${KERNEL_TARGET_SIMPLE})
elseif(${kernel} STREQUAL "opencascade")
target_link_libraries(${KERNEL_TARGET} PRIVATE ${OpenCASCADE_LIBRARIES})
foreach(tree_backend brep trianglebvh)
set(TREE_TARGET "geometry_tree_opencascade_${tree_backend}")
add_library(${TREE_TARGET} SHARED
${kernel}/tree_${tree_backend}_plugin.cpp
${kernel}/tree_backends.h
)
set_target_properties(${TREE_TARGET} PROPERTIES
COMPILE_FLAGS "-DIFC_GEOMLIBRARY_EXPORTS"
OUTPUT_NAME "geometry.tree.opencascade.${tree_backend}"
RUNTIME_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${kernel_plugin_runtime_dir}"
)
list(APPEND tree_libraries ${TREE_TARGET})
target_link_libraries(${TREE_TARGET} PRIVATE plugin IfcGeom geometry_kernel_opencascade ${OpenCASCADE_LIBRARIES} Eigen3::Eigen)
install(TARGETS ${TREE_TARGET})
endforeach()
endif()
install(FILES ${IFCGEOM_H_FILES}
@@ -45,3 +68,4 @@ foreach(kernel ${GEOMETRY_KERNELS})
endforeach()
set(kernel_libraries ${kernel_libraries} PARENT_SCOPE)
set(tree_libraries ${tree_libraries} PARENT_SCOPE)
+3 -1
View File
@@ -20,7 +20,9 @@
#ifndef IFC_GEOMLIBRARY_API_H
#define IFC_GEOMLIBRARY_API_H
#ifdef _WIN32
#ifdef SWIG
#define IFC_GEOMLIBRARY_API
#elif defined(_WIN32)
#ifdef IFC_GEOMLIBRARY_EXPORTS
#define IFC_GEOMLIBRARY_API __declspec(dllexport)
#else
+6 -25
View File
@@ -24,6 +24,7 @@
#include "../../../ifcgeom/IfcGeomElement.h"
#include "../../../ifcgeom/Iterator.h"
#include "../../../ifcgeom/tree.h"
#include "OpenCascadeConversionResult.h"
#include "OpenCascadeKernel.h"
#include "base_utils.h"
@@ -69,26 +70,6 @@
namespace IfcGeom {
struct ray_intersection_result {
double distance;
int style_index;
express::Entity instance;
std::array<double, 3> position;
std::array<double, 3> normal;
double ray_distance;
double dot_product;
};
struct clash {
int clash_type; // 0 = protrusion, 1 = pierce, 2 = collision, 3 = clearance
express::Base a;
express::Base b;
double distance;
std::array<double, 3> p1;
std::array<double, 3> p2;
};
namespace {
// Approximates the distance `other` protrudes into `volume` by finding the
@@ -1481,20 +1462,20 @@ namespace IfcGeom {
};
}
class tree : public impl::tree<express::Entity> {
class opencascade_tree : public impl::tree<express::Entity> {
public:
tree() {};
opencascade_tree() {};
tree(ifcopenshell::file& f) {
opencascade_tree(ifcopenshell::file& f) {
add_file(f, ifcopenshell::geometry::Settings{});
}
tree(ifcopenshell::file& f, ifcopenshell::geometry::Settings settings) {
opencascade_tree(ifcopenshell::file& f, ifcopenshell::geometry::Settings settings) {
add_file(f, settings);
}
tree(IfcGeom::Iterator& it) {
opencascade_tree(IfcGeom::Iterator& it) {
add_file(it);
}
@@ -0,0 +1,182 @@
/********************************************************************************
* *
* 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_OPENCASCADE_TREE_BACKENDS_H
#define IFCOPENSHELL_OPENCASCADE_TREE_BACKENDS_H
#include "../../kernel_registry.h"
#include "../../tree_registry.h"
#include "../../../ifcparse/exception.h"
#include "IfcGeomTree.h"
namespace ifcopenshell {
namespace geometry {
namespace trees {
namespace opencascade_tree_backends {
inline gp_Pnt make_point(const IfcGeom::tree_point& point) {
return gp_Pnt(point[0], point[1], point[2]);
}
inline Bnd_Box make_box(const IfcGeom::tree_box& bounds) {
Bnd_Box box;
box.Add(make_point(bounds[0]));
box.Add(make_point(bounds[1]));
return box;
}
class brep_tree : public abstract_tree {
public:
std::string_view backend_id() const override {
return "opencascade.brep";
}
void add_file(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings) override {
auto settings_ = settings;
settings_.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
settings_.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = true;
settings_.get<ifcopenshell::geometry::settings::ReorientShells>().value = true;
IfcGeom::Iterator iterator(ifcopenshell::geometry::kernels::construct(&file, "opencascade", settings_), settings_, &file, {}, 1);
if (iterator.initialize()) {
do {
add_element(iterator.get());
} while (iterator.next());
}
}
void add_element(IfcGeom::Element* element) override {
auto* brep = dynamic_cast<IfcGeom::BRepElement*>(element);
if (!brep) {
throw ifcopenshell::exception("Tree backend 'opencascade.brep' requires native BRep elements");
}
tree_.add_element(brep);
}
std::vector<express::Entity> select_box(const express::Entity& entity, bool completely_within, double extend) const override {
return tree_.select_box(entity, completely_within, extend);
}
std::vector<express::Entity> select_box(const IfcGeom::tree_point& point) const override {
return tree_.select_box(make_point(point));
}
std::vector<express::Entity> select_box(const IfcGeom::tree_box& bounds, bool completely_within) const override {
return tree_.select_box(make_box(bounds), completely_within);
}
std::vector<express::Entity> select(const express::Entity& entity, bool completely_within, double extend) const override {
return tree_.select(entity, completely_within, extend);
}
std::vector<express::Entity> select(const IfcGeom::Element* element, bool completely_within, double extend) const override {
auto* brep = dynamic_cast<const IfcGeom::BRepElement*>(element);
if (!brep) {
throw ifcopenshell::exception("Tree backend 'opencascade.brep' requires BRep elements for select()");
}
return tree_.select(brep, completely_within, extend);
}
std::vector<express::Entity> select(const IfcGeom::tree_point& point, double extend) const override {
return tree_.select(make_point(point), extend);
}
std::vector<IfcGeom::ray_intersection_result> select_ray(const IfcGeom::tree_point& origin, const IfcGeom::tree_point& direction, double length) const override {
return tree_.select_ray(make_point(origin), gp_Dir(direction[0], direction[1], direction[2]), length);
}
const std::vector<double>& distances() const override {
return tree_.distances();
}
const std::vector<double>& protrusion_distances() const override {
return tree_.protrusion_distances();
}
bool enable_face_styles() const override {
return tree_.enable_face_styles();
}
void enable_face_styles(bool enable) override {
tree_.enable_face_styles(enable);
}
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles() const override {
return tree_.styles();
}
private:
IfcGeom::opencascade_tree tree_;
};
class trianglebvh_tree : public abstract_tree {
public:
std::string_view backend_id() const override {
return "opencascade.trianglebvh";
}
void add_file(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings) override {
auto settings_ = settings;
settings_.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::TRIANGULATED;
settings_.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = true;
IfcGeom::Iterator iterator(ifcopenshell::geometry::kernels::construct(&file, "opencascade", settings_), settings_, &file, {}, 1);
if (iterator.initialize()) {
do {
add_element(iterator.get());
} while (iterator.next());
}
}
void add_element(IfcGeom::Element* element) override {
auto* triangulation = dynamic_cast<IfcGeom::TriangulationElement*>(element);
if (!triangulation) {
throw ifcopenshell::exception("Tree backend 'opencascade.trianglebvh' requires triangulation elements");
}
tree_.add_element(triangulation);
}
std::vector<IfcGeom::clash> clash_intersection_many(const std::vector<express::Entity>& set_a, const std::vector<express::Entity>& set_b, double tolerance, bool check_all) const override {
return tree_.clash_intersection_many(set_a, set_b, tolerance, check_all);
}
std::vector<IfcGeom::clash> clash_collision_many(const std::vector<express::Entity>& set_a, const std::vector<express::Entity>& set_b, bool allow_touching) const override {
return tree_.clash_collision_many(set_a, set_b, allow_touching);
}
std::vector<IfcGeom::clash> clash_clearance_many(const std::vector<express::Entity>& set_a, const std::vector<express::Entity>& set_b, double clearance, bool check_all) const override {
return tree_.clash_clearance_many(set_a, set_b, clearance, check_all);
}
#ifdef WITH_HDF5
void write_h5() override {
tree_.write_h5();
}
#endif
private:
IfcGeom::opencascade_tree tree_;
};
}
}
}
}
#endif
@@ -0,0 +1,55 @@
/********************************************************************************
* *
* 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 "../../tree_plugin.h"
#include "tree_backends.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace trees {
namespace opencascade_brep_tree_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return tree_plugin_metadata("opencascade.brep");
}
abstract_tree* create_tree() {
return new opencascade_tree_backends::brep_tree();
}
void register_plugin(tree_registry& registry, const plugin::module& module) {
tree_info info;
info.backend_id = "opencascade.brep";
registry.bind(info, create_tree, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::trees::opencascade_brep_tree_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::trees::opencascade_brep_tree_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::trees::opencascade_brep_tree_plugin::register_plugin, ifcopenshell_register_tree_plugin_v1)
@@ -0,0 +1,55 @@
/********************************************************************************
* *
* 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 "../../tree_plugin.h"
#include "tree_backends.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace trees {
namespace opencascade_trianglebvh_tree_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return tree_plugin_metadata("opencascade.trianglebvh");
}
abstract_tree* create_tree() {
return new opencascade_tree_backends::trianglebvh_tree();
}
void register_plugin(tree_registry& registry, const plugin::module& module) {
tree_info info;
info.backend_id = "opencascade.trianglebvh";
registry.bind(info, create_tree, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::trees::opencascade_trianglebvh_tree_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::trees::opencascade_trianglebvh_tree_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::trees::opencascade_trianglebvh_tree_plugin::register_plugin, ifcopenshell_register_tree_plugin_v1)
+10 -3
View File
@@ -1,14 +1,21 @@
find_package(Eigen3 REQUIRED)
set(mapping_plugin_runtime_dir "${CMAKE_BINARY_DIR}/ifcgeom/$<CONFIG>")
foreach(schema ${SCHEMA_VERSIONS})
file(GLOB IFCGEOM_I_FILES *.i)
file(GLOB IFCGEOM_H_FILES *.h)
file(GLOB IFCGEOM_CPP_FILES *.cpp)
set(IFCGEOM_FILES ${IFCGEOM_CPP_FILES} ${IFCGEOM_H_FILES} ${IFCGEOM_I_FILES})
add_library(geometry_mapping_ifc${schema} OBJECT ${IFCGEOM_FILES})
set_target_properties(geometry_mapping_ifc${schema} PROPERTIES COMPILE_FLAGS "-DIFC_GEOM_EXPORTS -DIfcSchema=Ifc${schema}")
target_link_libraries(geometry_mapping_ifc${schema} IfcParse Eigen3::Eigen)
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}"
RUNTIME_OUTPUT_DIRECTORY "${mapping_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${mapping_plugin_runtime_dir}"
)
target_link_libraries(geometry_mapping_ifc${schema} PRIVATE plugin IfcGeom IfcParse Eigen3::Eigen ${OpenCASCADE_LIBRARIES})
list(APPEND mapping_libraries geometry_mapping_ifc${schema})
+58
View File
@@ -0,0 +1,58 @@
/********************************************************************************
* *
* 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 "../mapping_plugin.h"
#include "mapping.h"
#include <boost/dll/alias.hpp>
namespace ifcopenshell {
namespace geometry {
namespace impl {
namespace mapping_plugin {
namespace {
struct POSTFIX_SCHEMA(factory_t) {
abstract_mapping* operator()(ifcopenshell::file* file, Settings& settings) const {
return new POSTFIX_SCHEMA(mapping)(file, settings);
}
};
}
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return mapping_plugin_metadata(STRINGIFY(IfcSchema));
}
void register_plugin(mapping_registry& registry, const plugin::module& module) {
POSTFIX_SCHEMA(factory_t) factory;
registry.bind(STRINGIFY(IfcSchema), factory, module);
}
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::geometry::impl::mapping_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::impl::mapping_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::geometry::impl::mapping_plugin::register_plugin, ifcopenshell_register_mapping_plugin_v1)
+57
View File
@@ -0,0 +1,57 @@
/********************************************************************************
* *
* 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 "mapping_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace {
constexpr const char* mapping_plugin_prefix = "geometry.mapping.";
}
const char* ifcopenshell::geometry::impl::mapping_plugin_registration_symbol() {
return "ifcopenshell_register_mapping_plugin_v1";
}
ifcopenshell::plugin::metadata ifcopenshell::geometry::impl::mapping_plugin_metadata(const std::string& schema_name) {
plugin::metadata metadata;
metadata.kind_ = plugin::kind::mapping;
metadata.id = mapping_plugin_prefix + boost::to_lower_copy(schema_name);
metadata.schema = boost::to_upper_copy(schema_name);
return metadata;
}
std::filesystem::path ifcopenshell::geometry::impl::mapping_plugin_directory() {
return plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::geometry::impl::load_mapping_plugins));
}
void ifcopenshell::geometry::impl::load_mapping_plugins(mapping_registry& registry) {
plugin::manager manager;
manager.add_search_path(mapping_plugin_directory());
for (const auto& path : manager.discover(mapping_plugin_prefix)) {
auto module = manager.load(path);
if (module.meta().kind_ != plugin::kind::mapping) {
continue;
}
auto register_plugin = module.get_alias<register_mapping_plugin_fn>(mapping_plugin_registration_symbol());
register_plugin(registry, module);
}
}
+42
View File
@@ -0,0 +1,42 @@
/********************************************************************************
* *
* 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_MAPPING_PLUGIN_H
#define IFCOPENSHELL_MAPPING_PLUGIN_H
#include "../ifcgeom/abstract_mapping.h"
#include <filesystem>
namespace ifcopenshell {
namespace geometry {
namespace impl {
typedef void register_mapping_plugin_fn(mapping_registry&, const ifcopenshell::plugin::module&);
IFC_GEOM_API const char* mapping_plugin_registration_symbol();
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);
}
}
}
#endif
+7 -6
View File
@@ -1,6 +1,7 @@
#ifndef PROFILE_HELPER_H
#define PROFILE_HELPER_H
#include "ifc_geom_api.h"
#include "taxonomy.h"
namespace ifcopenshell {
@@ -27,17 +28,17 @@ namespace ifcopenshell {
taxonomy::edge::ptr previous, next;
};
taxonomy::loop::ptr polygon_from_points(const std::vector<taxonomy::point3::ptr>& ps, bool external = true);
IFC_GEOM_API taxonomy::loop::ptr polygon_from_points(const std::vector<taxonomy::point3::ptr>& ps, bool external = true);
taxonomy::loop::ptr profile_helper(const taxonomy::matrix4::ptr& m4, const std::vector<profile_point>& points);
IFC_GEOM_API taxonomy::loop::ptr profile_helper(const taxonomy::matrix4::ptr& m4, const std::vector<profile_point>& points);
taxonomy::loop::ptr fillet_loop(taxonomy::loop::ptr lp, double radius);
IFC_GEOM_API taxonomy::loop::ptr fillet_loop(taxonomy::loop::ptr lp, double radius);
void remove_duplicate_points_from_loop(std::vector<taxonomy::point3::ptr>& polygon, bool closed, double tol);
IFC_GEOM_API void remove_duplicate_points_from_loop(std::vector<taxonomy::point3::ptr>& polygon, bool closed, double tol);
std::pair<std::vector<taxonomy::point3::ptr>, std::vector<std::set<std::string>>> remove_duplicate_points_from_loop(const std::vector<taxonomy::point3::ptr>& polygon, const std::vector<std::string>& tags);
IFC_GEOM_API std::pair<std::vector<taxonomy::point3::ptr>, std::vector<std::set<std::string>>> remove_duplicate_points_from_loop(const std::vector<taxonomy::point3::ptr>& polygon, const std::vector<std::string>& tags);
}
}
#endif
#endif
+266
View File
@@ -0,0 +1,266 @@
/********************************************************************************
* *
* 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 "tree.h"
#include "Iterator.h"
#include "tree_registry.h"
#include "../ifcparse/exception.h"
#include <boost/functional/hash.hpp>
#include <cstdio>
#include <limits>
#include <unordered_set>
namespace {
constexpr const char* default_selection_backend_id = "opencascade.brep";
constexpr const char* default_clash_backend_id = "opencascade.trianglebvh";
const std::vector<double>& empty_double_vector() {
static const std::vector<double> values;
return values;
}
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& empty_style_vector() {
static const std::vector<ifcopenshell::geometry::taxonomy::style::ptr> values;
return values;
}
std::vector<express::Entity> to_product_entities(const std::vector<express::Base>& instances) {
std::vector<express::Entity> entities;
entities.reserve(instances.size());
for (const auto& instance : instances) {
if (!instance) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
auto entity = instance.as<express::Entity>();
if (!entity || !instance.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
entities.push_back(entity);
}
return entities;
}
}
class IfcGeom::tree::impl {
public:
impl() = default;
explicit impl(const std::string& backend_id)
: backend_id_(backend_id)
{}
ifcopenshell::geometry::trees::abstract_tree& backend() const {
if (!backend_) {
if (backend_id_.empty()) {
throw ifcopenshell::exception("No geometry tree backend configured");
}
backend_ = ifcopenshell::geometry::trees::construct(backend_id_);
}
return *backend_;
}
ifcopenshell::geometry::trees::abstract_tree& backend(const std::string& default_backend_id) const {
if (backend_id_.empty()) {
backend_id_ = default_backend_id;
}
return backend();
}
ifcopenshell::geometry::trees::abstract_tree& backend_for_element(IfcGeom::Element* element) const {
if (dynamic_cast<IfcGeom::BRepElement*>(element)) {
return backend(default_selection_backend_id);
}
if (dynamic_cast<IfcGeom::TriangulationElement*>(element)) {
return backend(default_clash_backend_id);
}
throw ifcopenshell::exception("Unsupported tree element type");
}
const ifcopenshell::geometry::trees::abstract_tree* backend_or_null() const {
return backend_.get();
}
private:
mutable std::string backend_id_;
mutable std::unique_ptr<ifcopenshell::geometry::trees::abstract_tree> backend_;
};
IfcGeom::tree::tree()
: impl_(new impl())
{}
IfcGeom::tree::tree(const std::string& backend_id)
: impl_(new impl(backend_id))
{}
IfcGeom::tree::tree(ifcopenshell::file& file)
: tree()
{
add_file(file, ifcopenshell::geometry::Settings{});
}
IfcGeom::tree::tree(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings)
: tree()
{
add_file(file, settings);
}
IfcGeom::tree::tree(IfcGeom::Iterator& iterator)
: tree()
{
add_file(iterator);
}
IfcGeom::tree::~tree() = default;
IfcGeom::tree::tree(tree&& other) noexcept = default;
IfcGeom::tree& IfcGeom::tree::operator=(tree&& other) noexcept = default;
void IfcGeom::tree::add_file(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings) {
impl_->backend(default_selection_backend_id).add_file(file, settings);
}
void IfcGeom::tree::add_file(IfcGeom::Iterator& iterator) {
if (!iterator.initialize()) {
return;
}
do {
add_element(iterator.get());
} while (iterator.next());
}
void IfcGeom::tree::add_element(IfcGeom::Element* element) {
if (!element) {
return;
}
impl_->backend_for_element(element).add_element(element);
}
std::vector<express::Entity> IfcGeom::tree::select_box(const express::Entity& entity, bool completely_within, double extend) const {
return impl_->backend(default_selection_backend_id).select_box(entity, completely_within, extend);
}
std::vector<express::Entity> IfcGeom::tree::select_box(const tree_point& point) const {
return impl_->backend(default_selection_backend_id).select_box(point);
}
std::vector<express::Entity> IfcGeom::tree::select_box(const tree_box& bounds, bool completely_within) const {
return impl_->backend(default_selection_backend_id).select_box(bounds, completely_within);
}
std::vector<express::Entity> IfcGeom::tree::select(const express::Entity& entity, bool completely_within, double extend) const {
return impl_->backend(default_selection_backend_id).select(entity, completely_within, extend);
}
std::vector<express::Entity> IfcGeom::tree::select(const IfcGeom::Element* element, bool completely_within, double extend) const {
return impl_->backend(default_selection_backend_id).select(element, completely_within, extend);
}
std::vector<express::Entity> IfcGeom::tree::select(const tree_point& point, double extend) const {
return impl_->backend(default_selection_backend_id).select(point, extend);
}
std::vector<IfcGeom::ray_intersection_result> IfcGeom::tree::select_ray(const tree_point& origin, const tree_point& direction, double length) const {
return impl_->backend(default_selection_backend_id).select_ray(origin, direction, length);
}
std::vector<IfcGeom::clash> IfcGeom::tree::clash_intersection_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, double tolerance, bool check_all) const {
return impl_->backend(default_clash_backend_id).clash_intersection_many(to_product_entities(set_a), to_product_entities(set_b), tolerance, check_all);
}
std::vector<IfcGeom::clash> IfcGeom::tree::clash_collision_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, bool allow_touching) const {
return impl_->backend(default_clash_backend_id).clash_collision_many(to_product_entities(set_a), to_product_entities(set_b), allow_touching);
}
std::vector<IfcGeom::clash> IfcGeom::tree::clash_clearance_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, double clearance, bool check_all) const {
return impl_->backend(default_clash_backend_id).clash_clearance_many(to_product_entities(set_a), to_product_entities(set_b), clearance, check_all);
}
const std::vector<double>& IfcGeom::tree::distances() const {
const auto* backend = impl_->backend_or_null();
return backend ? backend->distances() : empty_double_vector();
}
const std::vector<double>& IfcGeom::tree::protrusion_distances() const {
const auto* backend = impl_->backend_or_null();
return backend ? backend->protrusion_distances() : empty_double_vector();
}
bool IfcGeom::tree::enable_face_styles() const {
const auto* backend = impl_->backend_or_null();
return backend ? backend->enable_face_styles() : false;
}
void IfcGeom::tree::enable_face_styles(bool enable) {
impl_->backend(default_selection_backend_id).enable_face_styles(enable);
}
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& IfcGeom::tree::styles() const {
const auto* backend = impl_->backend_or_null();
return backend ? backend->styles() : empty_style_vector();
}
#ifdef WITH_HDF5
void IfcGeom::tree::write_h5() {
impl_->backend(default_clash_backend_id).write_h5();
}
#endif
std::string IfcGeom::tree::uint8_to_b64(const std::vector<uint8_t>& uuids_array) const {
std::string hex_str;
hex_str.reserve(uuids_array.size() * 2);
for (auto byte : uuids_array) {
char hex[3];
std::snprintf(hex, sizeof(hex), "%02x", byte);
hex_str.append(hex);
}
return hex_str;
}
bool IfcGeom::tree::is_manifold(const std::vector<int>& faces) {
std::unordered_set<std::pair<size_t, size_t>, boost::hash<std::pair<size_t, size_t>>> directed_edges;
for (size_t i = 0; i < faces.size(); i += 3) {
for (size_t j = 0; j < 3; ++j) {
const auto k = (j + 1) % 3;
const std::pair<size_t, size_t> edge(faces[i + j], faces[i + k]);
const auto it = directed_edges.find(edge);
if (it != directed_edges.end()) {
directed_edges.erase(it);
} else {
directed_edges.insert({ faces[i + k], faces[i + j] });
}
}
}
return directed_edges.empty();
}
+116
View File
@@ -0,0 +1,116 @@
/********************************************************************************
* *
* 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_TREE_H
#define IFCOPENSHELL_TREE_H
#include "IfcGeomElement.h"
#include <array>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
namespace ifcopenshell {
class file;
namespace geometry {
class Settings;
}
}
namespace IfcGeom {
class Iterator;
using tree_point = std::array<double, 3>;
using tree_box = std::array<tree_point, 2>;
struct IFC_GEOM_API ray_intersection_result {
double distance;
int style_index;
express::Entity instance;
tree_point position;
tree_point normal;
double ray_distance;
double dot_product;
};
struct IFC_GEOM_API clash {
int clash_type;
express::Base a;
express::Base b;
double distance;
tree_point p1;
tree_point p2;
};
class IFC_GEOM_API tree {
public:
tree();
explicit tree(const std::string& backend_id);
explicit tree(ifcopenshell::file& file);
tree(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings);
explicit tree(IfcGeom::Iterator& iterator);
~tree();
tree(tree&& other) noexcept;
tree& operator=(tree&& other) noexcept;
tree(const tree& other) = delete;
tree& operator=(const tree& other) = delete;
void add_file(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings);
void add_file(IfcGeom::Iterator& iterator);
void add_element(IfcGeom::Element* element);
std::vector<express::Entity> select_box(const express::Entity& entity, bool completely_within = false, double extend = -1.e-5) const;
std::vector<express::Entity> select_box(const tree_point& point) const;
std::vector<express::Entity> select_box(const tree_box& bounds, bool completely_within = false) const;
std::vector<express::Entity> select(const express::Entity& entity, bool completely_within = false, double extend = 0.0) const;
std::vector<express::Entity> select(const IfcGeom::Element* element, bool completely_within = false, double extend = -1.e-5) const;
std::vector<express::Entity> select(const tree_point& point, double extend = 0.0) const;
std::vector<ray_intersection_result> select_ray(const tree_point& origin, const tree_point& direction, double length = 1000.) const;
std::vector<clash> clash_intersection_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, double tolerance = 0.002, bool check_all = true) const;
std::vector<clash> clash_collision_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, bool allow_touching = false) const;
std::vector<clash> clash_clearance_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, double clearance = 0.05, bool check_all = false) const;
const std::vector<double>& distances() const;
const std::vector<double>& protrusion_distances() const;
bool enable_face_styles() const;
void enable_face_styles(bool enable);
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles() const;
#ifdef WITH_HDF5
void write_h5();
#endif
std::string uint8_to_b64(const std::vector<uint8_t>& uuids_array) const;
static bool is_manifold(const std::vector<int>& faces);
private:
class impl;
std::unique_ptr<impl> impl_;
};
}
#endif
+54
View File
@@ -0,0 +1,54 @@
/********************************************************************************
* *
* 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 "tree_plugin.h"
namespace {
constexpr const char* tree_plugin_prefix = "geometry.tree.";
}
const char* ifcopenshell::geometry::trees::tree_plugin_registration_symbol() {
return "ifcopenshell_register_tree_plugin_v1";
}
ifcopenshell::plugin::metadata ifcopenshell::geometry::trees::tree_plugin_metadata(const std::string& plugin_name) {
plugin::metadata metadata;
metadata.kind_ = plugin::kind::tree;
metadata.id = std::string(tree_plugin_prefix) + plugin_name;
return metadata;
}
std::filesystem::path ifcopenshell::geometry::trees::tree_plugin_directory() {
return plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::geometry::trees::load_tree_plugins));
}
void ifcopenshell::geometry::trees::load_tree_plugins(tree_registry& registry) {
plugin::manager manager;
manager.add_search_path(tree_plugin_directory());
for (const auto& path : manager.discover(tree_plugin_prefix)) {
auto module = manager.load(path);
if (module.meta().kind_ != plugin::kind::tree) {
continue;
}
auto register_plugin = module.get_alias<register_tree_plugin_fn>(tree_plugin_registration_symbol());
register_plugin(registry, module);
}
}
+42
View File
@@ -0,0 +1,42 @@
/********************************************************************************
* *
* 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_TREE_PLUGIN_H
#define IFCOPENSHELL_TREE_PLUGIN_H
#include "tree_registry.h"
#include <filesystem>
namespace ifcopenshell {
namespace geometry {
namespace trees {
typedef void register_tree_plugin_fn(tree_registry&, const ifcopenshell::plugin::module&);
IFC_GEOM_API const char* tree_plugin_registration_symbol();
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);
}
}
}
#endif
+144
View File
@@ -0,0 +1,144 @@
/********************************************************************************
* *
* 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 "tree_registry.h"
#include "tree_plugin.h"
#include "../ifcparse/exception.h"
#include <boost/algorithm/string.hpp>
#include <mutex>
namespace {
std::string tree_key(const std::string& backend_id) {
return boost::to_lower_copy(backend_id);
}
[[noreturn]] void unsupported_tree_operation(const std::string& backend_id, const std::string& operation) {
throw ifcopenshell::exception("Tree backend '" + backend_id + "' does not support " + operation);
}
}
ifcopenshell::geometry::trees::abstract_tree::~abstract_tree() = default;
void ifcopenshell::geometry::trees::abstract_tree::add_file(ifcopenshell::file&, const ifcopenshell::geometry::Settings&) {
unsupported_tree_operation(std::string(backend_id()), "add_file()");
}
void ifcopenshell::geometry::trees::abstract_tree::add_element(IfcGeom::Element*) {
unsupported_tree_operation(std::string(backend_id()), "add_element()");
}
std::vector<express::Entity> ifcopenshell::geometry::trees::abstract_tree::select_box(const express::Entity&, bool, double) const {
unsupported_tree_operation(std::string(backend_id()), "select_box(entity)");
}
std::vector<express::Entity> ifcopenshell::geometry::trees::abstract_tree::select_box(const IfcGeom::tree_point&) const {
unsupported_tree_operation(std::string(backend_id()), "select_box(point)");
}
std::vector<express::Entity> ifcopenshell::geometry::trees::abstract_tree::select_box(const IfcGeom::tree_box&, bool) const {
unsupported_tree_operation(std::string(backend_id()), "select_box(bounds)");
}
std::vector<express::Entity> ifcopenshell::geometry::trees::abstract_tree::select(const express::Entity&, bool, double) const {
unsupported_tree_operation(std::string(backend_id()), "select(entity)");
}
std::vector<express::Entity> ifcopenshell::geometry::trees::abstract_tree::select(const IfcGeom::Element*, bool, double) const {
unsupported_tree_operation(std::string(backend_id()), "select(element)");
}
std::vector<express::Entity> ifcopenshell::geometry::trees::abstract_tree::select(const IfcGeom::tree_point&, double) const {
unsupported_tree_operation(std::string(backend_id()), "select(point)");
}
std::vector<IfcGeom::ray_intersection_result> ifcopenshell::geometry::trees::abstract_tree::select_ray(const IfcGeom::tree_point&, const IfcGeom::tree_point&, double) const {
unsupported_tree_operation(std::string(backend_id()), "select_ray()");
}
std::vector<IfcGeom::clash> ifcopenshell::geometry::trees::abstract_tree::clash_intersection_many(const std::vector<express::Entity>&, const std::vector<express::Entity>&, double, bool) const {
unsupported_tree_operation(std::string(backend_id()), "clash_intersection_many()");
}
std::vector<IfcGeom::clash> ifcopenshell::geometry::trees::abstract_tree::clash_collision_many(const std::vector<express::Entity>&, const std::vector<express::Entity>&, bool) const {
unsupported_tree_operation(std::string(backend_id()), "clash_collision_many()");
}
std::vector<IfcGeom::clash> ifcopenshell::geometry::trees::abstract_tree::clash_clearance_many(const std::vector<express::Entity>&, const std::vector<express::Entity>&, double, bool) const {
unsupported_tree_operation(std::string(backend_id()), "clash_clearance_many()");
}
const std::vector<double>& ifcopenshell::geometry::trees::abstract_tree::distances() const {
unsupported_tree_operation(std::string(backend_id()), "distances()");
}
const std::vector<double>& ifcopenshell::geometry::trees::abstract_tree::protrusion_distances() const {
unsupported_tree_operation(std::string(backend_id()), "protrusion_distances()");
}
bool ifcopenshell::geometry::trees::abstract_tree::enable_face_styles() const {
unsupported_tree_operation(std::string(backend_id()), "enable_face_styles()");
}
void ifcopenshell::geometry::trees::abstract_tree::enable_face_styles(bool) {
unsupported_tree_operation(std::string(backend_id()), "enable_face_styles(bool)");
}
const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& ifcopenshell::geometry::trees::abstract_tree::styles() const {
unsupported_tree_operation(std::string(backend_id()), "styles()");
}
#ifdef WITH_HDF5
void ifcopenshell::geometry::trees::abstract_tree::write_h5() {
unsupported_tree_operation(std::string(backend_id()), "write_h5()");
}
#endif
void ifcopenshell::geometry::trees::tree_registry::bind(const tree_info& info, create_fn create, const plugin::module& module) {
entry entry;
entry.info_ = info;
entry.create_ = create;
entry.module_ = module;
entries_[tree_key(info.backend_id)] = entry;
}
bool ifcopenshell::geometry::trees::tree_registry::has(const std::string& backend_id) const {
return entries_.find(tree_key(backend_id)) != entries_.end();
}
std::unique_ptr<ifcopenshell::geometry::trees::abstract_tree> ifcopenshell::geometry::trees::tree_registry::create(const std::string& backend_id) const {
const auto iter = entries_.find(tree_key(backend_id));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry tree registered for " + backend_id);
}
return std::unique_ptr<abstract_tree>(iter->second.create_());
}
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);
}
+103
View File
@@ -0,0 +1,103 @@
/********************************************************************************
* *
* 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_TREE_REGISTRY_H
#define IFCOPENSHELL_TREE_REGISTRY_H
#include "tree.h"
#include "../plugin/plugin.h"
#include <boost/function.hpp>
#include <map>
#include <memory>
#include <string>
#include <string_view>
namespace ifcopenshell {
class file;
namespace geometry {
class Settings;
namespace trees {
struct IFC_GEOM_API tree_info {
std::string backend_id;
};
class IFC_GEOM_API abstract_tree {
public:
virtual ~abstract_tree();
virtual std::string_view backend_id() const = 0;
virtual void add_file(ifcopenshell::file& file, const ifcopenshell::geometry::Settings& settings);
virtual void add_element(IfcGeom::Element* element);
virtual std::vector<express::Entity> select_box(const express::Entity& entity, bool completely_within, double extend) const;
virtual std::vector<express::Entity> select_box(const IfcGeom::tree_point& point) const;
virtual std::vector<express::Entity> select_box(const IfcGeom::tree_box& bounds, bool completely_within) const;
virtual std::vector<express::Entity> select(const express::Entity& entity, bool completely_within, double extend) const;
virtual std::vector<express::Entity> select(const IfcGeom::Element* element, bool completely_within, double extend) const;
virtual std::vector<express::Entity> select(const IfcGeom::tree_point& point, double extend) const;
virtual std::vector<IfcGeom::ray_intersection_result> select_ray(const IfcGeom::tree_point& origin, const IfcGeom::tree_point& direction, double length) const;
virtual std::vector<IfcGeom::clash> clash_intersection_many(const std::vector<express::Entity>& set_a, const std::vector<express::Entity>& set_b, double tolerance, bool check_all) const;
virtual std::vector<IfcGeom::clash> clash_collision_many(const std::vector<express::Entity>& set_a, const std::vector<express::Entity>& set_b, bool allow_touching) const;
virtual std::vector<IfcGeom::clash> clash_clearance_many(const std::vector<express::Entity>& set_a, const std::vector<express::Entity>& set_b, double clearance, bool check_all) const;
virtual const std::vector<double>& distances() const;
virtual const std::vector<double>& protrusion_distances() const;
virtual bool enable_face_styles() const;
virtual void enable_face_styles(bool enable);
virtual const std::vector<ifcopenshell::geometry::taxonomy::style::ptr>& styles() const;
#ifdef WITH_HDF5
virtual void write_h5();
#endif
};
class IFC_GEOM_API tree_registry {
public:
typedef boost::function0<abstract_tree*> create_fn;
void bind(const tree_info& info, create_fn create, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
bool has(const std::string& backend_id) const;
std::unique_ptr<abstract_tree> create(const std::string& backend_id) const;
private:
struct entry {
tree_info info_;
create_fn create_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
};
IFC_GEOM_API tree_registry& tree_registry_instance();
IFC_GEOM_API std::unique_ptr<abstract_tree> construct(const std::string& backend_id);
}
}
}
#endif
+3
View File
@@ -7,5 +7,8 @@ target_link_libraries(IfcGeomServer IfcGeom ${OpenCASCADE_LIBRARIES})
if(WITH_OPENCASCADE)
target_link_libraries(IfcGeomServer geometry_kernel_opencascade)
endif()
if(kernel_libraries OR mapping_libraries)
add_dependencies(IfcGeomServer ${kernel_libraries} ${mapping_libraries})
endif()
install(TARGETS IfcGeomServer)
@@ -379,9 +379,7 @@ class tree(ifcopenshell_wrapper.tree):
def select(
self,
value: Union[
entity_instance, ifcopenshell_wrapper.BRepElement, tuple[float, float, float], TopoDS.TopoDS_Shape
],
value: Union[entity_instance, ifcopenshell_wrapper.BRepElement, tuple[float, float, float]],
**kwargs,
) -> list[entity_instance]:
def unwrap(value):
@@ -399,12 +397,6 @@ class tree(ifcopenshell_wrapper.tree):
elif isinstance(value, (list, tuple)) and len(value) == 3 and set(map(type, value)) == {float}:
if "extend" in kwargs:
args.append(kwargs["extend"])
elif has_occ:
if isinstance(value, TopoDS.TopoDS_Shape):
args[1] = utils.serialize_shape(value)
args.append(kwargs.get("completely_within", False))
if "extend" in kwargs:
args.append(kwargs["extend"])
return ifcopenshell_wrapper.tree.select(*args)
def select_box(self, value, **kwargs) -> list[entity_instance]:
+3 -1
View File
@@ -20,7 +20,9 @@
#ifndef IFC_PARSE_API_H
#define IFC_PARSE_API_H
#ifdef _WIN32
#ifdef SWIG
#define IFC_PARSE_API
#elif defined(_WIN32)
#ifdef IFC_PARSE_EXPORTS
#define IFC_PARSE_API __declspec(dllexport)
#else
+2 -2
View File
@@ -504,7 +504,7 @@ class IFC_PARSE_API schema_registry {
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(const std::string& schema_name, get_schema_fn get, clear_schema_fn clear, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
void bind(schema_definition* schema);
const schema_definition* get(const std::string& schema_name);
std::vector<std::string> names() const;
@@ -515,7 +515,7 @@ class IFC_PARSE_API schema_registry {
const schema_definition* schema_ = nullptr;
get_schema_fn get_ = nullptr;
clear_schema_fn clear_ = nullptr;
plugin::module module_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
+3
View File
@@ -147,6 +147,9 @@ target_link_libraries(ifcopenshell_wrapper PRIVATE ${IFCOPENSHELL_LIBRARIES} ${O
else()
target_link_libraries(ifcopenshell_wrapper PRIVATE ${IFCOPENSHELL_LIBRARIES} ${LIBSVGFILL})
endif()
if(kernel_libraries OR tree_libraries OR mapping_libraries OR geometry_serializer_libraries OR document_serializer_libraries)
add_dependencies(ifcopenshell_wrapper ${kernel_libraries} ${tree_libraries} ${mapping_libraries} ${geometry_serializer_libraries} ${document_serializer_libraries})
endif()
if(NOT WIN32)
SET_INSTALL_RPATHS(ifcopenshell_wrapper "${IFCDIRS};${OCC_LIBRARY_DIR}")
endif()
+251 -417
View File
@@ -50,9 +50,7 @@
$result = PyBool_FromLong(static_cast<long>(*$1));
}
%ignore IfcGeom::impl::tree::selector;
// Using RTTI return a more specialized type of Element
// Using RTTI return a more specialized type of Element
// Note that these elements are not to be owned by SWIG/Python as they will be freed automatically upon the next iteration
// except for the IfcGeom::Element instances which are returned by Iterator::getObject() calls
%typemap(out) IfcGeom::Element* {
@@ -255,12 +253,11 @@ namespace {
%shared_ptr(ifcopenshell::geometry::taxonomy::extrusion);
%shared_ptr(ifcopenshell::geometry::taxonomy::revolve);
%shared_ptr(ifcopenshell::geometry::taxonomy::sweep_along_curve);
%shared_ptr(ifcopenshell::geometry::taxonomy::node);
%include "../ifcgeom/ifc_geom_api.h"
%include "../ifcgeom/Converter.h"
%include "../ifcgeom/ConversionResult.h"
%include "../ifcgeom/ConversionSettings.h"
%shared_ptr(ifcopenshell::geometry::taxonomy::node);
%include "../ifcgeom/ifc_geom_api.h"
%include "../ifcgeom/ConversionResult.h"
%include "../ifcgeom/ConversionSettings.h"
%include "../ifcgeom/IfcGeomElement.h"
%include "../ifcgeom/IfcGeomRepresentation.h"
%include "../ifcgeom/Iterator.h"
@@ -435,139 +432,72 @@ assign_matrix_access(revolve);
}
}
#ifdef IFOPSH_WITH_OPENCASCADE
%template(ray_intersection_results) std::vector<IfcGeom::ray_intersection_result>;
%template(clashes) std::vector<IfcGeom::clash>;
// A Template instantantation should be defined before it is used as a base class.
// But frankly I don't care as most methods are subtlely different anyway.
%include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
%extend IfcGeom::tree {
std::vector<express::Base> select_box(const express::Base& e, bool completely_within = false, double extend=-1.e-5) const {
%template(ray_intersection_results) std::vector<IfcGeom::ray_intersection_result>;
%template(clashes) std::vector<IfcGeom::clash>;
%include "../ifcgeom/tree.h"
%extend IfcGeom::tree {
std::vector<express::Base> select_box(const express::Base& e, bool completely_within = false, double extend=-1.e-5) const {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("Instance should be an IfcProduct");
}
return cast_vector<express::Base>($self->select_box(e.as<express::Entity>(), completely_within, extend));
}
std::vector<express::Base> select_box(const gp_Pnt& p) const {
return cast_vector<express::Base>($self->select_box(p));
}
std::vector<express::Base> select_box(const Bnd_Box& b, bool completely_within = false) const {
return cast_vector<express::Base>($self->select_box(b, completely_within));
}
std::vector<express::Base> select(const express::Base& e, bool completely_within = false, double extend = 0.0) const {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("Instance should be an IfcProduct");
}
return cast_vector<express::Base>($self->select(e.as<express::Entity>(), completely_within, extend));
}
std::vector<express::Base> select(const gp_Pnt& p, double extend=0.0) const {
return cast_vector<express::Base>($self->select(p, extend));
}
std::vector<express::Base> select(const std::string& shape_serialization, bool completely_within = false, double extend = -1.e-5) const {
std::stringstream stream(shape_serialization);
BRepTools_ShapeSet shapes;
shapes.Read(stream);
const TopoDS_Shape& shp = shapes.Shape(shapes.NbShapes());
return cast_vector<express::Base>($self->select(shp, completely_within, extend));
}
std::vector<express::Base> select(const IfcGeom::BRepElement* elem, bool completely_within = false, double extend = -1.e-5) const {
return cast_vector<express::Base>($self->select(elem, completely_within, extend));
}
/*
%typemap(in) const std::vector<express::Base>& (std::vector<express::Base> temp) {
if (!PyList_Check($input)) {
PyErr_SetString(PyExc_TypeError, "Expected a list.");
return NULL;
}
$1 = &temp; // Set $1 to the address of temp, which SWIG will use as the argument in the wrapped function
temp.reserve(PyList_Size($input)); // Pre-allocate memory for efficiency
for (Py_ssize_t i = 0; i < PyList_Size($input); ++i) {
PyObject* pyObj = PyList_GetItem($input, i);
void* ptr = 0;
int res = SWIG_ConvertPtr(pyObj, &ptr, SWIGTYPE_p_express__Base, 0);
if (!SWIG_IsOK(res)) {
PyErr_SetString(PyExc_TypeError, "List item is not of type IfcBaseClass.");
return NULL;
}
temp.push_back(reinterpret_cast<express::Base>(ptr));
}
}
*/
std::vector<clash> clash_intersection_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, double tolerance, bool check_all) const {
std::vector<express::Entity> set_a_entities;
std::vector<express::Entity> set_b_entities;
for (auto& e : set_a) {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
set_a_entities.push_back(e.as<express::Entity>());
}
for (auto& e : set_b) {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
set_b_entities.push_back(e.as<express::Entity>());
}
return $self->clash_intersection_many(set_a_entities, set_b_entities, tolerance, check_all);
}
std::vector<clash> clash_collision_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, bool allow_touching) const {
std::vector<express::Entity> set_a_entities;
std::vector<express::Entity> set_b_entities;
for (auto& e : set_a) {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
set_a_entities.push_back(e.as<express::Entity>());
}
for (auto& e : set_b) {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
set_b_entities.push_back(e.as<express::Entity>());
}
return $self->clash_collision_many(set_a_entities, set_b_entities, allow_touching);
}
std::vector<clash> clash_clearance_many(const std::vector<express::Base>& set_a, const std::vector<express::Base>& set_b, double clearance, bool check_all) const {
std::vector<express::Entity> set_a_entities;
std::vector<express::Entity> set_b_entities;
for (auto& e : set_a) {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
set_a_entities.push_back(e.as<express::Entity>());
}
for (auto& e : set_b) {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("All instances should be of type IfcProduct");
}
set_b_entities.push_back(e.as<express::Entity>());
}
return $self->clash_clearance_many(set_a_entities, set_b_entities, clearance, check_all);
}
}
#endif
// A visitor
%{
}
return cast_vector<express::Base>($self->select_box(e.as<express::Entity>(), completely_within, extend));
}
std::vector<express::Base> select_box(const std::vector<double>& p) const {
if (p.size() != 3) {
throw ifcopenshell::exception("Point should be a sequence of 3 floats");
}
IfcGeom::tree_point point = {{ p[0], p[1], p[2] }};
return cast_vector<express::Base>($self->select_box(point));
}
std::vector<express::Base> select_box(const std::vector<std::vector<double>>& b, bool completely_within = false) const {
if (b.size() != 2 || b[0].size() != 3 || b[1].size() != 3) {
throw ifcopenshell::exception("Bounding box should be a sequence of 2 x 3 floats");
}
IfcGeom::tree_box box = {{
{ b[0][0], b[0][1], b[0][2] },
{ b[1][0], b[1][1], b[1][2] }
}};
return cast_vector<express::Base>($self->select_box(box, completely_within));
}
std::vector<express::Base> select(const express::Base& e, bool completely_within = false, double extend = 0.0) const {
if (!e.declaration().is("IfcProduct")) {
throw ifcopenshell::exception("Instance should be an IfcProduct");
}
return cast_vector<express::Base>($self->select(e.as<express::Entity>(), completely_within, extend));
}
std::vector<express::Base> select(const std::vector<double>& p, double extend=0.0) const {
if (p.size() != 3) {
throw ifcopenshell::exception("Point should be a sequence of 3 floats");
}
IfcGeom::tree_point point = {{ p[0], p[1], p[2] }};
return cast_vector<express::Base>($self->select(point, extend));
}
std::vector<express::Base> select(const IfcGeom::Element* elem, bool completely_within = false, double extend = -1.e-5) const {
return cast_vector<express::Base>($self->select(elem, completely_within, extend));
}
std::vector<IfcGeom::ray_intersection_result> select_ray(const std::vector<double>& p0, const std::vector<double>& d, double length = 1000.) const {
if (p0.size() != 3 || d.size() != 3) {
throw ifcopenshell::exception("Origin and direction should be sequences of 3 floats");
}
IfcGeom::tree_point origin = {{ p0[0], p0[1], p0[2] }};
IfcGeom::tree_point direction = {{ d[0], d[1], d[2] }};
return $self->select_ray(origin, direction, length);
}
}
// A visitor
%{
struct ShapeRTTI : public boost::static_visitor<PyObject*>
{
PyObject* operator()(IfcGeom::Element* elem) const {
@@ -853,134 +783,70 @@ struct ShapeRTTI : public boost::static_visitor<PyObject*>
%}
};
%{
template <typename T>
std::string to_locale_invariant_string(const T& t) {
std::ostringstream oss;
oss.imbue(std::locale::classic());
oss << t;
return oss.str();
}
template <typename Schema>
static std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*> helper_fn_create_shape(const std::string& geometry_library, ifcopenshell::geometry::Settings& st, const express::Base& instance, const express::Base& representation = express::Base()) {
ifcopenshell::file* file = instance.file();
ifcopenshell::geometry::Converter kernel(ifcopenshell::geometry::kernels::construct(file, geometry_library, st), file, st);
if (auto product = instance.as<typename Schema::IfcProduct>()) {
if (representation) {
if (!representation.declaration().is(Schema::IfcRepresentation::Class())) {
throw ifcopenshell::exception("Supplied representation not of type IfcRepresentation");
}
}
if (!representation && !product.Representation()) {
throw ifcopenshell::exception("Representation is NULL");
}
auto prodrep = product.Representation();
auto reps = prodrep.Representations();
auto ifc_representation = representation ? representation.as<typename Schema::IfcRepresentation>() : typename Schema::IfcRepresentation();
if (!ifc_representation) {
// First, try to find a representation based on the settings
for (auto& rep : reps) {
if (!rep.RepresentationIdentifier()) {
continue;
}
if (st.get<ifcopenshell::geometry::settings::OutputDimensionality>().get() != ifcopenshell::geometry::settings::CURVES) {
if (*rep.RepresentationIdentifier() == "Body" || *rep.RepresentationIdentifier() == "Facetation") {
ifc_representation = rep;
break;
}
} else {
if (*rep.RepresentationIdentifier() == "Plan" || *rep.RepresentationIdentifier() == "Axis") {
ifc_representation = rep;
break;
}
}
}
}
// Otherwise, find a representation within the 'Model' or 'Plan' context
if (!ifc_representation) {
for (auto& rep : reps) {
auto context = rep.ContextOfItems();
// TODO: Remove redundancy with IfcGeomIterator.h
if (context.ContextType()) {
std::set<std::string> context_types;
if (st.get<ifcopenshell::geometry::settings::OutputDimensionality>().get() != ifcopenshell::geometry::settings::CURVES) {
context_types.insert("model");
context_types.insert("design");
context_types.insert("model view");
context_types.insert("detail view");
} else {
context_types.insert("plan");
}
std::string context_type_lc = *context.ContextType();
for (std::string::iterator c = context_type_lc.begin(); c != context_type_lc.end(); ++c) {
*c = tolower(*c);
}
if (context_types.find(context_type_lc) != context_types.end()) {
ifc_representation = rep;
}
}
}
}
if (!ifc_representation) {
if (reps.size()) {
// Return a random representation
ifc_representation = reps.front();
} else {
throw ifcopenshell::exception("No suitable IfcRepresentation found");
}
}
IfcGeom::BRepElement* brep = kernel.create_brep_for_representation_and_product(ifc_representation, product);
if (!brep) {
std::ostringstream oss_repr, oss_product;
ifc_representation.to_string(oss_repr);
product.to_string(oss_product);
throw ifcopenshell::exception("Failed to process shape. Product: " + oss_product.str() + ", representation: " + oss_repr.str());
}
if (st.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::SERIALIZED) {
IfcGeom::SerializedElement* serialization = new IfcGeom::SerializedElement(*brep);
delete brep;
%{
template <typename T>
std::string to_locale_invariant_string(const T& t) {
std::ostringstream oss;
oss.imbue(std::locale::classic());
oss << t;
return oss.str();
}
static std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*> helper_fn_create_shape(const std::string& geometry_library, ifcopenshell::geometry::Settings& st, const express::Base& instance, const express::Base& representation = express::Base()) {
ifcopenshell::file* file = instance.file();
ifcopenshell::geometry::Converter kernel(ifcopenshell::geometry::kernels::construct(file, geometry_library, st), file, st);
if (instance.declaration().is("IfcProduct")) {
if (representation && !representation.declaration().is("IfcRepresentation")) {
throw ifcopenshell::exception("Supplied representation not of type IfcRepresentation");
}
auto selected_representation = representation ? representation : kernel.mapping()->representation_of(instance);
if (!selected_representation) {
throw ifcopenshell::exception("No suitable IfcRepresentation found");
}
IfcGeom::BRepElement* brep = kernel.create_brep_for_representation_and_product(selected_representation, instance);
if (!brep) {
std::ostringstream oss_repr, oss_product;
selected_representation.to_string(oss_repr);
instance.to_string(oss_product);
throw ifcopenshell::exception("Failed to process shape. Product: " + oss_product.str() + ", representation: " + oss_repr.str());
}
if (st.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::SERIALIZED) {
IfcGeom::SerializedElement* serialization = new IfcGeom::SerializedElement(*brep);
delete brep;
return serialization;
} else if (st.get<ifcopenshell::geometry::settings::IteratorOutput>().get() == ifcopenshell::geometry::settings::TRIANGULATED) {
IfcGeom::TriangulationElement* triangulation = new IfcGeom::TriangulationElement(*brep);
delete brep;
return triangulation;
} else {
return brep;
}
} else if (instance.as<typename Schema::IfcPlacement>() || instance.as<typename Schema::IfcObjectPlacement>()) {
auto item = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::matrix4>(kernel.mapping()->map(instance));
if (item == nullptr) {
throw ifcopenshell::exception("Failed to convert placement");
}
if (st.get<ifcopenshell::geometry::settings::ConvertBackUnits>().get()) {
} else {
return brep;
}
} else if (instance.declaration().is("IfcPlacement") || instance.declaration().is("IfcObjectPlacement")) {
auto item = ifcopenshell::geometry::taxonomy::cast<ifcopenshell::geometry::taxonomy::matrix4>(kernel.mapping()->map(instance));
if (item == nullptr) {
throw ifcopenshell::exception("Failed to convert placement");
}
if (st.get<ifcopenshell::geometry::settings::ConvertBackUnits>().get()) {
// we pass the settings to the Transformation object, but access the data just offloads to the
// generic cartesian_base<Matrix4> so there's no time to apply the settings to the translation part.
item = ifcopenshell::geometry::taxonomy::matrix4::ptr(item->clone_());
item->components().col(3).head<3>() /= kernel.settings().get<ifcopenshell::geometry::settings::LengthUnit>().get();
}
return new IfcGeom::Transformation(kernel.settings(), item);
} else {
if (!representation) {
if (instance.declaration().is(Schema::IfcRepresentationItem::Class()) ||
instance.declaration().is(Schema::IfcRepresentation::Class()) ||
// https://github.com/IfcOpenShell/IfcOpenShell/issues/1649
instance.declaration().is(Schema::IfcProfileDef::Class())
) {
IfcGeom::ConversionResults shapes;
try {
shapes = kernel.convert(instance);
} catch (...) {
}
return new IfcGeom::Transformation(kernel.settings(), item);
} else {
if (!representation) {
if (instance.declaration().is("IfcRepresentationItem") ||
instance.declaration().is("IfcRepresentation") ||
// https://github.com/IfcOpenShell/IfcOpenShell/issues/1649
instance.declaration().is("IfcProfileDef")
) {
IfcGeom::ConversionResults shapes;
try {
shapes = kernel.convert(instance);
} catch (...) {
std::ostringstream oss;
instance.to_string(oss);
throw ifcopenshell::exception("Failed to process shape. Instance: " + oss.str());
@@ -1037,75 +903,12 @@ ifcopenshell::geometry::taxonomy::item::ptr try_upcast(PyObject* obj0, swig_type
std::unique_ptr<ifcopenshell::geometry::abstract_mapping> mapping(ifcopenshell::geometry::impl::mapping_implementations().construct(instance.file(), settings));
return mapping->map(instance);
}
%}
%inline %{
static std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*> create_shape(ifcopenshell::geometry::Settings& settings, const express::Base& instance, const express::Base& representation, const char* const geometry_library="opencascade") {
const std::string& schema_name = instance.declaration().schema()->name();
#ifdef HAS_SCHEMA_2x3
if (schema_name == "IFC2X3") {
return helper_fn_create_shape<Ifc2x3>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4
if (schema_name == "IFC4") {
return helper_fn_create_shape<Ifc4>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x1
if (schema_name == "IFC4X1") {
return helper_fn_create_shape<Ifc4x1>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x2
if (schema_name == "IFC4X2") {
return helper_fn_create_shape<Ifc4x2>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_rc1
if (schema_name == "IFC4X3_RC1") {
return helper_fn_create_shape<Ifc4x3_rc1>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_rc2
if (schema_name == "IFC4X3_RC2") {
return helper_fn_create_shape<Ifc4x3_rc2>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_rc3
if (schema_name == "IFC4X3_RC3") {
return helper_fn_create_shape<Ifc4x3_rc3>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_rc4
if (schema_name == "IFC4X3_RC4") {
return helper_fn_create_shape<Ifc4x3_rc4>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3
if (schema_name == "IFC4X3") {
return helper_fn_create_shape<Ifc4x3>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_tc1
if (schema_name == "IFC4X3_TC1") {
return helper_fn_create_shape<Ifc4x3_tc1>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_add1
if (schema_name == "IFC4X3_ADD1") {
return helper_fn_create_shape<Ifc4x3_add1>(geometry_library, settings, instance, representation);
}
#endif
#ifdef HAS_SCHEMA_4x3_add2
if (schema_name == "IFC4X3_ADD2") {
return helper_fn_create_shape<Ifc4x3_add2>(geometry_library, settings, instance, representation);
}
#endif
throw ifcopenshell::exception("No geometry support for " + schema_name);
}
%}
%inline %{
static std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*> create_shape(ifcopenshell::geometry::Settings& settings, const express::Base& instance, const express::Base& representation, const char* const geometry_library="opencascade") {
return helper_fn_create_shape(geometry_library, settings, instance, representation);
}
// Manual definition of overload without representation argument
static std::variant<IfcGeom::Element*, IfcGeom::Representation::Representation*, IfcGeom::Transformation*> create_shape(ifcopenshell::geometry::Settings& settings, const express::Base& instance, const char* const geometry_library="opencascade") {
@@ -1113,13 +916,15 @@ ifcopenshell::geometry::taxonomy::item::ptr try_upcast(PyObject* obj0, swig_type
}
%}
#ifdef IFOPSH_WITH_OPENCASCADE
%inline %{
express::Base serialise(ifcopenshell::file& f, const std::string& shape_str, bool advanced=true) {
std::stringstream stream(shape_str);
BRepTools_ShapeSet shapes;
shapes.Read(stream);
#ifdef IFOPSH_WITH_OPENCASCADE
%inline %{
#include <BRepTools_ShapeSet.hxx>
express::Base serialise(ifcopenshell::file& f, const std::string& shape_str, bool advanced=true) {
std::stringstream stream(shape_str);
BRepTools_ShapeSet shapes;
shapes.Read(stream);
const TopoDS_Shape& shp = shapes.Shape(shapes.NbShapes());
return IfcGeom::serialise(f, shp, advanced);
@@ -1137,86 +942,95 @@ ifcopenshell::geometry::taxonomy::item::ptr try_upcast(PyObject* obj0, swig_type
#endif
#ifdef IFOPSH_WITH_CGAL
%ignore hlr_writer;
%ignore hlr_calc;
%ignore occt_join;
%ignore prefiltered_hlr;
%ignore svgfill::svg_to_line_segments;
%ignore svgfill::line_segments_to_polygons;
%ignore svgfill::svg_to_polygons;
%ignore svgfill::arrange_polygons;
%template(svg_line_segments) std::vector<std::array<svgfill::point_2, 2>>;
%template(svg_groups_of_line_segments) std::vector<std::vector<std::array<svgfill::point_2, 2>>>;
%template(svg_point) std::array<double, 2>;
%template(line_segment) std::array<svgfill::point_2, 2>;
%template(svg_polygons) std::vector<svgfill::polygon_2>;
%template(svg_groups_of_polygons) std::vector<std::vector<svgfill::polygon_2>>;
%template(svg_loop) std::vector<std::array<double, 2>>;
%template(svg_loops) std::vector<std::vector<std::array<double, 2>>>;
%template(OpaqueCoordinate_3) IfcGeom::OpaqueCoordinate<3>;
%template(OpaqueCoordinate_4) IfcGeom::OpaqueCoordinate<4>;
%newobject create_epeck;
%inline %{
IfcGeom::OpaqueNumber* create_epeck(int i) {
return new ifcopenshell::geometry::NumberEpeck(i);
}
IfcGeom::OpaqueNumber* create_epeck(double d) {
return new ifcopenshell::geometry::NumberEpeck(d);
}
IfcGeom::OpaqueNumber* create_epeck(const std::string& s) {
return new ifcopenshell::geometry::NumberEpeck(typename CGAL::Epeck::FT::ET(s));
}
%}
%inline %{
IfcGeom::ConversionResultShape* nary_union(PyObject* sequence) {
std::vector<const CGAL::Nef_polyhedron_3<CGAL::Epeck>*> nefs;
for(Py_ssize_t i = 0; i < PySequence_Size(sequence); ++i) {
PyObject* element = PySequence_GetItem(sequence, i);
void* argp1 = nullptr;
auto res1 = SWIG_ConvertPtr(element, &argp1, SWIGTYPE_p_IfcGeom__ConversionResultShape, 0);
if (SWIG_IsOK(res1)) {
auto arg1 = reinterpret_cast<IfcGeom::ConversionResultShape*>(argp1);
auto cgs = dynamic_cast<ifcopenshell::geometry::CgalShape*>(arg1);
if (cgs) {
nefs.push_back(&cgs->nef());
}
}
}
ifcopenshell::geometry::CgalShape* shp;
Py_BEGIN_ALLOW_THREADS;
CGAL::Nef_nary_union_3< CGAL::Nef_polyhedron_3<CGAL::Epeck> > accum;
for (auto& n : nefs) {
accum.add_polyhedron(*n);
}
shp = new ifcopenshell::geometry::CgalShape(accum.get_union());
Py_END_ALLOW_THREADS;
return shp;
}
%}
%extend IfcGeom::ConversionResultShape {
std::string serialize_obj() {
std::ostringstream result;
auto cgs = dynamic_cast<ifcopenshell::geometry::CgalShape*>($self);
if (cgs) {
write_to_obj(cgs->nef(), result, std::numeric_limits<size_t>::max());
}
return result.str();
}
void convex_tag(bool b) {
auto cgs = dynamic_cast<ifcopenshell::geometry::CgalShape*>($self);
if (cgs) {
cgs->convex_tag() = b;
}
}
%template(OpaqueCoordinate_3) IfcGeom::OpaqueCoordinate<3>;
%template(OpaqueCoordinate_4) IfcGeom::OpaqueCoordinate<4>;
%newobject create_epeck;
%inline %{
IfcGeom::OpaqueNumber* create_epeck(int i) {
return new IfcGeom::NumberNativeDouble(i);
}
IfcGeom::OpaqueNumber* create_epeck(double d) {
return new IfcGeom::NumberNativeDouble(d);
}
IfcGeom::OpaqueNumber* create_epeck(const std::string& s) {
return new IfcGeom::NumberNativeDouble(std::stod(s));
}
%}
%inline %{
IfcGeom::ConversionResultShape* nary_union(PyObject* sequence) {
IfcGeom::ConversionResultShape* result = nullptr;
std::string backend_id;
auto identity = ifcopenshell::geometry::taxonomy::make<ifcopenshell::geometry::taxonomy::matrix4>();
for(Py_ssize_t i = 0; i < PySequence_Size(sequence); ++i) {
PyObject* element = PySequence_GetItem(sequence, i);
void* argp1 = nullptr;
auto res1 = SWIG_ConvertPtr(element, &argp1, SWIGTYPE_p_IfcGeom__ConversionResultShape, 0);
if (SWIG_IsOK(res1)) {
auto arg1 = reinterpret_cast<IfcGeom::ConversionResultShape*>(argp1);
auto element_backend_id = std::string(arg1->backend_id());
if (backend_id.empty()) {
backend_id = element_backend_id;
result = arg1->moved(identity);
} else {
if (element_backend_id != backend_id) {
delete result;
throw ifcopenshell::exception("nary_union requires shapes from the same geometry backend");
}
auto next = result->add(arg1);
if (!next) {
delete result;
throw ifcopenshell::exception("nary_union failed for backend " + backend_id);
}
delete result;
result = next;
}
}
}
if (!result) {
throw ifcopenshell::exception("nary_union requires at least one shape");
}
return result;
}
%}
%extend IfcGeom::ConversionResultShape {
std::string serialize_obj() {
ifcopenshell::geometry::Settings settings;
std::unique_ptr<IfcGeom::Representation::Triangulation> triangulation($self->Triangulate(settings));
std::ostringstream result;
for (auto it = triangulation->verts().begin(); it != triangulation->verts().end();) {
result << "v " << *(it++) << " " << *(it++) << " " << *(it++) << "\n";
}
for (auto it = triangulation->normals().begin(); it != triangulation->normals().end();) {
result << "vn " << *(it++) << " " << *(it++) << " " << *(it++) << "\n";
}
const bool has_normals = !triangulation->normals().empty();
for (auto it = triangulation->faces().begin(); it != triangulation->faces().end();) {
const auto v1 = *(it++) + 1;
const auto v2 = *(it++) + 1;
const auto v3 = *(it++) + 1;
if (has_normals) {
result << "f "
<< v1 << "//" << v1 << " "
<< v2 << "//" << v2 << " "
<< v3 << "//" << v3 << "\n";
} else {
result << "f " << v1 << " " << v2 << " " << v3 << "\n";
}
}
return result.str();
}
void convex_tag(bool b) {
(void)b;
throw ifcopenshell::exception("convex_tag is not available through the generic conversion result interface");
}
std::string serialize() {
std::string result;
@@ -1231,8 +1045,28 @@ ifcopenshell::geometry::taxonomy::item::ptr try_upcast(PyObject* obj0, swig_type
r = $self->solid();
Py_END_ALLOW_THREADS;
return r;
}
}
}
}
#ifdef IFOPSH_WITH_CGAL
%ignore hlr_writer;
%ignore hlr_calc;
%ignore occt_join;
%ignore prefiltered_hlr;
%ignore svgfill::svg_to_line_segments;
%ignore svgfill::line_segments_to_polygons;
%ignore svgfill::svg_to_polygons;
%ignore svgfill::arrange_polygons;
%template(svg_line_segments) std::vector<std::array<svgfill::point_2, 2>>;
%template(svg_groups_of_line_segments) std::vector<std::vector<std::array<svgfill::point_2, 2>>>;
%template(svg_point) std::array<double, 2>;
%template(line_segment) std::array<svgfill::point_2, 2>;
%template(svg_polygons) std::vector<svgfill::polygon_2>;
%template(svg_groups_of_polygons) std::vector<std::vector<svgfill::polygon_2>>;
%template(svg_loop) std::vector<std::array<double, 2>>;
%template(svg_loops) std::vector<std::vector<std::array<double, 2>>>;
%naturalvar svgfill::polygon_2::boundary;
%naturalvar svgfill::polygon_2::inner_boundaries;
+4 -16
View File
@@ -195,14 +195,10 @@
// of the module definition below.
%{
#include "../ifcgeom/Iterator.h"
#include "../ifcgeom/tree.h"
#include "../ifcgeom/Serialization/Serialization.h"
#include "../ifcgeom/taxonomy.h"
#include "../ifcgeom/function_item_evaluator.h"
#ifdef IFOPSH_WITH_OPENCASCADE
#include "../ifcgeom/Serialization/Serialization.h"
#include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
#include <BRepTools_ShapeSet.hxx>
#endif
#include "../serializers/SvgSerializer.h"
#include "../serializers/WavefrontObjSerializer.h"
@@ -256,10 +252,6 @@
#include "../ifcgeom/ConversionResult.h"
#include "../svgfill/src/svgfill.h"
#ifdef IFOPSH_WITH_CGAL
#include "../ifcgeom/kernels/cgal/CgalConversionResult.h"
#endif
%}
// Create docstrings for generated python code.
@@ -273,14 +265,10 @@
%module ifcopenshell_wrapper %{
#include "../ifcgeom/Converter.h"
#include "../ifcgeom/tree.h"
#include "../ifcgeom/Serialization/Serialization.h"
#include "../ifcgeom/taxonomy.h"
#include "../ifcgeom/function_item_evaluator.h"
#ifdef IFOPSH_WITH_OPENCASCADE
#include "../ifcgeom/Serialization/Serialization.h"
#include "../ifcgeom/kernels/opencascade/IfcGeomTree.h"
#include <BRepTools_ShapeSet.hxx>
#endif
#include "../ifcgeom/Iterator.h"
#include "../ifcgeom/ConversionResult.h"
#include "../ifcgeom/hybrid_kernel.h"
+83 -3
View File
@@ -29,6 +29,29 @@
template <> void* get_python_type<std::string>() { return &PyString_Type; }
#endif
template <typename T>
bool check_python_type(PyObject* element) {
return element->ob_type == get_python_type<T>();
}
inline bool convert_pyobject_to_base(PyObject* element, express::Base& value) {
void* arg = nullptr;
int result = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_express__Base, 0);
if (SWIG_IsOK(result) && arg) {
value = *static_cast<express::Base*>(arg);
return true;
}
value = express::Base{};
return false;
}
template <>
bool check_python_type<express::Base>(PyObject* element) {
express::Base value;
return convert_pyobject_to_base(element, value);
}
bool check_aggregate_of_type(PyObject* aggregate, void* type_obj) {
if (!PySequence_Check(aggregate)) return false;
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
@@ -57,6 +80,63 @@
return true;
}
template <typename T>
bool check_aggregate_of_type(PyObject* aggregate) {
if (!PySequence_Check(aggregate)) return false;
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
PyObject* element = PySequence_GetItem(aggregate, i);
bool valid = check_python_type<T>(element);
Py_DECREF(element);
if (!valid) {
return false;
}
}
return true;
}
template <>
bool check_aggregate_of_type<express::Base>(PyObject* aggregate) {
if (!PySequence_Check(aggregate)) return false;
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
PyObject* element = PySequence_GetItem(aggregate, i);
express::Base value;
bool valid = convert_pyobject_to_base(element, value);
Py_DECREF(element);
if (!valid) {
return false;
}
}
return true;
}
template <typename T>
bool check_aggregate_of_aggregate_of_type(PyObject* aggregate) {
if (!PySequence_Check(aggregate)) return false;
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
PyObject* element = PySequence_GetItem(aggregate, i);
bool valid = check_aggregate_of_type<T>(element);
Py_DECREF(element);
if (!valid) {
return false;
}
}
return true;
}
template <>
bool check_aggregate_of_aggregate_of_type<express::Base>(PyObject* aggregate) {
if (!PySequence_Check(aggregate)) return false;
for(Py_ssize_t i = 0; i < PySequence_Size(aggregate); ++i) {
PyObject* element = PySequence_GetItem(aggregate, i);
bool valid = check_aggregate_of_type<express::Base>(element);
Py_DECREF(element);
if (!valid) {
return false;
}
}
return true;
}
template <typename T>
T cast_pyobject(PyObject* element);
@@ -87,9 +167,8 @@
template <>
express::Base cast_pyobject(PyObject* element) {
void *arg = 0;
int res = SWIG_ConvertPtr(element, &arg, SWIGTYPE_p_express__Base, 0);
return SWIG_IsOK(res) ? *reinterpret_cast<express::Base*>(arg) : express::Base{};
express::Base value;
return convert_pyobject_to_base(element, value) ? value : express::Base{};
}
template<typename T>
@@ -112,6 +191,7 @@
PyObject* element = PySequence_GetItem(aggregate, i);
T t = cast_pyobject<T>(element);
add_to_container(result_vector, t);
Py_DECREF(element);
}
return result_vector;
}
+7 -57
View File
@@ -20,23 +20,23 @@
%define CREATE_VECTOR_TYPEMAP_IN(template_type, express_name, python_name)
%typemap(in) std::vector<template_type> {
if (!check_aggregate_of_type($input, get_python_type<template_type>())) {
if (!check_aggregate_of_type<template_type>($input)) {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF " #express_name " needs a python sequence of " #python_name "s");
}
$1 = python_sequence_as_vector<template_type>($input);
}
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) std::vector<template_type> {
$1 = check_aggregate_of_type($input, get_python_type<template_type>()) ? 1 : 0;
$1 = check_aggregate_of_type<template_type>($input) ? 1 : 0;
}
%typemap(typecheck,precedence=SWIG_TYPECHECK_INTEGER) const std::vector<template_type>& {
$1 = check_aggregate_of_type($input, get_python_type<template_type>()) ? 1 : 0;
$1 = check_aggregate_of_type<template_type>($input) ? 1 : 0;
}
%typemap(arginit) const std::vector<template_type>& {
$1 = new std::vector<template_type>();
}
%typemap(in) const std::vector<template_type>& {
if (!check_aggregate_of_type($input, get_python_type<template_type>())) {
if (!check_aggregate_of_type<template_type>($input)) {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF " #express_name " needs a python sequence of " #python_name "s");
}
*$1 = python_sequence_as_vector<template_type>($input);
@@ -46,7 +46,7 @@
}
%typemap(in) std::vector< std::vector<template_type> > {
if (!check_aggregate_of_aggregate_of_type($input, get_python_type<template_type>())) {
if (!check_aggregate_of_aggregate_of_type<template_type>($input)) {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF " #express_name " needs a python sequence of sequence of " #python_name "s");
}
$1 = python_sequence_as_vector_of_vector<template_type>($input);
@@ -56,7 +56,7 @@
$1 = new std::vector< std::vector<template_type> >();
}
%typemap(in) const std::vector< std::vector<template_type> >& {
if (!check_aggregate_of_aggregate_of_type($input, get_python_type<template_type>())) {
if (!check_aggregate_of_aggregate_of_type<template_type>($input)) {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF " #express_name " needs a python sequence of sequence of " #python_name "s");
}
*$1 = python_sequence_as_vector_of_vector<template_type>($input);
@@ -70,6 +70,7 @@
CREATE_VECTOR_TYPEMAP_IN(int, INTEGER, int)
CREATE_VECTOR_TYPEMAP_IN(double, REAL, float)
CREATE_VECTOR_TYPEMAP_IN(std::string, STRING, str)
CREATE_VECTOR_TYPEMAP_IN(express::Base, ENTITY INSTANCE, entity instance)
// @todo use macros.
@@ -166,57 +167,6 @@ CREATE_VECTOR_TYPEMAP_IN(std::string, STRING, str)
}
}
%typemap(in) aggregate_of_instance::ptr {
if (PySequence_Check($input)) {
$1 = aggregate_of_instance::ptr(new aggregate_of_instance());
for(Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
PyObject* element = PySequence_GetItem($input, i);
express::Base inst = cast_pyobject<express::Base>(element);
Py_DECREF(element);
if (inst) {
$1->push(inst);
} else {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF ENTITY INSTANCE needs a python sequence of entity instances");
}
}
} else {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF ENTITY INSTANCE needs a python sequence of entity instances");
}
}
%typemap(in) aggregate_of_aggregate_of_instance::ptr {
if (PySequence_Check($input)) {
$1 = aggregate_of_aggregate_of_instance::ptr(new aggregate_of_aggregate_of_instance());
for(Py_ssize_t i = 0; i < PySequence_Size($input); ++i) {
PyObject* element = PySequence_GetItem($input, i);
bool b = false;
if (PySequence_Check(element)) {
b = true;
std::vector<express::Base> vector;
vector.reserve(PySequence_Size(element));
for(Py_ssize_t j = 0; j < PySequence_Size(element); ++j) {
PyObject* element_element = PySequence_GetItem(element, j);
express::Base inst = cast_pyobject<express::Base>(element_element);
Py_DECREF(element_element);
if (inst) {
vector.push_back(inst);
} else {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF ENTITY INSTANCE needs a python sequence of sequence of entity instances");
}
}
$1->push(vector);
}
Py_DECREF(element);
if (!b) {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF ENTITY INSTANCE needs a python sequence of sequence of entity instances");
break;
}
}
} else {
SWIG_exception(SWIG_TypeError, "Attribute of type AGGREGATE OF AGGREGATE OF ENTITY INSTANCE needs a python sequence of sequence of entity instances");
}
}
%typemap(in) const gp_Pnt& {
if (!check_aggregate_of_type($input, get_python_type<double>())) {
SWIG_exception(SWIG_TypeError, "<Point> type needs a python sequence of 3 floats");
+33
View File
@@ -19,6 +19,12 @@
#include "plugin.h"
#ifndef _WIN32
#include <dlfcn.h>
#else
#include <windows.h>
#endif
#include <boost/algorithm/string/predicate.hpp>
#include <boost/dll/shared_library.hpp>
@@ -195,3 +201,30 @@ void ifcopenshell::plugin::validate_abi(const abi_info& abi) {
stream << " (plugin debug " << abi.debug_build << ", host debug " << host.debug_build << ")";
throw std::runtime_error(stream.str());
}
std::filesystem::path ifcopenshell::plugin::module_directory(const void* symbol) {
#ifdef _WIN32
HMODULE module_handle = nullptr;
if (!GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCWSTR>(symbol),
&module_handle)) {
throw std::runtime_error("Unable to resolve module path");
}
wchar_t buffer[MAX_PATH];
const DWORD length = GetModuleFileNameW(module_handle, buffer, MAX_PATH);
if (length == 0) {
throw std::runtime_error("Unable to read module filename");
}
return std::filesystem::path(std::wstring(buffer, length)).parent_path();
#else
Dl_info info;
if (dladdr(symbol, &info) == 0 || !info.dli_fname) {
throw std::runtime_error("Unable to resolve module path");
}
return std::filesystem::path(info.dli_fname).parent_path();
#endif
}
+2
View File
@@ -37,6 +37,7 @@ enum class kind {
parse_schema,
mapping,
kernel,
tree,
document_serializer,
geometry_serializer,
opencascade_geometry_ifc_writer
@@ -101,6 +102,7 @@ private:
PLUGIN_API abi_info host_abi();
PLUGIN_API void validate_abi(const abi_info& abi);
PLUGIN_API std::filesystem::path module_directory(const void* symbol);
}
}
+3 -1
View File
@@ -20,7 +20,9 @@
#ifndef PLUGIN_API_H
#define PLUGIN_API_H
#ifdef _WIN32
#ifdef SWIG
#define PLUGIN_API
#elif defined(_WIN32)
#ifdef PLUGIN_EXPORTS
#define PLUGIN_API __declspec(dllexport)
#else
+7 -3
View File
@@ -2,12 +2,12 @@ add_subdirectory(schema_dependent)
file(GLOB SERIALIZERS_H_FILES *.h)
file(GLOB SERIALIZERS_CPP_FILES *.cpp)
file(GLOB SERIALIZERS_S_H_FILES schema_dependent/*.h)
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)
if(WITH_PROJ)
find_package(proj REQUIRED)
@@ -20,7 +20,7 @@ endif()
target_link_libraries(Serializers
PRIVATE
${SERIALIZER_SCHEMA_LIBRARIES} ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}
plugin ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}
IfcGeom ${OpenCASCADE_LIBRARIES} IfcParse
)
@@ -28,7 +28,7 @@ if(WITH_OPENCASCADE)
target_link_libraries(Serializers PRIVATE geometry_kernel_opencascade)
endif()
install(TARGETS Serializers)
install(TARGETS Serializers ${document_serializer_libraries})
install(FILES ${SERIALIZERS_H_FILES}
DESTINATION ${INCLUDEDIR}/serializers/
@@ -37,3 +37,7 @@ install(FILES ${SERIALIZERS_H_FILES}
install(FILES ${SERIALIZERS_S_H_FILES}
DESTINATION ${INCLUDEDIR}/serializers/schema_dependent
)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} Serializers)
set(IFCOPENSHELL_LIBRARIES ${IFCOPENSHELL_LIBRARIES} PARENT_SCOPE)
set(document_serializer_libraries ${document_serializer_libraries} PARENT_SCOPE)
+7 -16
View File
@@ -20,35 +20,26 @@
#ifdef WITH_GLTF
#include "JsonSerializer.h"
#include "document_serializer_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
#define EXTERNAL_DEFS(r, data, elem) \
extern void BOOST_PP_CAT(init_JsonSerializer_Ifc, elem)(JsonSerializerFactory::Factory*);
#define CALL_DEFS(r, data, elem) \
BOOST_PP_CAT(init_JsonSerializer_Ifc, elem)(this);
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS, , SCHEMA_SEQ)
JsonSerializerFactory::Factory::Factory() {
BOOST_PP_SEQ_FOR_EACH(CALL_DEFS, , SCHEMA_SEQ)
ifcopenshell::serializers::load_document_serializer_plugins(*this, "json");
}
void JsonSerializerFactory::Factory::bind(const std::string& schema_name, fn f) {
void JsonSerializerFactory::Factory::bind(const std::string& schema_name, fn f, const ifcopenshell::plugin::module& module) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
this->insert(std::make_pair(schema_name_lower, f));
entries_[schema_name_lower] = { f, module };
}
JsonSerializer* JsonSerializerFactory::Factory::construct(const std::string& schema_name, ifcopenshell::file* file, std::string json_filename, JsonSerializer::Dialect dialect) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
auto it = this->find(schema_name_lower);
if (it == this->end()) {
auto it = entries_.find(schema_name_lower);
if (it == entries_.end()) {
throw ifcopenshell::exception("No Json serializer registered for " + schema_name);
}
return it->second(file, json_filename, dialect);
return it->second.fn_(file, json_filename, dialect);
}
JsonSerializer::JsonSerializer(ifcopenshell::file* file, const std::string& json_filename, JsonSerializer::Dialect dialect) {
+12 -3
View File
@@ -5,6 +5,7 @@
#include "../ifcgeom/Serializer.h"
#include "../ifcparse/file.h"
#include "../plugin/plugin.h"
#include "../serializers/serializers_api.h"
#include <boost/function.hpp>
@@ -16,7 +17,7 @@ class SERIALIZERS_API JsonSerializer : public Serializer {
JSON_DIALECT_CREOOX
};
private:
JsonSerializer* implementation_;
JsonSerializer* implementation_ = nullptr;
protected:
std::string json_filename;
@@ -37,11 +38,19 @@ class SERIALIZERS_API JsonSerializer : public Serializer {
struct SERIALIZERS_API JsonSerializerFactory {
typedef boost::function3<JsonSerializer*, ifcopenshell::file*, std::string, JsonSerializer::Dialect> fn;
class Factory : public std::map<std::string, fn> {
class SERIALIZERS_API Factory {
public:
Factory();
void bind(const std::string& schema_name, fn);
void bind(const std::string& schema_name, fn, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
JsonSerializer* construct(const std::string& schema_name, ifcopenshell::file*, std::string, JsonSerializer::Dialect);
private:
struct entry {
fn fn_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
};
static Factory& implementations();
+7 -17
View File
@@ -1,34 +1,24 @@
#include "XmlSerializer.h"
#include "document_serializer_plugin.h"
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#define EXTERNAL_DEFS(r, data, elem) \
extern void BOOST_PP_CAT(init_XmlSerializer_Ifc, elem)(XmlSerializerFactory::Factory*);
#define CALL_DEFS(r, data, elem) \
BOOST_PP_CAT(init_XmlSerializer_Ifc, elem)(this);
BOOST_PP_SEQ_FOR_EACH(EXTERNAL_DEFS, , SCHEMA_SEQ)
XmlSerializerFactory::Factory::Factory() {
BOOST_PP_SEQ_FOR_EACH(CALL_DEFS, , SCHEMA_SEQ)
ifcopenshell::serializers::load_document_serializer_plugins(*this, "xml");
}
void XmlSerializerFactory::Factory::bind(const std::string& schema_name, fn f) {
void XmlSerializerFactory::Factory::bind(const std::string& schema_name, fn f, const ifcopenshell::plugin::module& module) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
this->insert(std::make_pair(schema_name_lower, f));
entries_[schema_name_lower] = { f, module };
}
XmlSerializer* XmlSerializerFactory::Factory::construct(const std::string& schema_name, ifcopenshell::file* file, std::string xml_filename) {
const std::string schema_name_lower = boost::to_lower_copy(schema_name);
typename std::map<std::string, fn>::const_iterator it;
it = this->find(schema_name_lower);
if (it == this->end()) {
auto it = entries_.find(schema_name_lower);
if (it == entries_.end()) {
throw ifcopenshell::exception("No XML serializer registered for " + schema_name);
}
return it->second(file, xml_filename);
return it->second.fn_(file, xml_filename);
}
XmlSerializer::XmlSerializer(ifcopenshell::file* file, const std::string& xml_filename) {
+17 -3
View File
@@ -1,8 +1,12 @@
#ifndef XMLSERIALIZER_H
#define XMLSERIALIZER_H
#define SCHEMA_METHOD
#include "../serializers/serializers_api.h"
#include "../ifcgeom/Serializer.h"
#include "../ifcparse/file.h"
#include "../plugin/plugin.h"
#include <boost/function.hpp>
@@ -10,7 +14,7 @@
class SERIALIZERS_API XmlSerializer : public Serializer {
private:
XmlSerializer* implementation_;
XmlSerializer* implementation_ = nullptr;
protected:
std::string xml_filename;
@@ -30,12 +34,22 @@ public:
struct SERIALIZERS_API XmlSerializerFactory {
typedef boost::function2<XmlSerializer*, ifcopenshell::file*, std::string> fn;
class Factory : public std::map<std::string, fn> {
class SERIALIZERS_API Factory {
public:
Factory();
void bind(const std::string& schema_name, fn);
void bind(const std::string& schema_name, fn, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
XmlSerializer* construct(const std::string& schema_name, ifcopenshell::file*, std::string);
private:
struct entry {
fn fn_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
};
static Factory& implementations();
};
#endif
@@ -0,0 +1,78 @@
/********************************************************************************
* *
* 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 "document_serializer_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
namespace {
std::string document_serializer_plugin_prefix(const std::string& format) {
return "document." + boost::to_lower_copy(format) + ".";
}
template <typename registry_t, typename register_plugin_t>
void load_document_serializer_plugins_impl(registry_t& registry, const std::string& format) {
ifcopenshell::plugin::manager manager;
manager.add_search_path(ifcopenshell::serializers::document_serializer_plugin_directory());
const auto format_lower = boost::to_lower_copy(format);
const auto prefix = document_serializer_plugin_prefix(format_lower);
for (const auto& path : manager.discover(prefix)) {
auto module = manager.load(path);
if (module.meta().kind_ != ifcopenshell::plugin::kind::document_serializer) {
continue;
}
if (boost::to_lower_copy(module.meta().format) != format_lower) {
continue;
}
auto register_plugin = module.get_alias<register_plugin_t>(ifcopenshell::serializers::document_serializer_plugin_registration_symbol());
register_plugin(registry, module);
}
}
}
const char* ifcopenshell::serializers::document_serializer_plugin_registration_symbol() {
return "ifcopenshell_register_document_serializer_plugin_v1";
}
ifcopenshell::plugin::metadata ifcopenshell::serializers::document_serializer_plugin_metadata(const std::string& format, const std::string& schema_name) {
plugin::metadata metadata;
metadata.kind_ = plugin::kind::document_serializer;
metadata.id = document_serializer_plugin_prefix(format) + boost::to_lower_copy(schema_name);
metadata.schema = boost::to_upper_copy(schema_name);
metadata.format = boost::to_lower_copy(format);
return metadata;
}
std::filesystem::path ifcopenshell::serializers::document_serializer_plugin_directory() {
return plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::serializers::document_serializer_plugin_directory));
}
void ifcopenshell::serializers::load_document_serializer_plugins(XmlSerializerFactory::Factory& registry, const std::string& format) {
load_document_serializer_plugins_impl<XmlSerializerFactory::Factory, register_xml_document_serializer_plugin_fn>(registry, format);
}
#ifdef WITH_GLTF
void ifcopenshell::serializers::load_document_serializer_plugins(JsonSerializerFactory::Factory& registry, const std::string& format) {
load_document_serializer_plugins_impl<JsonSerializerFactory::Factory, register_json_document_serializer_plugin_fn>(registry, format);
}
#endif
@@ -0,0 +1,51 @@
/********************************************************************************
* *
* 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_DOCUMENT_SERIALIZER_PLUGIN_H
#define IFCOPENSHELL_DOCUMENT_SERIALIZER_PLUGIN_H
#include "XmlSerializer.h"
#ifdef WITH_GLTF
#include "JsonSerializer.h"
#endif
#include <filesystem>
#include <string>
namespace ifcopenshell {
namespace serializers {
typedef void register_xml_document_serializer_plugin_fn(XmlSerializerFactory::Factory&, const ifcopenshell::plugin::module&);
SERIALIZERS_API const char* document_serializer_plugin_registration_symbol();
SERIALIZERS_API ifcopenshell::plugin::metadata document_serializer_plugin_metadata(const std::string& format, const std::string& schema_name);
SERIALIZERS_API std::filesystem::path document_serializer_plugin_directory();
SERIALIZERS_API void load_document_serializer_plugins(XmlSerializerFactory::Factory& registry, const std::string& format);
#ifdef WITH_GLTF
typedef void register_json_document_serializer_plugin_fn(JsonSerializerFactory::Factory&, const ifcopenshell::plugin::module&);
SERIALIZERS_API void load_document_serializer_plugins(JsonSerializerFactory::Factory& registry, const std::string& format);
#endif
}
}
#endif
+22 -14
View File
@@ -1,19 +1,27 @@
file(GLOB SERIALIZERS_S_H_FILES *.h)
file(GLOB SERIALIZERS_S_CPP_FILES *.cpp)
set(SERIALIZERS_S_FILES ${SERIALIZERS_S_H_FILES} ${SERIALIZERS_S_CPP_FILES})
set(document_serializer_plugin_runtime_dir "${CMAKE_BINARY_DIR}/serializers/$<CONFIG>")
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 "-DSERIALIZERS_EXPORTS -DIfcSchema=Ifc${schema}")
if(WASM_BUILD)
target_link_libraries(Serializers_ifc${schema} ${HDF5_LIBRARIES})
else()
target_link_libraries(Serializers_ifc${schema} IfcGeom ${OpenCASCADE_LIBRARIES} ${HDF5_LIBRARIES})
endif()
add_library(document_serializer_xml_ifc${schema} SHARED XmlSerializer.cpp xml_plugin.cpp)
target_link_libraries(document_serializer_xml_ifc${schema} PRIVATE plugin Serializers IfcGeom IfcParse)
set_target_properties(document_serializer_xml_ifc${schema} PROPERTIES
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
OUTPUT_NAME "document.xml.ifc${schema}"
RUNTIME_OUTPUT_DIRECTORY "${document_serializer_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${document_serializer_plugin_runtime_dir}"
)
list(APPEND document_serializer_libraries document_serializer_xml_ifc${schema})
install(TARGETS Serializers_ifc${schema})
if(WITH_GLTF)
add_library(document_serializer_json_ifc${schema} SHARED JsonSerializer.cpp json_plugin.cpp)
target_link_libraries(document_serializer_json_ifc${schema} PRIVATE plugin Serializers IfcGeom IfcParse)
set_target_properties(document_serializer_json_ifc${schema} PROPERTIES
COMPILE_FLAGS "-DIfcSchema=Ifc${schema}"
OUTPUT_NAME "document.json.ifc${schema}"
RUNTIME_OUTPUT_DIRECTORY "${document_serializer_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${document_serializer_plugin_runtime_dir}"
)
list(APPEND document_serializer_libraries document_serializer_json_ifc${schema})
endif()
endforeach()
set(SERIALIZER_SCHEMA_LIBRARIES ${SERIALIZER_SCHEMA_LIBRARIES} PARENT_SCOPE)
set(document_serializer_libraries ${document_serializer_libraries} PARENT_SCOPE)
@@ -32,22 +32,6 @@
using json = nlohmann::json;
namespace {
struct POSTFIX_SCHEMA(factory_t) {
JsonSerializer* operator()(ifcopenshell::file* file, const std::string& json_filename, JsonSerializer::Dialect dialect) const {
POSTFIX_SCHEMA(JsonSerializer)* s = new POSTFIX_SCHEMA(JsonSerializer)(file, json_filename, dialect);
s->setFile(file);
return s;
}
};
}
void MAKE_INIT_FN(JsonSerializer)(JsonSerializerFactory::Factory* mapping) {
static const std::string schema_name = STRINGIFY(IfcSchema);
POSTFIX_SCHEMA(factory_t) factory;
mapping->bind(schema_name, factory);
}
namespace {
class format_value_visitor : public boost::static_visitor<std::string> {
@@ -598,4 +582,4 @@ void POSTFIX_SCHEMA(JsonSerializer)::finalize() {
f << output.dump(4);
}
#endif
#endif
@@ -32,24 +32,6 @@
using boost::property_tree::ptree;
#include "XmlSerializer.h"
namespace {
struct POSTFIX_SCHEMA(factory_t) {
XmlSerializer* operator()(ifcopenshell::file* file, const std::string& xml_filename) const {
POSTFIX_SCHEMA(XmlSerializer)* s = new POSTFIX_SCHEMA(XmlSerializer)(file, xml_filename);
s->setFile(file);
return s;
}
};
}
void MAKE_INIT_FN(XmlSerializer)(XmlSerializerFactory::Factory* mapping) {
static const std::string schema_name = STRINGIFY(IfcSchema);
POSTFIX_SCHEMA(factory_t) factory;
mapping->bind(schema_name, factory);
}
namespace {
// TODO: Make this a member of XmlSerializer?
@@ -0,0 +1,66 @@
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifdef WITH_GLTF
#include "../document_serializer_plugin.h"
#include "JsonSerializer.h"
#include "../../ifcparse/macros.h"
#include <boost/dll/alias.hpp>
namespace {
struct factory_t {
JsonSerializer* operator()(ifcopenshell::file* file, const std::string& json_filename, JsonSerializer::Dialect dialect) const {
auto* serializer = new POSTFIX_SCHEMA(JsonSerializer)(file, json_filename, dialect);
serializer->setFile(file);
return serializer;
}
};
}
namespace ifcopenshell {
namespace serializers {
namespace json_document_serializer_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return document_serializer_plugin_metadata("json", STRINGIFY(IfcSchema));
}
void register_plugin(JsonSerializerFactory::Factory& registry, const plugin::module& module) {
factory_t factory;
registry.bind(STRINGIFY(IfcSchema), factory, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::json_document_serializer_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::json_document_serializer_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::json_document_serializer_plugin::register_plugin, ifcopenshell_register_document_serializer_plugin_v1)
#endif
@@ -0,0 +1,62 @@
/********************************************************************************
* *
* 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 "../document_serializer_plugin.h"
#include "XmlSerializer.h"
#include "../../ifcparse/macros.h"
#include <boost/dll/alias.hpp>
namespace {
struct factory_t {
XmlSerializer* operator()(ifcopenshell::file* file, const std::string& xml_filename) const {
auto* serializer = new POSTFIX_SCHEMA(XmlSerializer)(file, xml_filename);
serializer->setFile(file);
return serializer;
}
};
}
namespace ifcopenshell {
namespace serializers {
namespace xml_document_serializer_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return document_serializer_plugin_metadata("xml", STRINGIFY(IfcSchema));
}
void register_plugin(XmlSerializerFactory::Factory& registry, const plugin::module& module) {
factory_t factory;
registry.bind(STRINGIFY(IfcSchema), factory, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::xml_document_serializer_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::xml_document_serializer_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::xml_document_serializer_plugin::register_plugin, ifcopenshell_register_document_serializer_plugin_v1)
+3 -1
View File
@@ -20,7 +20,9 @@
#ifndef IFC_SERIALIZERS_API_H
#define IFC_SERIALIZERS_API_H
#ifdef _WIN32
#ifdef SWIG
#define SERIALIZERS_API
#elif defined(_WIN32)
#ifdef SERIALIZERS_EXPORTS
#define SERIALIZERS_API __declspec(dllexport)
#else
+3 -1
View File
@@ -21,7 +21,9 @@
#ifndef SVGFILL_H
#define SVGFILL_H
#ifdef _WIN32
#ifdef SWIG
#define SVGFILL_API
#elif defined(_WIN32)
#ifdef svgfill_EXPORTS
#define SVGFILL_API __declspec(dllexport)
#else