More work on isolating into plug-ins

This commit is contained in:
Thomas Krijnen
2026-04-18 15:46:21 +02:00
parent d2cc66fdf0
commit b599ee1040
34 changed files with 1818 additions and 606 deletions
+73 -21
View File
@@ -1,34 +1,87 @@
add_subdirectory(schema_dependent)
set(document_serializer_plugin_runtime_dir "${CMAKE_BINARY_DIR}/serializers/$<CONFIG>")
set(geometry_serializer_plugin_runtime_dir "${CMAKE_BINARY_DIR}/serializers/$<CONFIG>")
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}")
function(add_document_serializer_plugin target output_name)
cmake_parse_arguments(PLUGIN "" "" "SOURCES;LIBRARIES" ${ARGN})
if(WITH_PROJ)
find_package(proj REQUIRED)
target_compile_definitions(Serializers PRIVATE "WITH_PROJ")
if(PROJ_STATIC)
target_compile_definitions(Serializers PRIVATE "PROJ_DLL=")
add_library(${target} SHARED ${PLUGIN_SOURCES})
target_compile_definitions(${target} PRIVATE SERIALIZERS_EXPORTS BOOST_DLL_USE_STD_FS)
target_link_libraries(${target} PRIVATE plugin IfcGeom IfcParse ${PLUGIN_LIBRARIES})
set_target_properties(${target} PROPERTIES
OUTPUT_NAME "${output_name}"
RUNTIME_OUTPUT_DIRECTORY "${document_serializer_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${document_serializer_plugin_runtime_dir}"
)
list(APPEND document_serializer_libraries ${target})
set(document_serializer_libraries ${document_serializer_libraries} PARENT_SCOPE)
endfunction()
function(add_geometry_serializer_plugin target output_name)
cmake_parse_arguments(PLUGIN "" "" "SOURCES;LIBRARIES" ${ARGN})
add_library(${target} SHARED ${PLUGIN_SOURCES})
target_compile_definitions(${target} PRIVATE SERIALIZERS_EXPORTS BOOST_DLL_USE_STD_FS)
target_link_libraries(${target} PRIVATE plugin IfcGeom IfcParse ${PLUGIN_LIBRARIES})
if(WITH_PROJ)
find_package(proj REQUIRED)
target_compile_definitions(${target} PRIVATE "WITH_PROJ")
if(PROJ_STATIC)
target_compile_definitions(${target} PRIVATE "PROJ_DLL=")
endif()
target_link_libraries(${target} PRIVATE proj::proj)
endif()
target_link_libraries(Serializers PRIVATE proj::proj)
set_target_properties(${target} PROPERTIES
OUTPUT_NAME "${output_name}"
RUNTIME_OUTPUT_DIRECTORY "${geometry_serializer_plugin_runtime_dir}"
LIBRARY_OUTPUT_DIRECTORY "${geometry_serializer_plugin_runtime_dir}"
)
list(APPEND geometry_serializer_libraries ${target})
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
endfunction()
if(WITH_ROCKSDB)
add_document_serializer_plugin(document_serializer_rdb "document.rdb" SOURCES document_rdb_plugin.cpp RocksDbSerializer.cpp LIBRARIES RocksDB::rocksdb)
endif()
target_link_libraries(Serializers
PRIVATE
plugin ${OPENCOLLADA_LIBRARIES} ${USD_LIBRARIES}
IfcGeom ${OpenCASCADE_LIBRARIES} IfcParse
)
add_subdirectory(schema_dependent)
set(ttl_geometry_serializer_libraries)
if(WITH_OPENCASCADE)
set(ttl_geometry_serializer_libraries geometry_kernel_opencascade ${OpenCASCADE_LIBRARIES})
endif()
add_geometry_serializer_plugin(geometry_serializer_obj "geometry.obj" SOURCES geometry_obj_plugin.cpp WavefrontObjSerializer.cpp)
add_geometry_serializer_plugin(geometry_serializer_ttl "geometry.ttl" SOURCES geometry_ttl_plugin.cpp TtlWktSerializer.cpp LIBRARIES ${ttl_geometry_serializer_libraries})
if(OPENCOLLADA_FOUND)
add_geometry_serializer_plugin(geometry_serializer_dae "geometry.dae" SOURCES geometry_dae_plugin.cpp ColladaSerializer.cpp LIBRARIES ${OPENCOLLADA_LIBRARIES})
endif()
if(GLTF_SUPPORT)
add_geometry_serializer_plugin(geometry_serializer_glb "geometry.glb" SOURCES geometry_glb_plugin.cpp GltfSerializer.cpp)
endif()
if(USD_SUPPORT)
add_geometry_serializer_plugin(geometry_serializer_usd "geometry.usd" SOURCES geometry_usd_plugin.cpp USDSerializer.cpp LIBRARIES ${USD_LIBRARIES})
endif()
if(WITH_OPENCASCADE)
target_link_libraries(Serializers PRIVATE geometry_kernel_opencascade)
set(opencascade_geometry_serializer_libraries geometry_kernel_opencascade ${OpenCASCADE_LIBRARIES})
add_geometry_serializer_plugin(geometry_serializer_stp "geometry.stp" SOURCES geometry_stp_plugin.cpp OpenCascadeBasedSerializer.cpp LIBRARIES ${opencascade_geometry_serializer_libraries})
add_geometry_serializer_plugin(geometry_serializer_igs "geometry.igs" SOURCES geometry_igs_plugin.cpp OpenCascadeBasedSerializer.cpp LIBRARIES ${opencascade_geometry_serializer_libraries})
add_geometry_serializer_plugin(geometry_serializer_svg "geometry.svg" SOURCES geometry_svg_plugin.cpp SvgSerializer.cpp util.cpp LIBRARIES ${opencascade_geometry_serializer_libraries})
if(HDF5_SUPPORT)
add_geometry_serializer_plugin(geometry_serializer_hdf "geometry.hdf" SOURCES geometry_hdf_plugin.cpp HdfSerializer.cpp LIBRARIES ${opencascade_geometry_serializer_libraries} ${HDF5_LIBRARIES})
endif()
endif()
install(TARGETS Serializers ${document_serializer_libraries})
install(TARGETS ${document_serializer_libraries} ${geometry_serializer_libraries})
install(FILES ${SERIALIZERS_H_FILES}
DESTINATION ${INCLUDEDIR}/serializers/
@@ -38,6 +91,5 @@ 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)
set(geometry_serializer_libraries ${geometry_serializer_libraries} PARENT_SCOPE)
-56
View File
@@ -1,56 +0,0 @@
/********************************************************************************
* *
* 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 "JsonSerializer.h"
#include "document_serializer_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
JsonSerializerFactory::Factory::Factory() {
ifcopenshell::serializers::load_document_serializer_plugins(*this, "json");
}
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);
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 = entries_.find(schema_name_lower);
if (it == entries_.end()) {
throw ifcopenshell::exception("No Json serializer registered for " + schema_name);
}
return it->second.fn_(file, json_filename, dialect);
}
JsonSerializer::JsonSerializer(ifcopenshell::file* file, const std::string& json_filename, JsonSerializer::Dialect dialect) {
if (file) {
implementation_ = JsonSerializerFactory::implementations().construct(file->schema()->name(), file, json_filename, dialect);
}
}
JsonSerializerFactory::Factory& JsonSerializerFactory::implementations() {
static JsonSerializerFactory::Factory impl;
return impl;
}
#endif
+25 -27
View File
@@ -7,55 +7,53 @@
#include "../ifcparse/file.h"
#include "../plugin/plugin.h"
#include "../serializers/serializers_api.h"
#include "../serializers/document_serializer_plugin.h"
#include <boost/function.hpp>
#include <map>
#include <boost/shared_ptr.hpp>
class SERIALIZERS_API JsonSerializer : public Serializer {
class JsonSerializer : public Serializer {
public:
enum Dialect {
JSON_DIALECT_CREOOX
};
private:
JsonSerializer* implementation_ = nullptr;
boost::shared_ptr<Serializer> implementation_;
protected:
std::string json_filename;
Dialect dialect_;
public:
JsonSerializer(ifcopenshell::file* file, const std::string& json_filename, Dialect dialect = Dialect::JSON_DIALECT_CREOOX);
JsonSerializer(ifcopenshell::file* file, const std::string& json_filename, Dialect dialect = Dialect::JSON_DIALECT_CREOOX)
: json_filename(json_filename)
, dialect_(dialect)
{
if (!file) {
return;
}
ifcopenshell::serializers::document_serializer_context context;
context.file = file;
context.output_filename = json_filename;
context.schema_name = file->schema()->name();
context.dialect = static_cast<int>(dialect);
implementation_ = ifcopenshell::serializers::document_serializer_registry_instance().create("json", context);
}
virtual ~JsonSerializer() {}
bool ready() { return true; }
void writeHeader() {}
void finalize() { implementation_->finalize(); }
void finalize() {
if (!implementation_) {
throw ifcopenshell::exception("No JSON serializer implementation constructed");
}
implementation_->finalize();
}
void setFile(ifcopenshell::file*) { throw ifcopenshell::exception("Should be supplied on construction"); }
};
struct SERIALIZERS_API JsonSerializerFactory {
typedef boost::function3<JsonSerializer*, ifcopenshell::file*, std::string, JsonSerializer::Dialect> fn;
class SERIALIZERS_API Factory {
public:
Factory();
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();
};
#endif
#endif
+115
View File
@@ -86,17 +86,132 @@
#include "../ifcgeom/kernels/opencascade/OpenCascadeConversionResult.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/format.hpp>
#include <boost/tokenizer.hpp>
#include "SvgSerializer.h"
namespace {
const double PI2 = M_PI * 2.;
std::pair<double, double> parse_svg_bounds(const std::string& value) {
unsigned int width = 0;
unsigned int height = 0;
if (std::sscanf(value.c_str(), "%ux%u", &width, &height) == 2 && width > 0 && height > 0) {
return { static_cast<double>(width), static_cast<double>(height) };
}
throw std::runtime_error("Invalid use of --bounds");
}
std::pair<double, double> parse_svg_center(const std::string& value) {
double center_x = 0.;
double center_y = 0.;
if (std::sscanf(value.c_str(), "%lfx%lf", &center_x, &center_y) == 2 &&
center_x >= 0. && center_y >= 0. &&
center_x <= 1. && center_y <= 1.) {
return { center_x, center_y };
}
throw std::runtime_error("Invalid use of --center");
}
double parse_svg_scale(const std::string& value) {
unsigned int numerator = 0;
unsigned int denominator = 0;
if (std::sscanf(value.c_str(), "%u:%u", &numerator, &denominator) == 2 &&
numerator > 0 && denominator > 0) {
return static_cast<double>(numerator) / denominator;
}
throw std::runtime_error("Invalid use of --scale");
}
SvgSerializer::storey_height_display_types parse_storey_height_display(const std::string& value) {
const auto display = boost::to_lower_copy(value);
if (display == "none") {
return SvgSerializer::SH_NONE;
}
if (display == "full") {
return SvgSerializer::SH_FULL;
}
if (display == "left") {
return SvgSerializer::SH_LEFT;
}
throw std::runtime_error("Invalid use of --draw-storey-heights, expected none|full|left");
}
}
bool SvgSerializer::ready() {
return true;
}
void SvgSerializer::apply_settings() {
using namespace ifcopenshell::geometry::settings;
if (settings().get<SvgBounds>().has()) {
const auto bounds = parse_svg_bounds(settings().get<SvgBounds>().get());
setBoundingRectangle(bounds.first, bounds.second);
}
if (settings().get<SvgScale>().has()) {
setScale(parse_svg_scale(settings().get<SvgScale>().get()));
}
if (settings().get<SvgCenter>().has()) {
const auto center = parse_svg_center(settings().get<SvgCenter>().get());
setDrawingCenter(center.first, center.second);
}
if (settings().get<SvgSectionHeightFromStoreys>().get()) {
if (settings().get<SvgSectionHeight>().has()) {
setSectionHeightsFromStoreys(settings().get<SvgSectionHeight>().get());
} else {
setSectionHeightsFromStoreys();
}
} else if (settings().get<SvgSectionHeight>().has()) {
setSectionHeight(settings().get<SvgSectionHeight>().get());
}
setPrintSpaceNames(settings().get<SvgPrintSpaceNames>().get());
setPrintSpaceAreas(settings().get<SvgPrintSpaceAreas>().get());
setDrawDoorArcs(settings().get<SvgDoorArcs>().get());
setAutoSection(settings().get<SvgAutoSection>().get());
setAutoElevation(settings().get<SvgAutoElevation>().get());
setUseNamespace(settings().get<SvgUseNamespace>().get());
setUseHlrPoly(settings().get<SvgUseHlrPoly>().get());
setUsePrefiltering(settings().get<SvgUsePrefiltering>().get());
setSegmentProjection(settings().get<SvgSegmentProjection>().get());
setPolygonal(settings().get<SvgPolygonal>().get());
setAlwaysProject(settings().get<SvgAlwaysProject>().get());
setWithoutStoreys(settings().get<SvgWithoutStoreys>().get());
setNoCSS(settings().get<SvgNoCss>().get());
if (settings().get<SvgDrawStoreyHeights>().has()) {
setDrawStoreyHeights(parse_storey_height_display(settings().get<SvgDrawStoreyHeights>().get()));
}
if (settings().get<SvgStoreyHeightLineLength>().has()) {
setStoreyHeightLineLength(settings().get<SvgStoreyHeightLineLength>().get());
}
if (settings().get<SvgSpaceNameTransform>().has()) {
setSpaceNameTransform(settings().get<SvgSpaceNameTransform>().get());
}
if (settings().get<SvgSectionRef>().has()) {
setSectionRef(settings().get<SvgSectionRef>().get());
}
if (settings().get<SvgElevationRef>().has()) {
setElevationRef(settings().get<SvgElevationRef>().get());
}
if (settings().get<SvgElevationRefGuid>().has()) {
setElevationRefGuid(settings().get<SvgElevationRefGuid>().get());
}
}
void SvgSerializer::write(path_object& p, const TopoDS_Shape& comp_or_wire, std::optional<std::vector<double>> dash_array) {
/* ShapeFix_Wire fix;
Handle(ShapeExtend_WireData) data = new ShapeExtend_WireData;
+4 -1
View File
@@ -589,6 +589,7 @@ protected:
Bnd_Box bnd_;
void draw_hlr(const gp_Pln& pln, const drawing_key& drawing_name);
void apply_settings();
subtract_before_project subtraction_settings_;
@@ -627,7 +628,9 @@ public:
, hlr(nullptr)
, namespace_prefix_("data-")
, subtraction_settings_(ON_SLABS_AT_FLOORPLANS)
{}
{
apply_settings();
}
void addXCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { xcoords.push_back(fi); }
void addYCoordinate(const boost::shared_ptr<util::string_buffer::float_item>& fi) { ycoords.push_back(fi); }
void addSizeComponent(const boost::shared_ptr<util::string_buffer::float_item>& fi) { radii.push_back(fi); }
-33
View File
@@ -1,33 +0,0 @@
#include "XmlSerializer.h"
#include "document_serializer_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
XmlSerializerFactory::Factory::Factory() {
ifcopenshell::serializers::load_document_serializer_plugins(*this, "xml");
}
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);
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);
auto it = entries_.find(schema_name_lower);
if (it == entries_.end()) {
throw ifcopenshell::exception("No XML serializer registered for " + schema_name);
}
return it->second.fn_(file, xml_filename);
}
XmlSerializer::XmlSerializer(ifcopenshell::file* file, const std::string& xml_filename) {
if (file) {
implementation_ = XmlSerializerFactory::implementations().construct(file->schema()->name(), file, xml_filename);
}
}
XmlSerializerFactory::Factory& XmlSerializerFactory::implementations() {
static XmlSerializerFactory::Factory impl;
return impl;
}
+23 -28
View File
@@ -7,49 +7,44 @@
#include "../ifcgeom/Serializer.h"
#include "../ifcparse/file.h"
#include "../plugin/plugin.h"
#include "../serializers/document_serializer_plugin.h"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <map>
class SERIALIZERS_API XmlSerializer : public Serializer {
class XmlSerializer : public Serializer {
private:
XmlSerializer* implementation_ = nullptr;
boost::shared_ptr<Serializer> implementation_;
protected:
std::string xml_filename;
public:
XmlSerializer(ifcopenshell::file* file, const std::string& xml_filename);
XmlSerializer(ifcopenshell::file* file, const std::string& xml_filename)
: xml_filename(xml_filename)
{
if (!file) {
return;
}
ifcopenshell::serializers::document_serializer_context context;
context.file = file;
context.output_filename = xml_filename;
context.schema_name = file->schema()->name();
implementation_ = ifcopenshell::serializers::document_serializer_registry_instance().create("xml", context);
}
virtual ~XmlSerializer() {}
bool ready() { return true; }
void writeHeader() {}
void finalize() { implementation_->finalize(); }
void finalize() {
if (!implementation_) {
throw ifcopenshell::exception("No XML serializer implementation constructed");
}
implementation_->finalize();
}
void setFile(ifcopenshell::file*) { throw ifcopenshell::exception("Should be supplied on construction"); }
};
struct SERIALIZERS_API XmlSerializerFactory {
typedef boost::function2<XmlSerializer*, ifcopenshell::file*, std::string> fn;
class SERIALIZERS_API Factory {
public:
Factory();
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
+68
View File
@@ -0,0 +1,68 @@
/********************************************************************************
* *
* 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 "RocksDbSerializer.h"
#ifdef IFOPSH_WITH_ROCKSDB
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace {
boost::shared_ptr<Serializer> create_serializer(const ifcopenshell::serializers::document_serializer_context& context) {
if (!context.stream || context.input_filename.empty()) {
throw ifcopenshell::exception("RocksDB document serializer requires --stream input");
}
return boost::make_shared<RocksDbSerializer>(context.input_filename, context.output_filename, true);
}
}
namespace ifcopenshell {
namespace serializers {
namespace rdb_document_serializer_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return document_serializer_plugin_metadata("rdb");
}
void register_plugin(document_serializer_registry& registry, const plugin::module& module) {
document_serializer_info info;
info.format = "rdb";
info.supports_ifc_file = false;
info.supports_input_filename = true;
info.writes_final_output = true;
registry.bind(info, create_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::rdb_document_serializer_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::rdb_document_serializer_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::rdb_document_serializer_plugin::register_plugin, ifcopenshell_register_document_serializer_plugin_v1)
#endif
+130 -27
View File
@@ -21,35 +21,117 @@
#include <boost/algorithm/string/case_conv.hpp>
#include "../ifcparse/logger.h"
#include <mutex>
#include <set>
namespace {
std::string document_serializer_plugin_prefix(const std::string& format) {
return "document." + boost::to_lower_copy(format) + ".";
std::string document_serializer_key(const std::string& format) {
if (format.empty()) {
return format;
}
auto key = boost::to_lower_copy(format);
if (key.front() == '.') {
key.erase(key.begin());
}
return key;
}
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());
std::string document_serializer_schema_key(const std::string& schema_name) {
return boost::to_upper_copy(schema_name);
}
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;
}
std::string document_serializer_plugin_prefix(const std::string& format = std::string()) {
const auto format_key = document_serializer_key(format);
return format_key.empty() ? "document." : "document." + format_key;
}
auto register_plugin = module.get_alias<register_plugin_t>(ifcopenshell::serializers::document_serializer_plugin_registration_symbol());
register_plugin(registry, module);
void add_document_serializer_search_paths(ifcopenshell::plugin::manager& manager) {
const auto directory = ifcopenshell::serializers::document_serializer_plugin_directory();
manager.add_search_path(directory);
const auto sibling_directory = directory.parent_path().parent_path() / "serializers" / directory.filename();
if (sibling_directory != directory && std::filesystem::exists(sibling_directory)) {
manager.add_search_path(sibling_directory);
}
}
}
void ifcopenshell::serializers::document_serializer_registry::bind(const document_serializer_info& info, create_fn create, const plugin::module& module) {
entry entry;
entry.info_ = info;
entry.info_.format = document_serializer_key(entry.info_.format);
entry.info_.schema_name = document_serializer_schema_key(entry.info_.schema_name);
entry.create_ = create;
entry.module_ = module.meta().id.empty() ? plugin::module(document_serializer_plugin_metadata(entry.info_.format, entry.info_.schema_name)) : module;
entries_[entry.info_.format].push_back(entry);
}
const ifcopenshell::serializers::document_serializer_registry::entry* ifcopenshell::serializers::document_serializer_registry::find_entry_(const std::string& format, const std::string& schema_name) const {
const auto format_key = document_serializer_key(format);
const auto iter = entries_.find(format_key);
if (iter == entries_.end()) {
return nullptr;
}
const auto schema_key = document_serializer_schema_key(schema_name);
const entry* fallback = nullptr;
for (const auto& candidate : iter->second) {
if (candidate.info_.schema_name.empty()) {
if (!fallback) {
fallback = &candidate;
}
continue;
}
if (!schema_key.empty() && candidate.info_.schema_name == schema_key) {
return &candidate;
}
if (schema_key.empty() && !fallback) {
fallback = &candidate;
}
}
return fallback;
}
const ifcopenshell::serializers::document_serializer_info* ifcopenshell::serializers::document_serializer_registry::find(const std::string& format, const std::string& schema_name) const {
const auto* entry = find_entry_(format, schema_name);
return entry ? &entry->info_ : nullptr;
}
boost::shared_ptr<Serializer> ifcopenshell::serializers::document_serializer_registry::create(const std::string& format, const document_serializer_context& context) const {
const auto schema_name = !context.schema_name.empty() ? context.schema_name :
(context.file ? context.file->schema()->name() : std::string());
const auto* entry = find_entry_(format, schema_name);
if (!entry) {
throw ifcopenshell::exception("No document serializer registered for " + format + (schema_name.empty() ? std::string() : " and schema " + schema_name));
}
return entry->create_(context);
}
std::vector<ifcopenshell::serializers::document_serializer_info> ifcopenshell::serializers::document_serializer_registry::serializers() const {
std::vector<document_serializer_info> result;
std::set<std::string> seen;
for (const auto& pair : entries_) {
for (const auto& entry : pair.second) {
const auto key = entry.info_.format + "|" + entry.info_.schema_name;
if (!seen.insert(key).second) {
continue;
}
result.push_back(entry.info_);
}
}
return result;
}
const char* ifcopenshell::serializers::document_serializer_plugin_registration_symbol() {
return "ifcopenshell_register_document_serializer_plugin_v1";
}
@@ -57,9 +139,12 @@ const char* ifcopenshell::serializers::document_serializer_plugin_registration_s
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);
metadata.id = document_serializer_plugin_prefix(format);
if (!schema_name.empty()) {
metadata.id += "." + boost::to_lower_copy(schema_name);
}
metadata.schema = document_serializer_schema_key(schema_name);
metadata.format = document_serializer_key(format);
return metadata;
}
@@ -67,12 +152,30 @@ std::filesystem::path ifcopenshell::serializers::document_serializer_plugin_dire
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);
void ifcopenshell::serializers::load_document_serializer_plugins(document_serializer_registry& registry) {
ifcopenshell::plugin::manager manager;
add_document_serializer_search_paths(manager);
for (const auto& path : manager.discover(document_serializer_plugin_prefix())) {
ifcopenshell::plugin::module module;
try {
module = manager.load(path);
} catch (const std::exception& e) {
logger::error(e);
continue;
}
if (module.meta().kind_ != ifcopenshell::plugin::kind::document_serializer) {
continue;
}
auto register_plugin = module.get_alias<register_document_serializer_plugin_fn>(document_serializer_plugin_registration_symbol());
register_plugin(registry, module);
}
}
#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);
ifcopenshell::serializers::document_serializer_registry& ifcopenshell::serializers::document_serializer_registry_instance() {
static document_serializer_registry registry;
static std::once_flag once;
std::call_once(once, load_document_serializer_plugins, std::ref(registry));
return registry;
}
#endif
+50 -13
View File
@@ -20,30 +20,67 @@
#ifndef IFCOPENSHELL_DOCUMENT_SERIALIZER_PLUGIN_H
#define IFCOPENSHELL_DOCUMENT_SERIALIZER_PLUGIN_H
#include "XmlSerializer.h"
#include "../serializers/serializers_api.h"
#include "../ifcgeom/Serializer.h"
#include "../ifcparse/file.h"
#include "../plugin/plugin.h"
#ifdef WITH_GLTF
#include "JsonSerializer.h"
#endif
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <filesystem>
#include <map>
#include <string>
#include <vector>
namespace ifcopenshell {
namespace serializers {
typedef void register_xml_document_serializer_plugin_fn(XmlSerializerFactory::Factory&, const ifcopenshell::plugin::module&);
struct SERIALIZERS_API document_serializer_info {
std::string format;
std::string schema_name;
bool supports_ifc_file = true;
bool supports_input_filename = false;
bool writes_final_output = false;
};
struct SERIALIZERS_API document_serializer_context {
ifcopenshell::file* file = nullptr;
std::string input_filename;
std::string output_filename;
std::string schema_name;
bool stream = false;
int dialect = 0;
};
class SERIALIZERS_API document_serializer_registry {
public:
typedef boost::function<boost::shared_ptr<Serializer>(const document_serializer_context&)> create_fn;
void bind(const document_serializer_info& info, create_fn create, const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
const document_serializer_info* find(const std::string& format, const std::string& schema_name = std::string()) const;
boost::shared_ptr<Serializer> create(const std::string& format, const document_serializer_context& context) const;
std::vector<document_serializer_info> serializers() const;
private:
struct entry {
document_serializer_info info_;
create_fn create_;
ifcopenshell::plugin::module module_;
};
const entry* find_entry_(const std::string& format, const std::string& schema_name) const;
std::map<std::string, std::vector<entry>> entries_;
};
typedef void register_document_serializer_plugin_fn(document_serializer_registry&, 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 ifcopenshell::plugin::metadata document_serializer_plugin_metadata(const std::string& format, const std::string& schema_name = std::string());
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
SERIALIZERS_API void load_document_serializer_plugins(document_serializer_registry& registry);
SERIALIZERS_API document_serializer_registry& document_serializer_registry_instance();
}
}
+62
View File
@@ -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/>. *
* *
********************************************************************************/
#ifdef WITH_OPENCOLLADA
#include "ColladaSerializer.h"
#include "geometry_serializer_plugin.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_dae_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("dae");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<ColladaSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "dae";
info.extensions = { ".dae" };
info.supports_triangulation = true;
info.supports_user_element_hierarchy = true;
info.requires_ascii_temp_file = true;
registry.bind(info, create_serializer, geometry_serializer_registry::configure_fn(), module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_dae_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_dae_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_dae_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
+61
View File
@@ -0,0 +1,61 @@
/********************************************************************************
* *
* 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 "geometry_serializer_plugin.h"
#include "GltfSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_glb_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("glb");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<GltfSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "glb";
info.extensions = { ".glb" };
info.supports_triangulation = true;
info.supports_user_element_hierarchy = true;
registry.bind(info, create_serializer, geometry_serializer_registry::configure_fn(), module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_glb_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_glb_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_glb_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
+66
View File
@@ -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/>. *
* *
********************************************************************************/
#if defined(WITH_HDF5) && defined(IFOPSH_WITH_OPENCASCADE)
#include "geometry_serializer_plugin.h"
#include "HdfSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_hdf_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("hdf");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<HdfSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void configure_serializer(geometry_serializer_context& context) {
context.geometry_settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "hdf";
info.extensions = { ".h5" };
info.kernel_ids = { "opencascade" };
info.supports_triangulation = true;
info.supports_brep = true;
registry.bind(info, create_serializer, configure_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_hdf_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_hdf_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_hdf_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
+76
View File
@@ -0,0 +1,76 @@
/********************************************************************************
* *
* 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 IFOPSH_WITH_OPENCASCADE
#include "geometry_serializer_plugin.h"
#include "IgesSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
#include <Standard_Version.hxx>
#if OCC_VERSION_HEX < 0x60900
#include <IGESControl_Controller.hxx>
#endif
namespace ifcopenshell {
namespace serializers {
namespace geometry_igs_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("igs");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
#if OCC_VERSION_HEX < 0x60900
IGESControl_Controller::Init();
#endif
return boost::make_shared<IgesSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void configure_serializer(geometry_serializer_context& context) {
context.geometry_settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = true;
context.geometry_settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "igs";
info.extensions = { ".igs" };
info.kernel_ids = { "opencascade" };
info.supports_brep = true;
info.requires_ascii_temp_file = true;
registry.bind(info, create_serializer, configure_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_igs_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_igs_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_igs_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
+74
View File
@@ -0,0 +1,74 @@
/********************************************************************************
* *
* 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 "geometry_serializer_plugin.h"
#include "WavefrontObjSerializer.h"
#include "../ifcparse/utils.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
#include <filesystem>
namespace {
std::string obj_mtl_filename(const std::string& output_filename) {
std::filesystem::path path(ifcopenshell::path::from_utf8(output_filename));
path.replace_extension(ifcopenshell::path::from_utf8(".mtl"));
return ifcopenshell::path::to_utf8(path.native());
}
}
namespace ifcopenshell {
namespace serializers {
namespace geometry_obj_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("obj");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<WaveFrontOBJSerializer>(context.output_temp_filename, obj_mtl_filename(context.output_filename), context.geometry_settings, context.serializer_settings);
}
void configure_serializer(geometry_serializer_context& context) {
context.geometry_settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = true;
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "obj";
info.extensions = { ".obj" };
info.supports_triangulation = true;
registry.bind(info, create_serializer, configure_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_obj_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_obj_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_obj_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
@@ -0,0 +1,160 @@
/********************************************************************************
* *
* 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 "geometry_serializer_plugin.h"
#include <boost/algorithm/string/case_conv.hpp>
#include <mutex>
#include <set>
namespace {
std::string geometry_serializer_plugin_prefix(const std::string& format = std::string()) {
const auto format_lower = boost::to_lower_copy(format);
return format_lower.empty() ? "geometry." : "geometry." + format_lower;
}
std::string geometry_serializer_key(const std::string& extension) {
if (extension.empty()) {
return extension;
}
auto key = boost::to_lower_copy(extension);
if (key.front() != '.') {
key.insert(key.begin(), '.');
}
return key;
}
void add_geometry_serializer_search_paths(ifcopenshell::plugin::manager& manager) {
const auto directory = ifcopenshell::serializers::geometry_serializer_plugin_directory();
manager.add_search_path(directory);
const auto sibling_directory = directory.parent_path().parent_path() / "serializers" / directory.filename();
if (sibling_directory != directory && std::filesystem::exists(sibling_directory)) {
manager.add_search_path(sibling_directory);
}
}
}
void ifcopenshell::serializers::geometry_serializer_registry::bind(const geometry_serializer_info& info, create_fn create, configure_fn configure, const plugin::module& module) {
entry entry;
entry.info_ = info;
entry.info_.format = boost::to_lower_copy(entry.info_.format);
entry.create_ = create;
entry.configure_ = configure;
entry.module_ = module.meta().id.empty() ? plugin::module(geometry_serializer_plugin_metadata(entry.info_.format)) : module;
if (entry.info_.extensions.empty() && !entry.info_.format.empty()) {
entry.info_.extensions.push_back("." + entry.info_.format);
}
for (auto& extension : entry.info_.extensions) {
extension = geometry_serializer_key(extension);
entries_[extension] = entry;
}
}
bool ifcopenshell::serializers::geometry_serializer_registry::has(const std::string& extension) const {
return entries_.find(geometry_serializer_key(extension)) != entries_.end();
}
const ifcopenshell::serializers::geometry_serializer_info* ifcopenshell::serializers::geometry_serializer_registry::find(const std::string& extension) const {
const auto iter = entries_.find(geometry_serializer_key(extension));
if (iter == entries_.end()) {
return nullptr;
}
return &iter->second.info_;
}
void ifcopenshell::serializers::geometry_serializer_registry::configure(const std::string& extension, geometry_serializer_context& context) const {
const auto iter = entries_.find(geometry_serializer_key(extension));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry serializer registered for " + extension);
}
if (iter->second.configure_) {
iter->second.configure_(context);
}
}
boost::shared_ptr<GeometrySerializer> ifcopenshell::serializers::geometry_serializer_registry::create(const std::string& extension, const geometry_serializer_context& context) const {
const auto iter = entries_.find(geometry_serializer_key(extension));
if (iter == entries_.end()) {
throw ifcopenshell::exception("No geometry serializer registered for " + extension);
}
return iter->second.create_(context);
}
std::vector<ifcopenshell::serializers::geometry_serializer_info> ifcopenshell::serializers::geometry_serializer_registry::serializers() const {
std::vector<geometry_serializer_info> result;
std::set<std::string> seen_formats;
for (const auto& pair : entries_) {
if (!seen_formats.insert(pair.second.info_.format).second) {
continue;
}
result.push_back(pair.second.info_);
}
return result;
}
const char* ifcopenshell::serializers::geometry_serializer_plugin_registration_symbol() {
return "ifcopenshell_register_geometry_serializer_plugin_v1";
}
ifcopenshell::plugin::metadata ifcopenshell::serializers::geometry_serializer_plugin_metadata(const std::string& format) {
plugin::metadata metadata;
metadata.kind_ = plugin::kind::geometry_serializer;
metadata.id = geometry_serializer_plugin_prefix(format);
metadata.format = boost::to_lower_copy(format);
return metadata;
}
std::filesystem::path ifcopenshell::serializers::geometry_serializer_plugin_directory() {
return plugin::module_directory(reinterpret_cast<const void*>(&ifcopenshell::serializers::geometry_serializer_plugin_directory));
}
void ifcopenshell::serializers::load_geometry_serializer_plugins(geometry_serializer_registry& registry) {
ifcopenshell::plugin::manager manager;
add_geometry_serializer_search_paths(manager);
for (const auto& path : manager.discover(geometry_serializer_plugin_prefix())) {
ifcopenshell::plugin::module module;
try {
module = manager.load(path);
} catch (const std::exception& e) {
logger::error(e);
continue;
}
if (module.meta().kind_ != ifcopenshell::plugin::kind::geometry_serializer) {
continue;
}
auto register_plugin = module.get_alias<register_geometry_serializer_plugin_fn>(geometry_serializer_plugin_registration_symbol());
register_plugin(registry, module);
}
}
ifcopenshell::serializers::geometry_serializer_registry& ifcopenshell::serializers::geometry_serializer_registry_instance() {
static geometry_serializer_registry registry;
static std::once_flag once;
std::call_once(once, load_geometry_serializer_plugins, std::ref(registry));
return registry;
}
@@ -0,0 +1,91 @@
/********************************************************************************
* *
* 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_GEOMETRY_SERIALIZER_PLUGIN_H
#define IFCOPENSHELL_GEOMETRY_SERIALIZER_PLUGIN_H
#include "../serializers/serializers_api.h"
#include "../ifcgeom/GeometrySerializer.h"
#include "../plugin/plugin.h"
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <filesystem>
#include <map>
#include <string>
#include <vector>
namespace ifcopenshell {
namespace serializers {
struct SERIALIZERS_API geometry_serializer_info {
std::string format;
std::vector<std::string> extensions;
std::vector<std::string> kernel_ids;
bool supports_triangulation = false;
bool supports_brep = false;
bool supports_user_element_hierarchy = false;
bool bypass_properties = true;
bool requires_ascii_temp_file = false;
bool writes_final_output = false;
};
struct SERIALIZERS_API geometry_serializer_context {
std::string output_filename;
std::string output_temp_filename;
ifcopenshell::geometry::Settings& geometry_settings;
const ifcopenshell::geometry::SerializerSettings& serializer_settings;
};
class SERIALIZERS_API geometry_serializer_registry {
public:
typedef boost::function<boost::shared_ptr<GeometrySerializer>(const geometry_serializer_context&)> create_fn;
typedef boost::function<void(geometry_serializer_context&)> configure_fn;
void bind(const geometry_serializer_info& info, create_fn create, configure_fn configure = configure_fn(), const ifcopenshell::plugin::module& module = ifcopenshell::plugin::module());
bool has(const std::string& extension) const;
const geometry_serializer_info* find(const std::string& extension) const;
void configure(const std::string& extension, geometry_serializer_context& context) const;
boost::shared_ptr<GeometrySerializer> create(const std::string& extension, const geometry_serializer_context& context) const;
std::vector<geometry_serializer_info> serializers() const;
private:
struct entry {
geometry_serializer_info info_;
create_fn create_;
configure_fn configure_;
ifcopenshell::plugin::module module_;
};
std::map<std::string, entry> entries_;
};
typedef void register_geometry_serializer_plugin_fn(geometry_serializer_registry&, const ifcopenshell::plugin::module&);
SERIALIZERS_API const char* geometry_serializer_plugin_registration_symbol();
SERIALIZERS_API ifcopenshell::plugin::metadata geometry_serializer_plugin_metadata(const std::string& format);
SERIALIZERS_API std::filesystem::path geometry_serializer_plugin_directory();
SERIALIZERS_API void load_geometry_serializer_plugins(geometry_serializer_registry& registry);
SERIALIZERS_API geometry_serializer_registry& geometry_serializer_registry_instance();
}
}
#endif
+67
View File
@@ -0,0 +1,67 @@
/********************************************************************************
* *
* 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 IFOPSH_WITH_OPENCASCADE
#include "geometry_serializer_plugin.h"
#include "StepSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_stp_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("stp");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<StepSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void configure_serializer(geometry_serializer_context& context) {
context.geometry_settings.get<ifcopenshell::geometry::settings::UseWorldCoords>().value = true;
context.geometry_settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "stp";
info.extensions = { ".stp" };
info.kernel_ids = { "opencascade" };
info.supports_brep = true;
info.requires_ascii_temp_file = true;
registry.bind(info, create_serializer, configure_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_stp_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_stp_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_stp_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
+67
View File
@@ -0,0 +1,67 @@
/********************************************************************************
* *
* 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 IFOPSH_WITH_OPENCASCADE
#include "geometry_serializer_plugin.h"
#include "SvgSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_svg_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("svg");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<SvgSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void configure_serializer(geometry_serializer_context& context) {
context.geometry_settings.get<ifcopenshell::geometry::settings::UseElementHierarchy>().value = true;
context.geometry_settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "svg";
info.extensions = { ".svg" };
info.kernel_ids = { "opencascade" };
info.supports_brep = true;
info.bypass_properties = false;
registry.bind(info, create_serializer, configure_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_svg_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_svg_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_svg_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
+64
View File
@@ -0,0 +1,64 @@
/********************************************************************************
* *
* 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 "geometry_serializer_plugin.h"
#include "TtlWktSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_ttl_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("ttl");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<TtlWktSerializer>(context.output_temp_filename, context.geometry_settings, context.serializer_settings);
}
void configure_serializer(geometry_serializer_context& context) {
context.geometry_settings.get<ifcopenshell::geometry::settings::TriangulationType>().value = ifcopenshell::geometry::settings::POLYHEDRON_WITH_HOLES;
if (context.serializer_settings.get<ifcopenshell::geometry::settings::WktUseSection>().get()) {
context.geometry_settings.get<ifcopenshell::geometry::settings::IteratorOutput>().value = ifcopenshell::geometry::settings::NATIVE;
}
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "ttl";
info.extensions = { ".ttl" };
info.supports_triangulation = true;
info.supports_brep = true;
registry.bind(info, create_serializer, configure_serializer, module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_ttl_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_ttl_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_ttl_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
+62
View File
@@ -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/>. *
* *
********************************************************************************/
#ifdef WITH_USD
#include "geometry_serializer_plugin.h"
#include "USDSerializer.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.hpp>
namespace ifcopenshell {
namespace serializers {
namespace geometry_usd_plugin {
plugin::abi_info plugin_abi() {
return plugin::host_abi();
}
plugin::metadata plugin_metadata() {
return geometry_serializer_plugin_metadata("usd");
}
boost::shared_ptr<GeometrySerializer> create_serializer(const geometry_serializer_context& context) {
return boost::make_shared<USDSerializer>(context.output_filename, context.geometry_settings, context.serializer_settings);
}
void register_plugin(geometry_serializer_registry& registry, const plugin::module& module) {
geometry_serializer_info info;
info.format = "usd";
info.extensions = { ".usd", ".usda", ".usdc" };
info.supports_triangulation = true;
info.supports_user_element_hierarchy = true;
info.writes_final_output = true;
registry.bind(info, create_serializer, geometry_serializer_registry::configure_fn(), module);
}
}
}
}
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_usd_plugin::plugin_abi, ifcopenshell_plugin_abi_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_usd_plugin::plugin_metadata, ifcopenshell_plugin_metadata_v1)
BOOST_DLL_ALIAS(ifcopenshell::serializers::geometry_usd_plugin::register_plugin, ifcopenshell_register_geometry_serializer_plugin_v1)
#endif
@@ -1,26 +1,10 @@
set(document_serializer_plugin_runtime_dir "${CMAKE_BINARY_DIR}/serializers/$<CONFIG>")
foreach(schema ${SCHEMA_VERSIONS})
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})
add_document_serializer_plugin(document_serializer_xml_ifc${schema} "document.xml.ifc${schema}" SOURCES XmlSerializer.cpp xml_plugin.cpp)
target_compile_definitions(document_serializer_xml_ifc${schema} PRIVATE IfcSchema=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})
if(GLTF_SUPPORT)
add_document_serializer_plugin(document_serializer_json_ifc${schema} "document.json.ifc${schema}" SOURCES JsonSerializer.cpp json_plugin.cpp)
target_compile_definitions(document_serializer_json_ifc${schema} PRIVATE IfcSchema=Ifc${schema})
endif()
endforeach()
@@ -25,16 +25,16 @@
#include "../../ifcparse/macros.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.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;
}
};
boost::shared_ptr<Serializer> create_serializer(const ifcopenshell::serializers::document_serializer_context& context) {
return boost::make_shared<POSTFIX_SCHEMA(JsonSerializer)>(
context.file,
context.output_filename,
static_cast<JsonSerializer::Dialect>(context.dialect));
}
}
@@ -50,9 +50,11 @@ 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);
void register_plugin(document_serializer_registry& registry, const plugin::module& module) {
document_serializer_info info;
info.format = "json";
info.schema_name = STRINGIFY(IfcSchema);
registry.bind(info, create_serializer, module);
}
}
@@ -23,16 +23,13 @@
#include "../../ifcparse/macros.h"
#include <boost/dll/alias.hpp>
#include <boost/make_shared.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;
}
};
boost::shared_ptr<Serializer> create_serializer(const ifcopenshell::serializers::document_serializer_context& context) {
return boost::make_shared<POSTFIX_SCHEMA(XmlSerializer)>(context.file, context.output_filename);
}
}
@@ -48,9 +45,11 @@ 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);
void register_plugin(document_serializer_registry& registry, const plugin::module& module) {
document_serializer_info info;
info.format = "xml";
info.schema_name = STRINGIFY(IfcSchema);
registry.bind(info, create_serializer, module);
}
}