diff --git a/src/svgfill/src/linework_processing_facade.cpp b/src/svgfill/src/linework_processing_facade.cpp new file mode 100644 index 0000000000..3893009495 --- /dev/null +++ b/src/svgfill/src/linework_processing_facade.cpp @@ -0,0 +1,167 @@ +/******************************************************************************** + * * + * 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 . * + * * + ********************************************************************************/ + +// This file was generated with the assistance of an AI coding tool. + +#include "linework_processing_plugin.h" + +#include "../../plugin/plugin.h" + +#include +#include +#include +#include + +namespace ifcopenshell { +namespace plugin { +PLUGIN_API std::filesystem::path add_search_paths_or_default(manager& manager, std::filesystem::path (*default_search_path)()); +} +} + +namespace { +struct provider_state { + svgfill::linework_processing_plugin::api api; + ifcopenshell::plugin::module module; +}; + +std::filesystem::path plugin_directory() { + return ifcopenshell::plugin::module_directory(reinterpret_cast(&svgfill::svg_to_line_segments)); +} + +void validate(const svgfill::linework_processing_plugin::api& api) { + if (!api.svg_to_line_segments || + !api.line_segments_to_polygons || + !api.line_segments_to_polygons_with_progress || + !api.polygons_to_svg_groups || + !api.polygons_to_svg || + !api.svg_to_polygons || + !api.arrange_polygons || + !api.create_arrangement || + !api.destroy_arrangement) { + throw std::runtime_error("Incomplete linework processing plugin API"); + } +} + +provider_state& provider() { + static provider_state state; + static std::once_flag once; + + std::call_once(once, [] { + ifcopenshell::plugin::manager manager; + ifcopenshell::plugin::add_search_paths_or_default(manager, &plugin_directory); + + for (const auto& path : manager.discover_exact(svgfill::linework_processing_plugin::id)) { + auto module = manager.load(path); + if (module.meta().kind_ != ifcopenshell::plugin::kind::linework_processing || + module.meta().id != svgfill::linework_processing_plugin::id) { + continue; + } + + auto register_plugin = module.get_alias( + svgfill::linework_processing_plugin::registration_symbol); + register_plugin(state.api); + validate(state.api); + state.module = std::move(module); + return; + } + + std::ostringstream stream; + stream << "Unable to load " << svgfill::linework_processing_plugin::id << " linework processing plugin"; + throw std::runtime_error(stream.str()); + }); + + return state; +} +} + +bool svgfill::svg_to_line_segments( + const std::string& data, + const std::optional& class_name, + std::vector>& segments) +{ + return provider().api.svg_to_line_segments(data, class_name, segments); +} + +bool svgfill::line_segments_to_polygons( + solver s, + double eps, + const std::vector>& segments, + std::vector>& polygons) +{ + return provider().api.line_segments_to_polygons(s, eps, segments, polygons); +} + +bool svgfill::line_segments_to_polygons( + solver s, + double eps, + const std::vector>& segments, + std::vector>& polygons, + std::function& progress) +{ + return provider().api.line_segments_to_polygons_with_progress(s, eps, segments, polygons, progress); +} + +std::string svgfill::polygons_to_svg(const std::vector>& polygons, bool random_color) { + return provider().api.polygons_to_svg_groups(polygons, random_color); +} + +std::string svgfill::polygons_to_svg(const std::vector& polygons, bool random_color) { + return provider().api.polygons_to_svg(polygons, random_color); +} + +bool svgfill::svg_to_polygons( + const std::string& data, + const std::optional& class_name, + std::vector& polygons) +{ + return provider().api.svg_to_polygons(data, class_name, polygons); +} + +bool svgfill::arrange_polygons( + arrange_polygon_settings settings, + const std::vector& polygons, + std::vector& arranged) +{ + return provider().api.arrange_polygons(settings, polygons, arranged); +} + +void svgfill::context::add(const std::vector& segments) { + segments_.insert(segments_.end(), segments.begin(), segments.end()); +} + +bool svgfill::context::build() { + arr_ = provider().api.create_arrangement(solver_); + return arr_ && (*arr_)(eps_, segments_, progress_); +} + +void svgfill::context::merge(const std::vector& edge_indices) { + arr_->merge(edge_indices); +} + +void svgfill::context::write(std::vector>& p) { + std::vector polygons; + arr_->write(polygons, progress_); + p.push_back(polygons); +} + +svgfill::context::~context() { + if (arr_) { + provider().api.destroy_arrangement(arr_); + } +} diff --git a/src/svgfill/src/linework_processing_plugin.h b/src/svgfill/src/linework_processing_plugin.h new file mode 100644 index 0000000000..864cc3d688 --- /dev/null +++ b/src/svgfill/src/linework_processing_plugin.h @@ -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 . * + * * + ********************************************************************************/ + +// This file was generated with the assistance of an AI coding tool. + +#ifndef IFCOPENSHELL_LINEWORK_PROCESSING_PLUGIN_H +#define IFCOPENSHELL_LINEWORK_PROCESSING_PLUGIN_H + +#include "svgfill.h" + +namespace svgfill { + +abstract_arrangement* create_arrangement(solver s); +void destroy_arrangement(abstract_arrangement* arrangement); + +namespace linework_processing_plugin { + +constexpr const char* id = "geometry.svgfill"; +constexpr const char* registration_symbol = "ifcopenshell_register_linework_processing_plugin_v1"; + +struct api { + bool (*svg_to_line_segments)( + const std::string&, + const std::optional&, + std::vector>&) = nullptr; + bool (*line_segments_to_polygons)( + solver, + double, + const std::vector>&, + std::vector>&) = nullptr; + bool (*line_segments_to_polygons_with_progress)( + solver, + double, + const std::vector>&, + std::vector>&, + std::function&) = nullptr; + std::string (*polygons_to_svg_groups)(const std::vector>&, bool) = nullptr; + std::string (*polygons_to_svg)(const std::vector&, bool) = nullptr; + bool (*svg_to_polygons)( + const std::string&, + const std::optional&, + std::vector&) = nullptr; + bool (*arrange_polygons)(arrange_polygon_settings, const std::vector&, std::vector&) = nullptr; + abstract_arrangement* (*create_arrangement)(solver) = nullptr; + void (*destroy_arrangement)(abstract_arrangement*) = nullptr; +}; + +using register_linework_processing_plugin_fn = void(api&); + +} +} + +#endif