/******************************************************************************** * * * 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 . * * * ********************************************************************************/ #ifndef ABSTRACT_KERNEL_H #define ABSTRACT_KERNEL_H #include "../ifcparse/macros.h" #include "../ifcparse/logger.h" #include "../ifcgeom/ifc_geom_api.h" #include "../ifcgeom/IfcGeomRepresentation.h" #include "../ifcgeom/taxonomy.h" #include "../ifcgeom/ConversionSettings.h" #include "../ifcgeom/abstract_mapping.h" #include static const double ALMOST_ZERO = 1.e-9; template inline static bool ALMOST_THE_SAME(const T& a, const T& b, double tolerance = ALMOST_ZERO) { return fabs(a - b) < tolerance; } namespace ifcopenshell { #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4275) #endif class IFC_GEOM_API not_implemented_error : public std::exception { public: const char* what() const noexcept override; }; class IFC_GEOM_API not_supported_error : public std::exception { public: const char* what() const noexcept override; }; #if defined(_MSC_VER) #pragma warning(pop) #endif namespace geom { namespace kernels { class IFC_GEOM_API abstract_kernel { private: std::unordered_map cache_; protected: std::string geometry_library_; ifcopenshell::geom::settings settings_; ::logger& logger_; public: bool propagate_exceptions = false; bool partial_success_is_success = true; abstract_kernel(const std::string& geometry_library, const ifcopenshell::geom::settings& settings, ::logger& logger = ::logger::root()) : geometry_library_(geometry_library) , settings_(settings) , logger_(logger) {} virtual ~abstract_kernel() = default; virtual bool convert(const taxonomy::ptr, ifcopenshell::geom::conversion_results&); const ifcopenshell::geom::settings& settings() const; const std::string& geometry_library() const { return geometry_library_; } virtual std::string_view backend_id() const { return geometry_library_; } virtual bool accepts(const ifcopenshell::geom::conversion_result_shape& shape) const { return shape.backend_id() == backend_id(); } ::logger& logger() const { return logger_; } virtual bool supports_boolean_operations() const = 0; virtual bool convert_impl(const taxonomy::matrix4::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::point3::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::direction3::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::line::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::circle::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::ellipse::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::bspline_curve::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::edge::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::loop::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::shell::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::face::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::extrusion::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::node::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::colour::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::boolean_result::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::plane::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::offset_curve::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::revolve::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::bspline_surface::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::cylinder::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::sphere::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::torus::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::solid::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::sweep_along_curve::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::loft::ptr, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual bool convert_impl(const taxonomy::collection::ptr, ifcopenshell::geom::conversion_results&); virtual bool convert_impl(const taxonomy::function_item::ptr item, ifcopenshell::geom::conversion_results& cs); virtual bool convert_impl(const taxonomy::functor_item::ptr item, ifcopenshell::geom::conversion_results& cs); virtual bool convert_impl(const taxonomy::piecewise_function::ptr item, ifcopenshell::geom::conversion_results& cs); virtual bool convert_impl(const taxonomy::gradient_function::ptr item, ifcopenshell::geom::conversion_results& cs); virtual bool convert_impl(const taxonomy::cant_function::ptr item, ifcopenshell::geom::conversion_results& cs); virtual bool convert_impl(const taxonomy::offset_function::ptr item, ifcopenshell::geom::conversion_results& cs); /* virtual void set_offset(const std::array &p_offset); virtual void set_rotation(const std::array &p_rotation); */ virtual bool apply_layerset(ifcopenshell::geom::conversion_results&, const ifcopenshell::geom::layerset_information&) { throw not_implemented_error(); } virtual bool apply_folded_layerset(ifcopenshell::geom::conversion_results&, const ifcopenshell::geom::layerset_information&, const std::map&) { throw not_implemented_error(); } virtual bool convert_openings(const express::base& entity, const std::vector>& openings, const ifcopenshell::geom::conversion_results& entity_shapes, const ifcopenshell::geom::taxonomy::matrix4& entity_trsf, ifcopenshell::geom::conversion_results& cut_shapes) = 0; virtual bool unify_shapes(const ifcopenshell::geom::conversion_results&, ifcopenshell::geom::conversion_results&) { throw not_implemented_error(); } virtual abstract_kernel* clone(::logger& logger) const = 0; }; } } } namespace { /* A compile-time for loop over the taxonomy kinds */ template struct dispatch_conversion { static bool dispatch(ifcopenshell::geom::kernels::abstract_kernel* kernel, ifcopenshell::geom::taxonomy::kinds item_kind, const ifcopenshell::geom::taxonomy::ptr& item, ifcopenshell::geom::conversion_results& results) { if (N == item_kind) { auto concrete_item = std::static_pointer_cast>(item); return kernel->convert_impl(concrete_item, results); } else { return dispatch_conversion::dispatch(kernel, item_kind, item, results); } } }; template <> struct dispatch_conversion { static bool dispatch(ifcopenshell::geom::kernels::abstract_kernel* kernel, ifcopenshell::geom::taxonomy::kinds, const ifcopenshell::geom::taxonomy::ptr& item, ifcopenshell::geom::conversion_results&) { if (kernel->partial_success_is_success) { std::string created_from; if (item->instance) { created_from = " (created from " + item->instance.declaration().name() + ")"; } kernel->logger().error("UNS", 1, "No support for " + ifcopenshell::geom::taxonomy::kind_to_string(item->kind()) + created_from + " in kernel " + kernel->geometry_library()); } return false; } }; template struct dispatch_with_upgrade { static bool dispatch(ifcopenshell::geom::kernels::abstract_kernel* kernel, const ifcopenshell::geom::taxonomy::ptr& item, ifcopenshell::geom::conversion_results& results) { auto concrete_item = ifcopenshell::geom::taxonomy::template dcast>(item); if (concrete_item) { return kernel->convert_impl(concrete_item, results); } else { return dispatch_with_upgrade::dispatch(kernel, item, results); } } }; template <> struct dispatch_with_upgrade { static bool dispatch(ifcopenshell::geom::kernels::abstract_kernel* kernel, const ifcopenshell::geom::taxonomy::ptr& item, ifcopenshell::geom::conversion_results&) { if (kernel->partial_success_is_success) { std::string created_from; if (item->instance) { created_from = " (created from " + item->instance.declaration().name() + ")"; } kernel->logger().error("UNS", 2, "No support (after considering item upgrade) for " + ifcopenshell::geom::taxonomy::kind_to_string(item->kind()) + created_from + " in kernel " + kernel->geometry_library()); } return false; } }; template struct tuple_type_index; template struct tuple_type_index> { static const std::size_t value = 0; }; template struct tuple_type_index> { static const std::size_t value = 1 + tuple_type_index>::value; }; /* A compile-time for loop over the curve kinds */ template struct dispatch_curve_creation { static bool dispatch(const ifcopenshell::geom::taxonomy::ptr& item, T& visitor) { constexpr auto KindIndex = tuple_type_index, ifcopenshell::geom::taxonomy::impl::kinds_tuple>::value; if (item->kind() == KindIndex) { auto concrete_item = std::static_pointer_cast>(item); visitor(concrete_item); return true; } else { return dispatch_curve_creation::dispatch(item, visitor); } } }; template struct dispatch_curve_creation { static bool dispatch(const ifcopenshell::geom::taxonomy::ptr& item, T&) { ::logger::root().error("GEO", 28, "No conversion for " + std::to_string(item->kind())); return false; } }; /* A compile-time for loop over the curve kinds */ template struct dispatch_surface_creation { static bool dispatch(const ifcopenshell::geom::taxonomy::ptr& item, T& visitor) { auto v = ifcopenshell::geom::taxonomy::template dcast>(item); if (v && item->kind() == v->kind()) { visitor(v); return true; } else { return dispatch_surface_creation::dispatch(item, visitor); } } }; template struct dispatch_surface_creation { static bool dispatch(const ifcopenshell::geom::taxonomy::ptr& item, T&) { ::logger::root().error("GEO", 29, "No conversion for " + std::to_string(item->kind())); return false; } }; } #endif