From c595adfb7b5c7d94f67cc0ef195ca63a5caf0d24 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 5 Dec 2023 21:10:42 +0100 Subject: [PATCH 1/6] Use world coords on OBJ/STP/IGS serializers as before --- src/ifcconvert/IfcConvert.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ifcconvert/IfcConvert.cpp b/src/ifcconvert/IfcConvert.cpp index 98c59d77b6..baeb3409de 100644 --- a/src/ifcconvert/IfcConvert.cpp +++ b/src/ifcconvert/IfcConvert.cpp @@ -805,6 +805,10 @@ int main(int argc, char** argv) { IfcGeom::update_default_style("IfcSpace").transparency = geometry_settings.get().get(); } + if (output_extension == OBJ || output_extension == STP || output_extension == IGS) { + geometry_settings.get().value = true; + } + boost::shared_ptr serializer; /**< @todo use std::unique_ptr when possible */ if (output_extension == OBJ) { // Do not use temp file for MTL as it's such a small file. From 4cd327f711737253d5f979d0b15fa80c3c69872d Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 5 Dec 2023 21:11:36 +0100 Subject: [PATCH 2/6] Don't mutate conversion result placement. Breaks combination of world coords + optimized model. --- src/ifcgeom/ConversionResult.cpp | 10 ++++++++++ src/ifcgeom/ConversionResult.h | 10 ++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/ConversionResult.cpp b/src/ifcgeom/ConversionResult.cpp index da29dc380e..30bed11214 100644 --- a/src/ifcgeom/ConversionResult.cpp +++ b/src/ifcgeom/ConversionResult.cpp @@ -8,3 +8,13 @@ IfcGeom::Representation::Triangulation * IfcGeom::ConversionResultShape::Triangu Triangulate(settings, iden, t, -1); return t; } + +using namespace ifcopenshell::geometry::taxonomy; + +void IfcGeom::ConversionResult::append(ifcopenshell::geometry::taxonomy::matrix4::ptr trsf) { + placement_ = make(placement_->ccomponents() * trsf->ccomponents()); +} + +void IfcGeom::ConversionResult::prepend(ifcopenshell::geometry::taxonomy::matrix4::ptr trsf) { + placement_ = make(trsf->ccomponents() * placement_->ccomponents()); +} diff --git a/src/ifcgeom/ConversionResult.h b/src/ifcgeom/ConversionResult.h index 333b305ec4..1577eb369d 100644 --- a/src/ifcgeom/ConversionResult.h +++ b/src/ifcgeom/ConversionResult.h @@ -245,14 +245,8 @@ namespace IfcGeom { ConversionResult(int id, ConversionResultShape* shape) : id(id), placement_(ifcopenshell::geometry::taxonomy::make()), shape_(shape) {} - void append(ifcopenshell::geometry::taxonomy::matrix4::ptr trsf) { - // @todo verify order - placement_->components() = placement_->ccomponents() * trsf->ccomponents(); - } - void prepend(ifcopenshell::geometry::taxonomy::matrix4::ptr trsf) { - // @todo verify order - placement_->components() = trsf->ccomponents() * placement_->ccomponents(); - } + void append(ifcopenshell::geometry::taxonomy::matrix4::ptr trsf); + void prepend(ifcopenshell::geometry::taxonomy::matrix4::ptr trsf); std::shared_ptr Shape() const { return shape_; } ifcopenshell::geometry::taxonomy::matrix4::ptr Placement() const { return placement_; } bool hasStyle() const { return !!style_; } From 0b4718b3b5cedce2f69b2602138a72c3588d8fbe Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 5 Dec 2023 21:12:09 +0100 Subject: [PATCH 3/6] Report tasks on actual mapped products --- src/ifcgeom/Iterator.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/Iterator.h b/src/ifcgeom/Iterator.h index b5698a570b..9c31ff8948 100644 --- a/src/ifcgeom/Iterator.h +++ b/src/ifcgeom/Iterator.h @@ -185,9 +185,9 @@ namespace IfcGeom { tasks_.push_back(res); } - std::vector products; - for (auto& r : reps) { - std::copy(r.products->begin(), r.products->end(), std::back_inserter(products)); + size_t num_products = 0; + for (auto& r : tasks_) { + num_products += r.products.size(); } /* @@ -220,7 +220,7 @@ namespace IfcGeom { } */ - Logger::Notice("Created " + boost::lexical_cast(tasks_.size()) + " tasks for " + boost::lexical_cast(products.size()) + " products"); + Logger::Notice("Created " + boost::lexical_cast(tasks_.size()) + " tasks for " + boost::lexical_cast(num_products) + " products"); if (tasks_.size() == 0) { Logger::Warning("No representations encountered, aborting"); From 059c9fb7d5b7d544f1a2db4e5e8e0820e3ca3d2f Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 5 Dec 2023 21:13:43 +0100 Subject: [PATCH 4/6] remove_degenerate_faces() in order to prevent division by zero --- src/ifcgeom/kernels/cgal/CgalConversionResult.cpp | 6 ++++++ src/ifcgeom/kernels/cgal/CgalConversionResult.h | 4 +--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index f29b935501..207a55e186 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -18,6 +18,12 @@ using ifcopenshell::geometry::NumberEpeck; #define NumberType NumberEpeck #endif +ifcopenshell::geometry::CgalShape::CgalShape(const cgal_shape_t & shape) { + shape_ = shape; + CGAL::Polygon_mesh_processing::triangulate_faces(*shape_); + CGAL::Polygon_mesh_processing::remove_degenerate_faces(*shape_); +} + #ifndef IFOPSH_SIMPLE_KERNEL void ifcopenshell::geometry::CgalShape::to_poly() const { if (!shape_) { diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.h b/src/ifcgeom/kernels/cgal/CgalConversionResult.h index b0e3da28c0..0811b1968d 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.h +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.h @@ -171,9 +171,7 @@ namespace ifcopenshell { namespace geometry { mutable boost::optional> nef_; #endif public: - CgalShape(const cgal_shape_t& shape) { - shape_ = shape; - } + CgalShape(const cgal_shape_t& shape); #ifndef IFOPSH_SIMPLE_KERNEL CgalShape(const CGAL::Nef_polyhedron_3& shape) { From c1cb16f5f67989f65e95feab4b1290e384cd2228 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 5 Dec 2023 21:14:43 +0100 Subject: [PATCH 5/6] Implement a bunch of shape analysis routines --- .../kernels/cgal/CgalConversionResult.cpp | 95 +++++++++++++++++-- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 207a55e186..357741ba92 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -265,12 +265,62 @@ std::shared_ptr ifcopenshell::geometry::CgalShape::volume() OpaqueCoordinate<3> ifcopenshell::geometry::CgalShape::position() { - throw std::runtime_error("Invalid shape type"); + to_poly(); + if (shape_->size_of_facets() == 1) { + // return centroid; + // CGAL::Vector_3 p; + std::array p; + for (auto it = shape_->points_begin(); it != shape_->points_end(); ++it) { + for (int i = 0; i < 3; ++i) { + p[i] += it->cartesian(i); + } + } + Kernel_::FT N(std::distance(shape_->points_begin(), shape_->points_end())); + for (int i = 0; i < 3; ++i) { + p[i] /= N; + } + return OpaqueCoordinate<3>( + std::make_shared(p[0]), + std::make_shared(p[1]), + std::make_shared(p[2]) + ); + } else { + throw std::runtime_error("Invalid shape type"); + } +} + +namespace { + struct Plane_equation { + template + typename Facet::Plane_3 operator()(Facet& f) { + // @todo from the docs, but better use Newell's method + typename Facet::Halfedge_handle h = f.halfedge(); + typedef typename Facet::Plane_3 Plane; + return Plane(h->vertex()->point(), + h->next()->vertex()->point(), + h->next()->next()->vertex()->point()); + } + }; } OpaqueCoordinate<3> ifcopenshell::geometry::CgalShape::axis() { - throw std::runtime_error("Invalid shape type"); + to_poly(); + if (shape_->size_of_facets() == 1) { + auto pl = Plane_equation()(*shape_->facets_begin()); + std::array abc{ pl.a(), pl.b(), pl.c() }; + auto minel = std::min_element(abc.begin(), abc.end()); + auto maxel = std::max_element(abc.begin(), abc.end()); + auto maxval = ((-*minel) > *maxel) ? (-*minel) : *maxel; + + return OpaqueCoordinate<3>( + std::make_shared(pl.a() / maxval), + std::make_shared(pl.b() / maxval), + std::make_shared(pl.c() / maxval) + ); + } else { + throw std::runtime_error("Invalid shape type"); + } } OpaqueCoordinate<4> ifcopenshell::geometry::CgalShape::plane_equation() @@ -330,7 +380,24 @@ std::vector ifcopenshell::geometry::CgalShape::edges() std::vector ifcopenshell::geometry::CgalShape::facets() { - throw std::runtime_error("Not implemented"); + to_poly(); + std::vector result; + for (auto &face : faces(*shape_)) { + std::vector ps; + std::vector> ids(1); + + auto it = face->facet_begin(); + do { + ps.push_back(it->vertex()->point()); + ids.front().push_back(ids.front().size()); + } while (++it != face->facet_begin()); + + cgal_shape_t poly; + CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(ps, ids, poly); + + result.push_back(new CgalShape(poly)); + } + return result; } ConversionResultShape* ifcopenshell::geometry::CgalShape::add(ConversionResultShape* other) @@ -459,10 +526,14 @@ OpaqueCoordinate<3> ifcopenshell::geometry::CgalShapeHalfSpaceDecomposition::pos OpaqueCoordinate<3> ifcopenshell::geometry::CgalShapeHalfSpaceDecomposition::axis() { if (planes_.size() == 1) { + std::array abc{ planes_.front().a(), planes_.front().b(), planes_.front().c() }; + auto minel = std::min_element(abc.begin(), abc.end()); + auto maxel = std::max_element(abc.begin(), abc.end()); + auto maxval = ((-*minel) > *maxel) ? (-*minel) : *maxel; return OpaqueCoordinate<3>( - std::make_shared(planes_.front().a()), - std::make_shared(planes_.front().b()), - std::make_shared(planes_.front().c()) + std::make_shared(planes_.front().a() / maxval), + std::make_shared(planes_.front().b() / maxval), + std::make_shared(planes_.front().c() / maxval) ); } else { throw std::runtime_error("Invalid shape type"); @@ -472,11 +543,15 @@ OpaqueCoordinate<3> ifcopenshell::geometry::CgalShapeHalfSpaceDecomposition::axi OpaqueCoordinate<4> ifcopenshell::geometry::CgalShapeHalfSpaceDecomposition::plane_equation() { if (planes_.size() == 1) { + std::array abc{ planes_.front().a(), planes_.front().b(), planes_.front().c() }; + auto minel = std::min_element(abc.begin(), abc.end()); + auto maxel = std::max_element(abc.begin(), abc.end()); + auto maxval = ((-*minel) > *maxel) ? (-*minel) : *maxel; return OpaqueCoordinate<4>( - std::make_shared(planes_.front().a()), - std::make_shared(planes_.front().b()), - std::make_shared(planes_.front().c()), - std::make_shared(planes_.front().d()) + std::make_shared(planes_.front().a() / maxval), + std::make_shared(planes_.front().b() / maxval), + std::make_shared(planes_.front().c() / maxval), + std::make_shared(planes_.front().d() / maxval) ); } else { throw std::runtime_error("Invalid shape type"); From f687e610b9686d0d7eed51daa15017fb408b8924 Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 5 Dec 2023 21:15:06 +0100 Subject: [PATCH 6/6] Workaround to create epeck number from python --- src/ifcwrap/IfcGeomWrapper.i | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ifcwrap/IfcGeomWrapper.i b/src/ifcwrap/IfcGeomWrapper.i index 4d3808fec8..099615fa18 100644 --- a/src/ifcwrap/IfcGeomWrapper.i +++ b/src/ifcwrap/IfcGeomWrapper.i @@ -631,6 +631,17 @@ struct ShapeRTTI : public boost::static_visitor %template(OpaqueCoordinate_3) IfcGeom::OpaqueCoordinate<3>; %template(OpaqueCoordinate_4) IfcGeom::OpaqueCoordinate<4>; +%{ + #include "../ifcgeom/kernels/cgal/CgalConversionResult.h" +%} + +%inline %{ + std::shared_ptr create_epeck(int i) { + return std::make_shared(i); + } +%} + + %naturalvar svgfill::polygon_2::boundary; %naturalvar svgfill::polygon_2::inner_boundaries; %naturalvar svgfill::polygon_2::point_inside;