From 6cf987547272b405372c56290f4edf87f0ebc8cc Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 10 Sep 2024 12:15:43 +0500 Subject: [PATCH 01/12] Fix error processing IfcCircle/IfcEllipse #5352 --- src/ifcgeom/mapping/IfcCircle.cpp | 8 +++- src/ifcgeom/mapping/IfcEllipse.cpp | 7 +++- .../test/geom/geometry_tests.py | 42 +++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 src/ifcopenshell-python/test/geom/geometry_tests.py diff --git a/src/ifcgeom/mapping/IfcCircle.cpp b/src/ifcgeom/mapping/IfcCircle.cpp index 6693cd18ca..82a822e34c 100644 --- a/src/ifcgeom/mapping/IfcCircle.cpp +++ b/src/ifcgeom/mapping/IfcCircle.cpp @@ -34,5 +34,11 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCircle* inst) { auto c = taxonomy::make(); c->radius = r; c->matrix = taxonomy::cast(map(placement)); - return c; + + auto e = taxonomy::make(); + e->basis = c; + e->start = 0.; + e->end = 2 * boost::math::constants::pi(); + + return e; } diff --git a/src/ifcgeom/mapping/IfcEllipse.cpp b/src/ifcgeom/mapping/IfcEllipse.cpp index 1d1e70e303..dfde1c2128 100644 --- a/src/ifcgeom/mapping/IfcEllipse.cpp +++ b/src/ifcgeom/mapping/IfcEllipse.cpp @@ -51,5 +51,10 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcEllipse* inst) { el->radius = x; el->radius2 = y; - return el; + auto e = taxonomy::make(); + e->basis = el; + e->start = 0.; + e->end = 2 * boost::math::constants::pi(); + + return e; } diff --git a/src/ifcopenshell-python/test/geom/geometry_tests.py b/src/ifcopenshell-python/test/geom/geometry_tests.py new file mode 100644 index 0000000000..1ecfa35b4b --- /dev/null +++ b/src/ifcopenshell-python/test/geom/geometry_tests.py @@ -0,0 +1,42 @@ +# IfcOpenShell - IFC toolkit and geometry engine +# Copyright (C) 2021 Dion Moult +# +# This file is part of IfcOpenShell. +# +# IfcOpenShell is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 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 +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with IfcOpenShell. If not, see . + +import ifcopenshell +import ifcopenshell.geom +import test.bootstrap +from ifcopenshell.util.shape_builder import ShapeBuilder, V + + +class TestCreatingShapes(test.bootstrap.IFC4): + def test_create_IfcCirle(self): + builder = ShapeBuilder(self.file) + item = builder.circle(radius=1.0) + settings = ifcopenshell.geom.settings() + shape = ifcopenshell.geom.create_shape(settings, item) + assert shape.verts + + def test_create_IfcEllipse(self): + ifc_position = self.file.create_entity( + "IfcAxis2Placement2D", + self.file.create_entity("IfcCartesianPoint", V(0, 0)), + RefDirection=self.file.create_entity("IfcDirection", V(1, 0)), + ) + item = self.file.create_entity("IfcEllipse", Position=ifc_position, SemiAxis1=1.0, SemiAxis2=0.5) + settings = ifcopenshell.geom.settings() + shape = ifcopenshell.geom.create_shape(settings, item) + assert shape.verts From 11f017e715efea05628aad9cb51a5f9834f4f874 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Tue, 10 Sep 2024 18:26:14 +0500 Subject: [PATCH 02/12] revert manual upgrade to edges for ellipses and circles --- src/ifcgeom/mapping/IfcCircle.cpp | 7 +------ src/ifcgeom/mapping/IfcEllipse.cpp | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/src/ifcgeom/mapping/IfcCircle.cpp b/src/ifcgeom/mapping/IfcCircle.cpp index 82a822e34c..754c62df62 100644 --- a/src/ifcgeom/mapping/IfcCircle.cpp +++ b/src/ifcgeom/mapping/IfcCircle.cpp @@ -35,10 +35,5 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcCircle* inst) { c->radius = r; c->matrix = taxonomy::cast(map(placement)); - auto e = taxonomy::make(); - e->basis = c; - e->start = 0.; - e->end = 2 * boost::math::constants::pi(); - - return e; + return c; } diff --git a/src/ifcgeom/mapping/IfcEllipse.cpp b/src/ifcgeom/mapping/IfcEllipse.cpp index dfde1c2128..1d1e70e303 100644 --- a/src/ifcgeom/mapping/IfcEllipse.cpp +++ b/src/ifcgeom/mapping/IfcEllipse.cpp @@ -51,10 +51,5 @@ taxonomy::ptr mapping::map_impl(const IfcSchema::IfcEllipse* inst) { el->radius = x; el->radius2 = y; - auto e = taxonomy::make(); - e->basis = el; - e->start = 0.; - e->end = 2 * boost::math::constants::pi(); - - return e; + return el; } From 37315e941a6d0fd08877f48ac2d74cc26fdf30da Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 11:56:49 +0500 Subject: [PATCH 03/12] taxonomy.h - move upgrades code to cpp --- src/ifcgeom/taxonomy.cpp | 153 +++++++++++++++++++++++++++++++++++++++ src/ifcgeom/taxonomy.h | 135 +++------------------------------- 2 files changed, 165 insertions(+), 123 deletions(-) diff --git a/src/ifcgeom/taxonomy.cpp b/src/ifcgeom/taxonomy.cpp index 9b4f5043aa..0c78b84601 100644 --- a/src/ifcgeom/taxonomy.cpp +++ b/src/ifcgeom/taxonomy.cpp @@ -599,3 +599,156 @@ void ifcopenshell::geometry::taxonomy::extrusion::print(std::ostream& o, int ind direction->print(o, indent + 4); basis->print(o, indent + 4); } + +boost::optional ifcopenshell::geometry::taxonomy::loop_to_face_upgrade_impl(ptr item) { + boost::optional face_; + auto loop_ = dcast(item); + if (loop_) { + loop_->external = true; + + face_ = make(); + (*face_)->instance = loop_->instance; + (*face_)->matrix = loop_->matrix; + (*face_)->children = { clone(loop_) }; + } + return face_; +} + +boost::optional ifcopenshell::geometry::taxonomy::curve_to_edge_upgrade_impl(ptr item) { + boost::optional edge_; + auto circle_ = dcast(item); + auto ellipse_ = dcast(item); + auto line_ = dcast(item); + auto bspline_curve_ = dcast(item); + if (circle_ || ellipse_ || line_ || bspline_curve_) { + edge_ = make(); + if (circle_) { + (*edge_)->basis = circle_; + } else if (ellipse_) { + (*edge_)->basis = ellipse_; + } else if (line_) { + (*edge_)->basis = line_; + } else if (bspline_curve_) { + (*edge_)->basis = bspline_curve_; + } + + if (circle_ || ellipse_) { + // @todo + (*edge_)->start = 0.; + (*edge_)->end = 2 * boost::math::constants::pi(); + } + } + return edge_; +} + +boost::optional ifcopenshell::geometry::taxonomy::curve_to_loop_upgrade_impl(ptr item) { + boost::optional loop_; + auto circle_ = dcast(item); + auto ellipse_ = dcast(item); + auto line_ = dcast(item); + auto bspline_curve_ = dcast(item); + if (circle_ || ellipse_ || line_ || bspline_curve_) { + auto edge_ = make(); + if (circle_) { + edge_->basis = circle_; + } else if (ellipse_) { + edge_->basis = ellipse_; + } else if (line_) { + edge_->basis = line_; + } else if (bspline_curve_) { + edge_->basis = bspline_curve_; + } + + if (circle_ || ellipse_) { + // @todo + edge_->start = 0.; + edge_->end = 2 * boost::math::constants::pi(); + } + + loop_ = make(); + (*loop_)->children.push_back(edge_); + } + return loop_; +} + +boost::optional ifcopenshell::geometry::taxonomy::edge_to_loop_upgrade_impl(ptr item) { + boost::optional loop_; + auto edge_ = dcast(item); + if (edge_) { + loop_ = make(); + (*loop_)->children.push_back(edge_); + } + return loop_; +} + +boost::optional ifcopenshell::geometry::taxonomy::curve_to_face_upgrade_impl(ptr item) { + boost::optional face_; + auto circle_ = dcast(item); + auto ellipse_ = dcast(item); + auto line_ = dcast(item); + auto bspline_curve_ = dcast(item); + + if (circle_ || ellipse_ || line_ || bspline_curve_) { + auto edge_ = make(); + if (circle_) { + edge_->basis = circle_; + } else if (ellipse_) { + edge_->basis = ellipse_; + } else if (line_) { + edge_->basis = line_; + } else if (bspline_curve_) { + edge_->basis = bspline_curve_; + } + + if (circle_ || ellipse_) { + // @todo + edge_->start = 0.; + edge_->end = 2 * boost::math::constants::pi(); + } + + auto loop_ = make(); + loop_->children.push_back(edge_); + + face_ = make(); + (*face_)->instance = loop_->instance; + (*face_)->matrix = loop_->matrix; + (*face_)->children = { clone(loop_) }; + } + return face_; +} + + +boost::optional ifcopenshell::geometry::taxonomy::loop_to_piecewise_function_upgrade_impl(ptr item) { + boost::optional pwf_; + auto loop_ = dcast(item); + if (loop_) { + if (loop_->pwf.is_initialized()) { + pwf_ = loop_->pwf; + } else { + piecewise_function::spans_t spans; + spans.reserve(loop_->children.size()); + for (auto& edge_ : loop_->children) { + // the edge could be an arc or trimmed circle in the case of IfcIndexPolyCurve - support for this isn't implemented yet + if (edge_->basis) { + Logger::Message(Logger::Severity::LOG_NOTICE, "Shape of basis curve ignored - edge is treated as a straight line edge"); + } + + const auto& s = boost::get(edge_->start)->ccomponents(); + const auto& e = boost::get(edge_->end)->ccomponents(); + Eigen::Vector3d v = e - s; + auto l = v.norm(); // the norm of a vector is a measure of its length + v.normalize(); // normalize the vector so that it is a unit direction vector + std::function fn = [s, v](double u) { + Eigen::Vector3d o(s + u * v), axis(0, 0, 1), refDirection(v); + auto Y = axis.cross(refDirection).normalized(); + axis = refDirection.cross(Y).normalized(); + return make(o, axis, refDirection)->components(); + }; + spans.emplace_back(l, fn); + } + pwf_ = make(0.0,spans); + loop_->pwf = pwf_; + } + } + return pwf_; +} diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 3b77273240..40e738d1d8 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -1089,6 +1089,7 @@ typedef item const* ptr; static const size_t max = std::tuple_size::value; }; + boost::optional loop_to_face_upgrade_impl(ptr item); template class loop_to_face_upgrade { private: @@ -1096,15 +1097,7 @@ typedef item const* ptr; public: loop_to_face_upgrade(taxonomy::ptr item) { if constexpr (std::is_same_v) { - auto loop = taxonomy::dcast(item); - if (loop) { - loop->external = true; - - face_ = taxonomy::make(); - (*face_)->instance = loop->instance; - (*face_)->matrix = loop->matrix; - (*face_)->children = { taxonomy::clone(loop) }; - } + face_ = loop_to_face_upgrade_impl(item); } } @@ -1122,6 +1115,7 @@ typedef item const* ptr; } }; + boost::optional curve_to_edge_upgrade_impl(ptr item); template class curve_to_edge_upgrade { private: @@ -1129,28 +1123,7 @@ typedef item const* ptr; public: curve_to_edge_upgrade(taxonomy::ptr item) { if constexpr (std::is_same_v) { - auto circle = taxonomy::dcast(item); - auto ellipse = taxonomy::dcast(item); - auto line = taxonomy::dcast(item); - auto bspline_curve = taxonomy::dcast(item); - if (circle || ellipse || line || bspline_curve) { - edge_ = taxonomy::make(); - if (circle) { - (*edge_)->basis = circle; - } else if (ellipse) { - (*edge_)->basis = ellipse; - } else if (line) { - (*edge_)->basis = line; - } else if (bspline_curve) { - (*edge_)->basis = bspline_curve; - } - - if (circle || ellipse) { - // @todo - (*edge_)->start = 0.; - (*edge_)->end = 2 * boost::math::constants::pi(); - } - } + edge_ = taxonomy::curve_to_edge_upgrade_impl(item); } } @@ -1168,7 +1141,7 @@ typedef item const* ptr; } }; - + boost::optional curve_to_loop_upgrade_impl(ptr item); template class curve_to_loop_upgrade { private: @@ -1176,31 +1149,7 @@ typedef item const* ptr; public: curve_to_loop_upgrade(taxonomy::ptr item) { if constexpr (std::is_same_v) { - auto circle = taxonomy::dcast(item); - auto ellipse = taxonomy::dcast(item); - auto line = taxonomy::dcast(item); - auto bspline_curve = taxonomy::dcast(item); - if (circle || ellipse || line || bspline_curve) { - auto edge = taxonomy::make(); - if (circle) { - edge->basis = circle; - } else if (ellipse) { - edge->basis = ellipse; - } else if (line) { - edge->basis = line; - } else if (bspline_curve) { - edge->basis = bspline_curve; - } - - if (circle || ellipse) { - // @todo - edge->start = 0.; - edge->end = 2 * boost::math::constants::pi(); - } - - loop_ = taxonomy::make(); - (*loop_)->children.push_back(edge); - } + loop_ = curve_to_loop_upgrade_impl(item); } } @@ -1218,6 +1167,7 @@ typedef item const* ptr; } }; + boost::optional edge_to_loop_upgrade_impl(ptr item); template class edge_to_loop_upgrade { private: @@ -1225,11 +1175,7 @@ typedef item const* ptr; public: edge_to_loop_upgrade(taxonomy::ptr item) { if constexpr (std::is_same_v) { - auto edge = taxonomy::dcast(item); - if (edge) { - loop_ = taxonomy::make(); - (*loop_)->children.push_back(edge); - } + loop_ = edge_to_loop_upgrade_impl(item); } } @@ -1247,7 +1193,7 @@ typedef item const* ptr; } }; - + boost::optional curve_to_face_upgrade_impl(ptr item); template class curve_to_face_upgrade { private: @@ -1255,36 +1201,7 @@ typedef item const* ptr; public: curve_to_face_upgrade(taxonomy::ptr item) { if constexpr (std::is_same_v) { - auto circle = taxonomy::dcast(item); - auto ellipse = taxonomy::dcast(item); - auto line = taxonomy::dcast(item); - auto bspline_curve = taxonomy::dcast(item); - if (circle || ellipse || line || bspline_curve) { - auto edge = taxonomy::make(); - if (circle) { - edge->basis = circle; - } else if (ellipse) { - edge->basis = ellipse; - } else if (line) { - edge->basis = line; - } else if (bspline_curve) { - edge->basis = bspline_curve; - } - - if (circle || ellipse) { - // @todo - edge->start = 0.; - edge->end = 2 * boost::math::constants::pi(); - } - - auto loop = taxonomy::make(); - loop->children.push_back(edge); - - face_ = taxonomy::make(); - (*face_)->instance = loop->instance; - (*face_)->matrix = loop->matrix; - (*face_)->children = { taxonomy::clone(loop) }; - } + face_ = curve_to_face_upgrade_impl(item); } } @@ -1302,6 +1219,7 @@ typedef item const* ptr; } }; + boost::optional loop_to_piecewise_function_upgrade_impl(ptr item); template class loop_to_piecewise_function_upgrade { private: @@ -1310,36 +1228,7 @@ typedef item const* ptr; public: loop_to_piecewise_function_upgrade(taxonomy::ptr item) { if constexpr (std::is_same_v) { - auto loop = taxonomy::dcast(item); - if (loop) { - if (loop->pwf.is_initialized()) { - pwf_ = loop->pwf; - } else { - taxonomy::piecewise_function::spans_t spans; - spans.reserve(loop->children.size()); - for (auto& edge : loop->children) { - // the edge could be an arc or trimmed circle in the case of IfcIndexPolyCurve - support for this isn't implemented yet - if (edge->basis) { - Logger::Message(Logger::Severity::LOG_NOTICE, "Shape of basis curve ignored - edge is treated as a straight line edge"); - } - - const auto& s = boost::get(edge->start)->ccomponents(); - const auto& e = boost::get(edge->end)->ccomponents(); - Eigen::Vector3d v = e - s; - auto l = v.norm(); // the norm of a vector is a measure of its length - v.normalize(); // normalize the vector so that it is a unit direction vector - std::function fn = [s, v](double u) { - Eigen::Vector3d o(s + u * v), axis(0, 0, 1), refDirection(v); - auto Y = axis.cross(refDirection).normalized(); - axis = refDirection.cross(Y).normalized(); - return taxonomy::make(o, axis, refDirection)->components(); - }; - spans.emplace_back(l, fn); - } - pwf_ = taxonomy::make(0.0,spans); - loop->pwf = pwf_; - } - } + pwf_ = loop_to_piecewise_function_upgrade_impl(item); } } From 35221ed77294927038e5c28a70d5f0ddc3ed3f93 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 11:56:21 +0500 Subject: [PATCH 04/12] AbstractKernel::convert to use upgrade to edge as a fallback --- src/ifcgeom/AbstractKernel.cpp | 18 ++++++++++++++++-- src/ifcgeom/taxonomy.cpp | 4 ++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/AbstractKernel.cpp b/src/ifcgeom/AbstractKernel.cpp index a82e7c1641..4a59c24521 100644 --- a/src/ifcgeom/AbstractKernel.cpp +++ b/src/ifcgeom/AbstractKernel.cpp @@ -29,8 +29,22 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::pt try { return dispatch_conversion<0>::dispatch(this, item->kind(), item, results); } catch (std::exception& e) { - Logger::Error(e, item->instance); - return false; + std::string prev_exception; + try { + prev_exception = std::string(e.what()); + // Try to upgrade. Works for circles and ellipses. + auto concrete_item = ifcopenshell::geometry::taxonomy::template dcast(item); + if (concrete_item) { + return convert_impl(concrete_item, results); + } + Logger::Error(prev_exception + " Upgrade also didn't worked.", item->instance); + return false; + } catch (std::exception& e) { + Logger::Error(prev_exception + " Conversion for upgraded element failed with: " + std::string(e.what()), item->instance); + return false; + } catch (...) { + return false; + } } catch (...) { // @todo we can't log OCCT exceptions here, can we do some reraising to solve this? return false; diff --git a/src/ifcgeom/taxonomy.cpp b/src/ifcgeom/taxonomy.cpp index 0c78b84601..818802dd2d 100644 --- a/src/ifcgeom/taxonomy.cpp +++ b/src/ifcgeom/taxonomy.cpp @@ -624,12 +624,16 @@ boost::optional ifcopenshell::geometry::taxonomy::curve_to_edge_upgra edge_ = make(); if (circle_) { (*edge_)->basis = circle_; + (*edge_)->instance = circle_->instance; } else if (ellipse_) { (*edge_)->basis = ellipse_; + (*edge_)->instance = ellipse_->instance; } else if (line_) { (*edge_)->basis = line_; + (*edge_)->instance = line_->instance; } else if (bspline_curve_) { (*edge_)->basis = bspline_curve_; + (*edge_)->instance = bspline_curve_->instance; } if (circle_ || ellipse_) { From fe0be0cdae22123016ff847f984d4155755e3765 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 15:05:18 +0500 Subject: [PATCH 05/12] shape_builder.create_axis2_placement_2d --- .../ifcopenshell/util/shape_builder.py | 23 +++++++++++-------- .../test/geom/geometry_tests.py | 8 +++---- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py index 57868109ba..822f012925 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py +++ b/src/ifcopenshell-python/ifcopenshell/util/shape_builder.py @@ -228,10 +228,8 @@ class ShapeBuilder: :return: IfcCircle :rtype: ifcopenshell.entity_instance """ - ifc_center = self.file.createIfcAxis2Placement2D(self.file.createIfcCartesianPoint(center)) + ifc_center = self.create_axis2_placement_2d(center) ifc_curve = self.file.createIfcCircle(ifc_center, radius) - - # self.file_file.createIfcAxis2Placement2D(tool.Ifc.get().createIfcCartesianPoint(center[0:2])) return ifc_curve def plane( @@ -324,9 +322,7 @@ class ShapeBuilder: for further extrusion. """ direction = self.file.createIfcDirection(ref_x_direction) - ifc_position = self.file.createIfcAxis2Placement2D( - self.file.createIfcCartesianPoint(position), RefDirection=direction - ) + ifc_position = self.create_axis2_placement_2d(position, direction) ifc_ellipse = self.file.createIfcEllipse( Position=ifc_position, SemiAxis1=x_axis_radius, SemiAxis2=y_axis_radius ) @@ -373,9 +369,7 @@ class ShapeBuilder: "OuterCurve": outer_curve, } if self.file.schema == "IFC2X3": - kwargs["Position"] = self.file.create_entity( - "IfcAxis2Placement2D", self.file.create_entity("IfcCartesianPoint", [0.0, 0.0]) - ) + kwargs["Position"] = self.create_axis2_placement_2d() if inner_curves: if not isinstance(inner_curves, collections.abc.Iterable): @@ -584,6 +578,17 @@ class ShapeBuilder: position=matrix[:, 3][:3].tolist(), z_axis=matrix[:, 2][:3].tolist(), x_axis=matrix[:, 0][:3].tolist() ) + def create_axis2_placement_2d( + self, position: VectorTuple = (0.0, 0.0), x_direction: Optional[VectorTuple] = None + ) -> ifcopenshell.entity_instance: + """Create IfcAxis2Placement2D.""" + ref_direction = self.file.create_entity("IfcDirection", x_direction) if x_direction else None + return self.file.create_entity( + "IfcAxis2Placement2D", + Location=self.file.create_entity("IfcCartesianPoint", position), + RefDirection=ref_direction, + ) + def mirror( self, curve_or_item: Union[ifcopenshell.entity_instance, list[ifcopenshell.entity_instance]], diff --git a/src/ifcopenshell-python/test/geom/geometry_tests.py b/src/ifcopenshell-python/test/geom/geometry_tests.py index 1ecfa35b4b..92a8f14da6 100644 --- a/src/ifcopenshell-python/test/geom/geometry_tests.py +++ b/src/ifcopenshell-python/test/geom/geometry_tests.py @@ -31,12 +31,10 @@ class TestCreatingShapes(test.bootstrap.IFC4): assert shape.verts def test_create_IfcEllipse(self): - ifc_position = self.file.create_entity( - "IfcAxis2Placement2D", - self.file.create_entity("IfcCartesianPoint", V(0, 0)), - RefDirection=self.file.create_entity("IfcDirection", V(1, 0)), + builder = ShapeBuilder(self.file) + item = self.file.create_entity( + "IfcEllipse", Position=builder.create_axis2_placement_2d(), SemiAxis1=1.0, SemiAxis2=0.5 ) - item = self.file.create_entity("IfcEllipse", Position=ifc_position, SemiAxis1=1.0, SemiAxis2=0.5) settings = ifcopenshell.geom.settings() shape = ifcopenshell.geom.create_shape(settings, item) assert shape.verts From ad8131114dbfcf1bb0faeaf4029f8d17c9b146f6 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 15:08:18 +0500 Subject: [PATCH 06/12] IfcLine, IfcBSplineCurve geometry tests --- .../test/geom/geometry_tests.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/ifcopenshell-python/test/geom/geometry_tests.py b/src/ifcopenshell-python/test/geom/geometry_tests.py index 92a8f14da6..c7163df73f 100644 --- a/src/ifcopenshell-python/test/geom/geometry_tests.py +++ b/src/ifcopenshell-python/test/geom/geometry_tests.py @@ -38,3 +38,27 @@ class TestCreatingShapes(test.bootstrap.IFC4): settings = ifcopenshell.geom.settings() shape = ifcopenshell.geom.create_shape(settings, item) assert shape.verts + + def test_create_IfcLine(self): + item = self.file.create_entity( + "IfcLine", + Pnt=self.file.create_entity("IfcCartesianPoint", (0.0, 0.0)), + Dir=self.file.create_entity( + "IfcVector", Orientation=self.file.create_entity("IfcDirection", (1.0, 0.0)), Magnitude=1.0 + ), + ) + settings = ifcopenshell.geom.settings() + shape = ifcopenshell.geom.create_shape(settings, item) + assert shape.verts + + def test_create_IfcBSplineCurve(self): + item = item = self.file.create_entity( + "IfcBSplineCurveWithKnots", + Degree=3, + ControlPointsList=[self.file.create_entity("IfcCartesianPoint", p) for p in points], + KnotMultiplicities=(4, 1, 1, 4), + Knots=(0.0, 1 / 3, 2 / 3, 1.0), + ) + settings = ifcopenshell.geom.settings() + shape = ifcopenshell.geom.create_shape(settings, item) + assert shape.verts From 858e57351e9f2d59412c7d324fc461312037e6d8 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 17:46:11 +0500 Subject: [PATCH 07/12] AbstractKernel::convert - more generic approach --- src/ifcgeom/AbstractKernel.cpp | 11 ++--------- src/ifcgeom/AbstractKernel.h | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ifcgeom/AbstractKernel.cpp b/src/ifcgeom/AbstractKernel.cpp index 4a59c24521..23d7bc1e21 100644 --- a/src/ifcgeom/AbstractKernel.cpp +++ b/src/ifcgeom/AbstractKernel.cpp @@ -29,16 +29,9 @@ bool ifcopenshell::geometry::kernels::AbstractKernel::convert(const taxonomy::pt try { return dispatch_conversion<0>::dispatch(this, item->kind(), item, results); } catch (std::exception& e) { - std::string prev_exception; + std::string prev_exception = std::string(e.what()); try { - prev_exception = std::string(e.what()); - // Try to upgrade. Works for circles and ellipses. - auto concrete_item = ifcopenshell::geometry::taxonomy::template dcast(item); - if (concrete_item) { - return convert_impl(concrete_item, results); - } - Logger::Error(prev_exception + " Upgrade also didn't worked.", item->instance); - return false; + return dispatch_with_upgrade<0>::dispatch(this, item, results); } catch (std::exception& e) { Logger::Error(prev_exception + " Conversion for upgraded element failed with: " + std::string(e.what()), item->instance); return false; diff --git a/src/ifcgeom/AbstractKernel.h b/src/ifcgeom/AbstractKernel.h index 87a6e4d623..f743d7c497 100644 --- a/src/ifcgeom/AbstractKernel.h +++ b/src/ifcgeom/AbstractKernel.h @@ -102,6 +102,26 @@ namespace { } }; + template + struct dispatch_with_upgrade { + static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults& results) { + auto concrete_item = ifcopenshell::geometry::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::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults&) { + Logger::Error("No conversion with upgrade for " + std::to_string(item->kind())); + return false; + } + }; + template struct TupleTypeIndex; From 005c17084b2f290651dddcb3db79d2bf869c4505 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 18:24:24 +0500 Subject: [PATCH 08/12] dispatch_with_upgrade to use only upgrade types for optimization --- src/ifcgeom/AbstractKernel.h | 4 ++-- src/ifcgeom/taxonomy.h | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/AbstractKernel.h b/src/ifcgeom/AbstractKernel.h index f743d7c497..8c65643e24 100644 --- a/src/ifcgeom/AbstractKernel.h +++ b/src/ifcgeom/AbstractKernel.h @@ -105,7 +105,7 @@ namespace { template struct dispatch_with_upgrade { static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults& results) { - auto concrete_item = ifcopenshell::geometry::taxonomy::template dcast>(item); + auto concrete_item = ifcopenshell::geometry::taxonomy::template dcast>(item); if (concrete_item) { return kernel->convert_impl(concrete_item, results); } else { @@ -115,7 +115,7 @@ namespace { }; template <> - struct dispatch_with_upgrade { + struct dispatch_with_upgrade { static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel*, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults&) { Logger::Error("No conversion with upgrade for " + std::to_string(item->kind())); return false; diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 40e738d1d8..d2eae3813a 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -1066,6 +1066,7 @@ typedef item const* ptr; typedef std::tuple KindsTuple; typedef std::tuple CurvesTuple; typedef std::tuple SurfacesTuple; + typedef std::tuple UpgradesTuple; } struct type_by_kind { @@ -1089,6 +1090,13 @@ typedef item const* ptr; static const size_t max = std::tuple_size::value; }; + struct upgrades { + template + using type = typename std::tuple_element::type; + + static const size_t max = std::tuple_size::value; + }; + boost::optional loop_to_face_upgrade_impl(ptr item); template class loop_to_face_upgrade { From 4c04bc7cb5050c8b93e932fe57a8817563ccbfef Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Wed, 11 Sep 2024 19:41:10 +0500 Subject: [PATCH 09/12] fix test_create_IfcBSplineCurve --- src/ifcopenshell-python/test/geom/geometry_tests.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/ifcopenshell-python/test/geom/geometry_tests.py b/src/ifcopenshell-python/test/geom/geometry_tests.py index c7163df73f..0d77f505ed 100644 --- a/src/ifcopenshell-python/test/geom/geometry_tests.py +++ b/src/ifcopenshell-python/test/geom/geometry_tests.py @@ -52,7 +52,15 @@ class TestCreatingShapes(test.bootstrap.IFC4): assert shape.verts def test_create_IfcBSplineCurve(self): - item = item = self.file.create_entity( + points = [ + (6.4062, 19.4575766757, 13.352536093), + (5.8477429418, 19.9080686796, 14.1328111323), + (3.6139147091, 20.3256826827, 14.8561398035), + (1.1790137971e-05, 20.2853841412, 14.7863406821), + (1.1790137971e-05, 18.5102818197, 11.7117732726), + (1.16078600148, 18.0665062393, 10.9431314203), + ] + item = self.file.create_entity( "IfcBSplineCurveWithKnots", Degree=3, ControlPointsList=[self.file.create_entity("IfcCartesianPoint", p) for p in points], From 93c47498ef6e9787cfeaef121de873899dd35342 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 12 Sep 2024 11:13:59 +0500 Subject: [PATCH 10/12] AbstractKernel::dispatch_conversion - use static cast Previously it was using taxonomy::cast that was also trying to upgrade current item - due to the strictness of dispatch_conversion (it works only if type matches exactly because of `N == item_kind`) upgrades will never succeed so we may just skip them. --- src/ifcgeom/AbstractKernel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ifcgeom/AbstractKernel.h b/src/ifcgeom/AbstractKernel.h index 8c65643e24..d06fe6bf4a 100644 --- a/src/ifcgeom/AbstractKernel.h +++ b/src/ifcgeom/AbstractKernel.h @@ -86,7 +86,7 @@ namespace { struct dispatch_conversion { static bool dispatch(ifcopenshell::geometry::kernels::AbstractKernel* kernel, ifcopenshell::geometry::taxonomy::kinds item_kind, const ifcopenshell::geometry::taxonomy::ptr item, IfcGeom::ConversionResults& results) { if (N == item_kind) { - auto concrete_item = ifcopenshell::geometry::taxonomy::template cast>(item); + 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); From f9308972409ad1ba3a2decc0a3d8be02d0df702b Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 12 Sep 2024 11:16:49 +0500 Subject: [PATCH 11/12] taxonomy::dcast - add missing curve_to_loop_upgrade --- src/ifcgeom/taxonomy.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index d2eae3813a..8232f021d2 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -1307,6 +1307,12 @@ typedef item const* ptr; return upg; } } + { + curve_to_loop_upgrade upg(u); + if (upg) { + return upg; + } + } { curve_to_face_upgrade upg(u); if (upg) { From cb21f9bc0749bb054bb10eff1b2af732f54a1a00 Mon Sep 17 00:00:00 2001 From: Andrej730 Date: Thu, 12 Sep 2024 11:19:37 +0500 Subject: [PATCH 12/12] taxonomy::cast - order upgrades in the same order as in taxonomy::dcast for consistency --- src/ifcgeom/taxonomy.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/taxonomy.h b/src/ifcgeom/taxonomy.h index 8232f021d2..07385be746 100644 --- a/src/ifcgeom/taxonomy.h +++ b/src/ifcgeom/taxonomy.h @@ -1270,13 +1270,13 @@ typedef item const* ptr; } } { - edge_to_loop_upgrade upg(u); + curve_to_face_upgrade upg(u); if (upg) { return upg; } } { - curve_to_face_upgrade upg(u); + edge_to_loop_upgrade upg(u); if (upg) { return upg; }