2023-03-21 20:15:01 +01:00
|
|
|
#include "../ifcgeom/IfcGeomElement.h"
|
2023-03-22 11:17:14 +01:00
|
|
|
#include "../ifcgeom/ConversionSettings.h"
|
2024-04-29 21:03:33 +02:00
|
|
|
#include "../ifcgeom/abstract_mapping.h"
|
2025-01-02 11:10:56 -08:00
|
|
|
#include "../ifcgeom/function_item_evaluator.h"
|
2023-03-21 20:15:01 +01:00
|
|
|
|
2025-09-26 14:24:49 +02:00
|
|
|
#include "AbstractKernel.h"
|
2023-03-21 20:15:01 +01:00
|
|
|
|
2023-03-22 11:17:14 +01:00
|
|
|
using namespace ifcopenshell::geometry;
|
|
|
|
|
|
2025-10-03 14:00:20 +00:00
|
|
|
const char* ifcopenshell::not_implemented_error::what() const noexcept {
|
|
|
|
|
return "Not implemented.";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* ifcopenshell::not_supported_error::what() const noexcept {
|
|
|
|
|
return "Not supported.";
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 16:42:06 +08:00
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::ptr item, IfcGeom::ConversionResults& results) {
|
2025-05-18 22:14:22 +02:00
|
|
|
if (settings_.get<settings::CacheShapes>().get()) {
|
|
|
|
|
auto it = cache_.find(item);
|
|
|
|
|
if (it != cache_.end()) {
|
|
|
|
|
results = it->second;
|
2026-06-10 18:30:54 +02:00
|
|
|
logger_.Notice("SYS", 25, "Cache hit #" + std::to_string(item->instance->as<IfcUtil::IfcBaseEntity>()->id()) +
|
2025-05-18 22:14:22 +02:00
|
|
|
" -> #" + std::to_string(it->first->instance->as<IfcUtil::IfcBaseEntity>()->id()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-09 13:14:49 +02:00
|
|
|
auto with_exception_handling = [&](auto fn) {
|
2024-09-11 11:56:21 +05:00
|
|
|
try {
|
2024-10-09 13:14:49 +02:00
|
|
|
return fn();
|
2024-09-11 11:56:21 +05:00
|
|
|
} catch (std::exception& e) {
|
2026-06-10 18:30:54 +02:00
|
|
|
logger_.Error("GEO", 27, e, item->instance);
|
2024-09-11 11:56:21 +05:00
|
|
|
return false;
|
|
|
|
|
} catch (...) {
|
2024-10-09 13:14:49 +02:00
|
|
|
// @todo we can't log OCCT exceptions here, can we do some reraising to solve this?
|
2024-09-11 11:56:21 +05:00
|
|
|
return false;
|
|
|
|
|
}
|
2024-10-09 13:14:49 +02:00
|
|
|
};
|
|
|
|
|
auto without_exception_handling = [](auto fn) {
|
|
|
|
|
return fn();
|
|
|
|
|
};
|
|
|
|
|
auto process_with_upgrade = [&]() {
|
|
|
|
|
try {
|
|
|
|
|
return dispatch_conversion<0>::dispatch(this, item->kind(), item, results);
|
|
|
|
|
} catch (const not_implemented_error&) {
|
|
|
|
|
return dispatch_with_upgrade<0>::dispatch(this, item, results);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-05-18 22:14:22 +02:00
|
|
|
bool res;
|
2024-10-09 13:14:49 +02:00
|
|
|
if (propagate_exceptions) {
|
2025-05-18 22:14:22 +02:00
|
|
|
res = without_exception_handling(process_with_upgrade);
|
2024-10-09 13:14:49 +02:00
|
|
|
} else {
|
2025-05-18 22:14:22 +02:00
|
|
|
res = with_exception_handling(process_with_upgrade);
|
2023-03-21 20:15:01 +01:00
|
|
|
}
|
2025-05-18 22:14:22 +02:00
|
|
|
|
|
|
|
|
if (settings_.get<settings::CacheShapes>().get() && res) {
|
|
|
|
|
cache_.insert({ item, results });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
2023-03-21 20:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
2023-11-15 10:32:20 +01:00
|
|
|
const Settings& ifcopenshell::geometry::kernels::AbstractKernel::settings() const
|
2023-03-21 20:15:01 +01:00
|
|
|
{
|
2023-11-15 10:32:20 +01:00
|
|
|
return settings_;
|
2023-03-21 20:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
2026-07-21 23:07:13 +03:00
|
|
|
namespace {
|
|
|
|
|
// Homogeneous taxonomy::point3 collections (e.g. IfcCartesianPointList3D)
|
|
|
|
|
// are reduced to a single result, see #134/#1409/#5218.
|
|
|
|
|
bool is_reducible_point_collection(const ifcopenshell::geometry::taxonomy::collection::ptr& collection) {
|
|
|
|
|
if (collection->children.empty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (auto& c : collection->children) {
|
|
|
|
|
if (c->kind() != ifcopenshell::geometry::taxonomy::POINT3) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-27 16:42:06 +08:00
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::collection::ptr collection, IfcGeom::ConversionResults& r) {
|
2026-07-21 23:07:13 +03:00
|
|
|
if (collection->instance && is_reducible_point_collection(collection)) {
|
|
|
|
|
// Reduce via the generic wrap_in_compound()/concat_many() API rather
|
|
|
|
|
// than a per-kernel convert_impl(collection) override. concat_many()
|
|
|
|
|
// combines everything in a single bulk call so kernels can implement
|
|
|
|
|
// it in O(n): a loop calling concat() pairwise would either
|
|
|
|
|
// re-classify an ever-growing accumulator (quadratic) or produce an
|
|
|
|
|
// O(n)-deep nested shape (quadratic to traverse later).
|
|
|
|
|
// Kept alive until concat_many() below: shapes[] holds raw pointers
|
|
|
|
|
// into these ConversionResults' shared_ptr<ConversionResultShape>.
|
|
|
|
|
IfcGeom::ConversionResults child_results;
|
|
|
|
|
for (auto& c : collection->children) {
|
|
|
|
|
if (!convert(c, child_results) && !partial_success_is_success) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (child_results.empty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<IfcGeom::ConversionResultShape*> shapes;
|
|
|
|
|
shapes.reserve(child_results.size());
|
|
|
|
|
for (auto& t : child_results) {
|
|
|
|
|
shapes.push_back(t.Shape().get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto* first = shapes.front();
|
|
|
|
|
std::vector<IfcGeom::ConversionResultShape*> rest(shapes.begin() + 1, shapes.end());
|
|
|
|
|
auto* accum = first->concat_many(rest);
|
|
|
|
|
|
|
|
|
|
r.emplace_back(IfcGeom::ConversionResult(collection->instance->as<IfcUtil::IfcBaseEntity>()->id(), accum, collection->surface_style));
|
|
|
|
|
if (collection->matrix) {
|
|
|
|
|
r.back().prepend(collection->matrix);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 20:15:01 +01:00
|
|
|
auto s = r.size();
|
|
|
|
|
for (auto& c : collection->children) {
|
2025-04-30 14:53:53 +02:00
|
|
|
if (!convert(c, r) && !partial_success_is_success) {
|
2025-04-29 22:03:18 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2023-03-21 20:15:01 +01:00
|
|
|
}
|
|
|
|
|
for (auto i = s; i < r.size(); ++i) {
|
2023-07-27 16:42:06 +08:00
|
|
|
if (collection->matrix) {
|
|
|
|
|
r[i].prepend(collection->matrix);
|
|
|
|
|
}
|
2023-03-21 20:15:01 +01:00
|
|
|
if (!r[i].hasStyle() && collection->surface_style) {
|
2023-07-27 16:42:06 +08:00
|
|
|
r[i].setStyle(collection->surface_style);
|
2023-03-21 20:15:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return r.size() > s;
|
|
|
|
|
}
|
2023-10-14 16:37:50 +02:00
|
|
|
|
2025-01-02 11:10:56 -08:00
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::function_item::ptr item, IfcGeom::ConversionResults& cs) {
|
|
|
|
|
function_item_evaluator evaluator(settings(),item);
|
2024-09-10 10:11:17 -07:00
|
|
|
auto expl = evaluator.evaluate();
|
2023-10-14 16:37:50 +02:00
|
|
|
expl->instance = item->instance;
|
|
|
|
|
return convert(expl, cs);
|
|
|
|
|
}
|
2025-01-02 11:10:56 -08:00
|
|
|
|
|
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::functor_item::ptr item, IfcGeom::ConversionResults& cs) {
|
|
|
|
|
function_item_evaluator evaluator(settings(), item);
|
|
|
|
|
auto expl = evaluator.evaluate();
|
|
|
|
|
expl->instance = item->instance;
|
|
|
|
|
return convert(expl, cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::piecewise_function::ptr item, IfcGeom::ConversionResults& cs) {
|
|
|
|
|
function_item_evaluator evaluator(settings(), item);
|
|
|
|
|
auto expl = evaluator.evaluate();
|
|
|
|
|
expl->instance = item->instance;
|
|
|
|
|
return convert(expl, cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::gradient_function::ptr item, IfcGeom::ConversionResults& cs) {
|
|
|
|
|
function_item_evaluator evaluator(settings(), item);
|
|
|
|
|
auto expl = evaluator.evaluate();
|
|
|
|
|
expl->instance = item->instance;
|
|
|
|
|
return convert(expl, cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::cant_function::ptr item, IfcGeom::ConversionResults& cs) {
|
|
|
|
|
function_item_evaluator evaluator(settings(), item);
|
|
|
|
|
auto expl = evaluator.evaluate();
|
|
|
|
|
expl->instance = item->instance;
|
|
|
|
|
return convert(expl, cs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ifcopenshell::geometry::kernels::AbstractKernel::convert_impl(const taxonomy::offset_function::ptr item, IfcGeom::ConversionResults& cs) {
|
|
|
|
|
function_item_evaluator evaluator(settings(), item);
|
|
|
|
|
auto expl = evaluator.evaluate();
|
|
|
|
|
expl->instance = item->instance;
|
|
|
|
|
return convert(expl, cs);
|
|
|
|
|
}
|