From 11ad1b2cc56717a1a0c8ce677ffc65704546759e Mon Sep 17 00:00:00 2001 From: Thomas Krijnen Date: Tue, 24 Sep 2019 15:46:50 +0200 Subject: [PATCH] cgal extrusion --- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 154 ++++++++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 16 ++- 2 files changed, 166 insertions(+), 4 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index f78f39a18c..7ce5eeb9ed 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -179,6 +179,37 @@ bool CgalKernel::convert(const taxonomy::face* face, cgal_face_t& result) { return true; } +namespace { + bool convert_curve(CgalKernel* kernel, const taxonomy::item* curve, cgal_wire_t& builder) { + if (curve->kind() == taxonomy::EDGE) { + auto e = (taxonomy::edge*) curve; + if (true || e->basis == nullptr) { + if (builder.empty()) { + const auto& p = boost::get(e->start); + cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + builder.push_back(pnt); + } + const auto& p = boost::get(e->end); + cgal_point_t pnt(p.components(0), p.components(1), p.components(2)); + builder.push_back(pnt); + } else if (e->basis->kind() == taxonomy::CIRCLE) { + // @todo + } else if (e->basis->kind() == taxonomy::ELLIPSE) { + + } else { + throw std::runtime_error("Not implemented basis kind"); + } + } else if (curve->kind() == taxonomy::LOOP) { + const auto& edges = ((taxonomy::loop*) curve)->children; + for (auto& c : edges) { + convert_curve(kernel, c, builder); + } + } else { + throw std::runtime_error("Not implemented curve"); + } + } +} + bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { // @todo only implement polygonal loops @@ -187,6 +218,7 @@ bool CgalKernel::convert(const taxonomy::loop* loop, cgal_wire_t& result) { for (auto& e : edges) { if (e->basis) { + Logger::Error("Only polyhedra supported :("); return false; } points.push_back(boost::get(e->start)); @@ -244,3 +276,125 @@ bool CgalKernel::convert_impl(const taxonomy::shell *shell, ifcopenshell::geomet )); return true; } + +bool CgalKernel::convert_impl(const taxonomy::extrusion* extrusion, ifcopenshell::geometry::ConversionResults& results) { + cgal_shape_t shape; + if (!convert(extrusion, shape)) { + return false; + } + results.emplace_back(ConversionResult( + extrusion->instance->data().id(), + extrusion->matrix, + new CgalShape(shape), + extrusion->surface_style + )); + return true; +} + +bool CgalKernel::convert(const taxonomy::extrusion* extrusion, cgal_shape_t &shape) { + const double& height = extrusion->depth; + if (height < precision_) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", extrusion->instance); + return false; + } + + // Outer + cgal_face_t bottom_face; + if (!convert(&extrusion->basis, bottom_face)) { + return false; + } + // std::cout << "Face vertices: " << face.outer.size() << std::endl; + + auto fs = extrusion->direction.components; + cgal_direction_t dir(fs(0), fs(1), fs(2)); + // std::cout << "Direction: " << dir << std::endl; + + std::list face_list; + face_list.push_back(bottom_face); + + for (std::vector::const_iterator current_vertex = bottom_face.outer.begin(); + current_vertex != bottom_face.outer.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == bottom_face.outer.end()) { + next_vertex = bottom_face.outer.begin(); + } cgal_face_t side_face; + side_face.outer.push_back(*next_vertex); + side_face.outer.push_back(*current_vertex); + side_face.outer.push_back(*current_vertex + height * dir); + side_face.outer.push_back(*next_vertex + height * dir); + face_list.push_back(side_face); + } + + cgal_face_t top_face; + for (std::vector::const_reverse_iterator vertex = bottom_face.outer.rbegin(); + vertex != bottom_face.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex + height * dir); + } face_list.push_back(top_face); + + if (bottom_face.inner.empty()) { + shape = create_polyhedron(face_list); + // if (has_position) for (auto &vertex : vertices(shape)) vertex->point() = vertex->point().transform(trsf); + return true; + } + + CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); + + // Inner + // TODO: Would be faster to triangulate top/bottom face template rather than use Nef polyhedra for subtraction + for (auto &inner : bottom_face.inner) { + // std::cout << "Inner wire" << std::endl; + face_list.clear(); + + cgal_face_t hole_bottom_face; + hole_bottom_face.outer = inner; + remove_duplicate_points_from_loop(hole_bottom_face.outer); + face_list.push_back(hole_bottom_face); + + for (std::vector::const_iterator current_vertex = inner.begin(); + current_vertex != inner.end(); + ++current_vertex) { + std::vector::const_iterator next_vertex = current_vertex; + ++next_vertex; + if (next_vertex == inner.end()) { + next_vertex = inner.begin(); + } cgal_face_t hole_side_face; + hole_side_face.outer.push_back(*next_vertex); + hole_side_face.outer.push_back(*current_vertex); + hole_side_face.outer.push_back(*current_vertex + height * dir); + hole_side_face.outer.push_back(*next_vertex + height * dir); + face_list.push_back(hole_side_face); + } + + cgal_face_t hole_top_face; + for (std::vector::const_reverse_iterator vertex = inner.rbegin(); + vertex != inner.rend(); + ++vertex) { + hole_top_face.outer.push_back(*vertex + height * dir); + } face_list.push_back(hole_top_face); + + try { + nef_shape -= create_nef_polyhedron(face_list); + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot subtract opening for:", extrusion->instance); + return false; + } + } + + /*if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + }*/ + + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + Logger::Message(Logger::LOG_ERROR, "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron for:", extrusion->instance); + return false; + } + +} \ No newline at end of file diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 541c07e465..bb682a7e8f 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -92,10 +92,14 @@ namespace geometry { namespace kernels { class IFC_GEOM_API CgalKernel : public AbstractKernel { + private: + double precision_; public: CgalKernel() - : AbstractKernel("cgal") {} + : AbstractKernel("cgal") + // @todo + , precision_(1.e-5) {} void remove_duplicate_points_from_loop(cgal_wire_t& polygon); @@ -104,12 +108,16 @@ namespace kernels { CGAL::Nef_polyhedron_3 create_nef_polyhedron(std::list &face_list); CGAL::Nef_polyhedron_3 create_nef_polyhedron(CGAL::Polyhedron_3 &polyhedron); + bool convert(const taxonomy::extrusion*, cgal_shape_t&); bool convert(const taxonomy::face*, cgal_face_t&); bool convert(const taxonomy::loop*, cgal_wire_t&); - bool convert(const taxonomy::shell* l, cgal_shape_t& shape); - + // bool convert(const taxonomy::matrix4*, cgal_placement_t&); + bool convert(const taxonomy::shell*, cgal_shape_t&); + + // virtual bool convert_impl(const taxonomy::face*, ifcopenshell::geometry::ConversionResults&); virtual bool convert_impl(const taxonomy::shell*, ifcopenshell::geometry::ConversionResults&); - // virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); + virtual bool convert_impl(const taxonomy::extrusion*, ifcopenshell::geometry::ConversionResults&); + // virtual bool convert_impl(const taxonomy::boolean_result*, ifcopenshell::geometry::ConversionResults&); }; }