From 2cb53a860dfc91f4fdc68d7b0fda5f34125a14a5 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 15:09:05 -0600 Subject: [PATCH 01/11] Entities for basic CSG --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 78 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index b163696066..520c21dfd4 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -37,6 +37,8 @@ SHAPES(IfcManifoldSolidBrep); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); +SHAPE(IfcCsgSolid); +SHAPE(IfcBlock); FACE(IfcFace); FACE(IfcRectangleProfileDef); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index b8efaf7f18..78b9b33c80 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -138,3 +138,81 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ shape = polyhedron; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCsgSolid* l, cgal_shape_t& shape) { + return convert_shape(l->TreeRootExpression(), shape); +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& shape) { + const double dx = l->XLength() * getValue(GV_LENGTH_UNIT); + const double dy = l->YLength() * getValue(GV_LENGTH_UNIT); + const double dz = l->ZLength() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + // x = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + + // x = dx + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + + // y = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + + // y = dy + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + + // z = 0 + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + + // z = dz + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, dz)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, dz)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + // IfcCsgPrimitive3D.Position has unit scale factor + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From c9633273a6f89206364a7d76ffbea65e10ca56ae Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 17:11:58 -0600 Subject: [PATCH 02/11] Several more classes, needs testing --- .../kernels/cgal/CgalConversionFunctions.cpp | 5 ++ src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 3 ++ src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp | 10 ++++ .../kernels/cgal/CgalIfcGeomShapes.cpp | 52 +++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp | 20 ++++++- src/ifcgeom/kernels/cgal/CgalKernel.h | 2 + 6 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 38f9e0d457..b096b3408e 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -144,3 +144,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcObjectPlacement* l, cgal_p // CACHE(IfcObjectPlacement,l,trsf) return true; } + +bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face) { + face.outer = wire; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 520c21dfd4..54efeb04ba 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -34,16 +34,19 @@ SHAPES(IfcRepresentation); // IfcFacetedBrepWithVoids included // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); +SHAPES(IfcMappedItem); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); SHAPE(IfcCsgSolid); SHAPE(IfcBlock); +FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); FACE(IfcRectangleProfileDef); WIRE(IfcPolyLoop); +WIRE(IfcPolyline); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 6cd88a434b..7c4e64337f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -1,5 +1,15 @@ #include "CgalKernel.h" +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcArbitraryClosedProfileDef* l, cgal_face_t& face) { + cgal_wire_t wire; + if ( ! convert_wire(l->OuterCurve(),wire) ) return false; + + cgal_face_t f; + bool success = convert_wire_to_face(wire, f); + if (success) face = f; + return success; +} + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cgal_face_t& face) { const double x = l->XDim() / 2.0f * getValue(GV_LENGTH_UNIT); const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 78b9b33c80..37c344e483 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -32,6 +32,58 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcManifoldSolidBrep* l, Conv return false; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionResults& shapes) { + cgal_placement_t gtrsf; + IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); + if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); + return false; + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3D) ) { + cgal_placement_t trsf; + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); + gtrsf = trsf; + } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { + cgal_placement_t trsf_2d; + Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator2D*)transform,trsf_2d); + gtrsf = (cgal_placement_t) trsf_2d; + } + IfcSchema::IfcRepresentationMap* map = l->MappingSource(); + IfcSchema::IfcAxis2Placement* placement = map->MappingOrigin(); + cgal_placement_t trsf; + if (placement->is(IfcSchema::Type::IfcAxis2Placement3D)) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement3D*)placement,trsf); + } else { + cgal_placement_t trsf_2d; + IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); + trsf = trsf_2d; + } + // TODO: Check + gtrsf = trsf * gtrsf; + + const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l); + + const size_t previous_size = shapes.size(); + bool b = convert_shapes(map->MappedRepresentation(), shapes); + + for (size_t i = previous_size; i < shapes.size(); ++ i ) { + IfcGeom::CgalPlacement place(gtrsf); + shapes[i].prepend(&place); + + // Apply styles assigned to the mapped item only if on + // a more granular level no styles have been applied + if (!shapes[i].hasStyle()) { + shapes[i].setStyle(mapped_item_style); + } + } + + return b; +} + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal_shape_t &shape) { const double height = l->Depth() * getValue(GV_LENGTH_UNIT); if (height < getValue(GV_PRECISION)) { diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 56e43432c3..c6d8820c65 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -18,7 +18,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& return false; } - // TODO: Remove repeated points (and points that are too close to one another?) + // TODO: Remove repeated points and points that are too close to one another // remove_duplicate_points_from_loop(polygon, true); std::size_t count = polygon.size(); @@ -41,3 +41,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyLoop* l, cgal_wire_t& return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& result) { + IfcSchema::IfcCartesianPoint::list::ptr points = l->Points(); + + // Parse and store the points in a sequence + cgal_wire_t polygon = std::vector(); + for(IfcSchema::IfcCartesianPoint::list::it it = points->begin(); it != points->end(); ++ it) { + cgal_point_t pnt; + IfcGeom::CgalKernel::convert(*it, pnt); + polygon.push_back(pnt); + } + + // TODO: Remove points that are too close to one another + // remove_duplicate_points_from_loop(polygon, false); + + result = polygon; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 4e82272375..94021ae750 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -130,6 +130,8 @@ namespace IfcGeom { bool convert_wire(const IfcUtil::IfcBaseClass* L, cgal_wire_t& result); bool convert_curve(const IfcUtil::IfcBaseClass* L, cgal_curve_t& result); bool convert_face(const IfcUtil::IfcBaseClass* L, cgal_face_t& result); + + bool convert_wire_to_face(const cgal_wire_t& wire, cgal_face_t& face); // bool convert_openings(const IfcSchema::IfcProduct* entity, const IfcSchema::IfcRelVoidsElement::list::ptr& openings, const ConversionResults& entity_shapes, const gp_Trsf& entity_trsf, ConversionResults& cut_shapes); From 6297ff74f169bac61fc462720bf003552bbff0cb Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:11:11 -0600 Subject: [PATCH 03/11] Boolean ops using Nef polyhedra (untested) --- .../kernels/cgal/CgalConversionFunctions.cpp | 7 +- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 238 ++++++++++++++++++ src/ifcgeom/kernels/cgal/CgalKernel.h | 1 + 4 files changed, 246 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index b096b3408e..9573fdaa7a 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -25,14 +25,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRepresentation* l, Convers bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianPoint* l, cgal_point_t& point) { std::vector xyz = l->Coordinates(); - if (xyz.size() == 3) { + if (xyz.size() < 4) { point = Kernel::Point_3(xyz.size() ? (xyz[0]*getValue(GV_LENGTH_UNIT)) : 0.0f, xyz.size() > 1 ? (xyz[1]*getValue(GV_LENGTH_UNIT)) : 0.0f, xyz.size() > 2 ? (xyz[2]*getValue(GV_LENGTH_UNIT)) : 0.0f); // std::cout << "Converted Point(" << point << ")" << std::endl; return true; } else { - throw std::runtime_error("Point without 3 coordinates"); + std::cout << "Point("; + for (auto &coordinate: xyz) std::cout << coordinate << " "; + std::cout << ")"; + throw std::runtime_error("Could not parse point"); } } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 54efeb04ba..12c8224e20 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -40,6 +40,8 @@ SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); SHAPE(IfcCsgSolid); SHAPE(IfcBlock); +SHAPE(IfcBooleanResult); +SHAPE(IfcSphere); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 37c344e483..d16264bc0f 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -268,3 +268,241 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh shape = polyhedron; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_shape_t& shape) { + + cgal_shape_t s1, s2; + ConversionResults items1, items2; + cgal_wire_t boundary_wire; + IfcSchema::IfcBooleanOperand* operand1 = l->FirstOperand(); + IfcSchema::IfcBooleanOperand* operand2 = l->SecondOperand(); + bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); + + if ( shape_type(operand1) == ST_SHAPELIST ) { + std::cout << "ST_SHAPELIST" << std::endl; +// if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { + return false; +// } + } else if ( shape_type(operand1) == ST_SHAPE ) { + if ( ! convert_shape(operand1, s1) ) { + return false; + } +// TopoDS_Solid temp_solid; +// s1 = ensure_fit_for_subtraction(s1, temp_solid); + } else { + Logger::Message(Logger::LOG_ERROR, "s1: Invalid representation item for boolean operation", operand1->entity); + return false; + } + +// const double first_operand_volume = shape_volume(s1); +// if ( first_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",l->FirstOperand()->entity); + + bool shape2_processed = false; + if ( shape_type(operand2) == ST_SHAPELIST ) { + std::cout << "ST_SHAPELIST" << std::endl; +// shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); + } else if ( shape_type(operand2) == ST_SHAPE ) { + shape2_processed = convert_shape(operand2,s2); + if (shape2_processed && !is_halfspace) { +// TopoDS_Solid temp_solid; +// s2 = ensure_fit_for_subtraction(s2, temp_solid); + } + } else { + Logger::Message(Logger::LOG_ERROR, "s2: Invalid representation item for boolean operation", operand2->entity); + } + + if (!shape2_processed) { +// shape = s1; + Logger::Message(Logger::LOG_ERROR,"Failed to convert SecondOperand of:",l->entity); +// return true; + } + +// if (!is_halfspace) { +// const double second_operand_volume = shape_volume(s2); +// if ( second_operand_volume <= ALMOST_ZERO ) +// Logger::Message(Logger::LOG_WARNING,"Empty solid for:",operand2->entity); +// } + + const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + + CGAL::Nef_polyhedron_3 nef1(s1); + CGAL::Nef_polyhedron_3 nef2(s2); + + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + + CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); + shape = result; + return true; + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + + CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); + shape = result; + return true; + + } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + + CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + cgal_shape_t result; + nef_result.convert_to_polyhedron(result); + shape = result; + return true; + + } + + return false; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + + // Make icosahedron + float golden_ratio = (1.0+sqrtf(5.0))/2.0; + float normalising_factor = sqrtf(golden_ratio*golden_ratio+1.0); + std::vector icosahedron_vertices; + icosahedron_vertices.push_back(Kernel::Point_3(-1.0/normalising_factor, golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3( 1.0/normalising_factor, golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3(-1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3( 1.0/normalising_factor, -golden_ratio/normalising_factor, 0.0)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, -1.0/normalising_factor, golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, 1.0/normalising_factor, golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, -1.0/normalising_factor, -golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(0.0, 1.0/normalising_factor, -golden_ratio/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3( golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3( golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(-golden_ratio/normalising_factor, 0.0, -1.0/normalising_factor)); + icosahedron_vertices.push_back(Kernel::Point_3(-golden_ratio/normalising_factor, 0.0, 1.0/normalising_factor)); + + std::list face_list; + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[0]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[5]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[11]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[10]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[7]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[3]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[5]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[4]); + face_list.back().outer.push_back(icosahedron_vertices[11]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[2]); + face_list.back().outer.push_back(icosahedron_vertices[10]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[6]); + face_list.back().outer.push_back(icosahedron_vertices[7]); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(icosahedron_vertices[9]); + face_list.back().outer.push_back(icosahedron_vertices[8]); + face_list.back().outer.push_back(icosahedron_vertices[1]); + + // TODO: Refine icosahedron to create icosphere + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = Kernel::Point_3(vertex->point().x()*r, + vertex->point().y()*r, + vertex->point().z()*r).transform(trsf); + } + + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 94021ae750..748fd4fbb3 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -47,6 +47,7 @@ if ( it != cache.T.end() ) { e = it->second; return true; } #include #include #include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; From 82cd4056b7a825891a4239c07d05e9d59eefd2be Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:22:34 -0600 Subject: [PATCH 04/11] IfcRectangularPyramid --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 12c8224e20..20d363e13b 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -42,6 +42,7 @@ SHAPE(IfcCsgSolid); SHAPE(IfcBlock); SHAPE(IfcBooleanResult); SHAPE(IfcSphere); +SHAPE(IfcRectangularPyramid); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index d16264bc0f..ae969a8e13 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -260,7 +260,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh cgal_placement_t trsf; IfcGeom::CgalKernel::convert(l->Position(),trsf); - // IfcCsgPrimitive3D.Position has unit scale factor for (auto &vertex: vertices(polyhedron)) { vertex->point() = vertex->point().transform(trsf); } @@ -506,3 +505,62 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cgal_shape_t& shape) { + const double dx = l->XLength() * getValue(GV_LENGTH_UNIT); + const double dy = l->YLength() * getValue(GV_LENGTH_UNIT); + const double dz = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + // Base + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + + // Lateral faces + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(0, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, dy, 0)); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(dx, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, 0)); + face_list.back().outer.push_back(Kernel::Point_3(0.5*dx, 0.5*dy, dz)); + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From bece7053a001af99686db6bc249dd78915e8d545 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:39:18 -0600 Subject: [PATCH 05/11] IfcRightCircularCylinder --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 20d363e13b..0f66367e23 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -43,6 +43,7 @@ SHAPE(IfcBlock); SHAPE(IfcBooleanResult); SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); +SHAPE(IfcRightCircularCylinder); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index ae969a8e13..8b28f4abbb 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -564,3 +564,61 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga shape = polyhedron; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, cgal_shape_t& shape) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + const int segments = 10; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + // Side faces + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*3.141592653589793/((double)segments); + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), h)); + } + + // Top + face_list.push_back(cgal_face_t()); + for (int current_segment = segments-1; current_segment >= 0; --current_segment) { + double current_angle = current_segment*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From 302e7b2db86dacdf5fa7b74580f15cd5bdfd59e0 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 2 Mar 2017 18:42:10 -0600 Subject: [PATCH 06/11] IfcRightCircularCone --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 1 + .../kernels/cgal/CgalIfcGeomShapes.cpp | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 0f66367e23..afbb9db9f5 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -44,6 +44,7 @@ SHAPE(IfcBooleanResult); SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); +SHAPE(IfcRightCircularCone); FACE(IfcArbitraryClosedProfileDef); FACE(IfcFace); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 8b28f4abbb..71dd71432b 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -622,3 +622,53 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, shape = polyhedron; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal_shape_t& shape) { + const double r = l->BottomRadius() * getValue(GV_LENGTH_UNIT); + const double h = l->Height() * getValue(GV_LENGTH_UNIT); + + std::list face_list; + + const int segments = 10; + + // Base + face_list.push_back(cgal_face_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*3.141592653589793/((double)segments); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + // Side faces + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*3.141592653589793/((double)segments); + int next_segment = (current_segment+1)%segments; + double next_angle = next_segment*3.141592653589793/((double)segments); + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + face_list.back().outer.push_back(Kernel::Point_3(0, 0, h)); + } + + // Naive creation + cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); + } + // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + + cgal_placement_t trsf; + IfcGeom::CgalKernel::convert(l->Position(),trsf); + + for (auto &vertex: vertices(polyhedron)) { + vertex->point() = vertex->point().transform(trsf); + } + + shape = polyhedron; + return true; +} From 596c4f8b7750b4bb37822fcc3da9869a9473525f Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 09:58:17 -0600 Subject: [PATCH 07/11] Adding some validation code --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 71dd71432b..b0e710c084 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -142,7 +142,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; shape = polyhedron; @@ -254,7 +254,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -278,7 +278,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha bool is_halfspace = operand2->is(IfcSchema::Type::IfcHalfSpaceSolid); if ( shape_type(operand1) == ST_SHAPELIST ) { - std::cout << "ST_SHAPELIST" << std::endl; + Logger::Message(Logger::LOG_ERROR, "s1: ST_SHAPELIST Unsupported", operand1->entity); // if (!(convert_shapes(operand1, items1) && flatten_shape_list(items1, s1, true))) { return false; // } @@ -299,7 +299,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha bool shape2_processed = false; if ( shape_type(operand2) == ST_SHAPELIST ) { - std::cout << "ST_SHAPELIST" << std::endl; + Logger::Message(Logger::LOG_ERROR, "s2: ST_SHAPELIST Unsupported", operand1->entity); // shape2_processed = convert_shapes(operand2, items2) && flatten_shape_list(items2, s2, true); } else if ( shape_type(operand2) == ST_SHAPE ) { shape2_processed = convert_shape(operand2,s2); @@ -325,8 +325,19 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha const IfcSchema::IfcBooleanOperator::IfcBooleanOperator op = l->Operator(); + CGAL_precondition(s1.is_valid() && s1.is_closed()); CGAL::Nef_polyhedron_3 nef1(s1); + if (!nef1.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s1: Not simple Nef?", operand1->entity); + return false; + } + + CGAL_precondition(s2.is_valid() && s2.is_closed()); CGAL::Nef_polyhedron_3 nef2(s2); + if (!nef2.is_simple()) { + Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); + return false; + } if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { @@ -491,7 +502,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -551,7 +562,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -609,7 +620,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -659,7 +670,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } + } CGAL_postcondition(polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; From 7145b1ae85d7f56a45f74a3c9cfdade0007a0d3c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 12:58:52 -0600 Subject: [PATCH 08/11] Some debugging code, checking transformations --- .../kernels/cgal/CgalConversionFunctions.cpp | 6 +-- .../kernels/cgal/CgalIfcGeomShapes.cpp | 52 ++++++++++++++++--- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 9573fdaa7a..d0d6be43bc 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -53,7 +53,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) cgal_point_t o; cgal_direction_t axis = Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); IfcGeom::CgalKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( hasRef ) IfcGeom::CgalKernel::convert(l->RefDirection(),refDirection); @@ -62,7 +62,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_ Kernel::Vector_3 y = CGAL::cross_product(Kernel::Vector_3(0.0, 0.0, 1.0), refDirection); trsf = Kernel::Aff_transformation_3(refDirection.cartesian(0), y.cartesian(0), 0.0, o.cartesian(0), refDirection.cartesian(1), y.cartesian(1), 0.0, o.cartesian(1), - 0.0, y.cartesian(2), 1.0, 0.0); + 0.0, 0.0, 1.0, 0.0); // CACHE(IfcAxis2Placement3D,l,trsf) return true; @@ -72,7 +72,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement3D* l, cgal_ // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) cgal_point_t o; cgal_direction_t axis = Kernel::Vector_3(0,0,1); - cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); // TODO: Put identity for now. Check? + cgal_direction_t refDirection = Kernel::Vector_3(1,0,0); IfcGeom::CgalKernel::convert(l->Location(),o); bool hasRef = l->hasRefDirection(); if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index b0e710c084..87acdd4394 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -142,7 +142,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; shape = polyhedron; @@ -254,7 +254,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -339,27 +339,63 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha return false; } + std::ofstream f1; + f1.open("/Users/ken/Desktop/s1.off"); + f1 << s1 << std::endl; + f1.close(); + std::ofstream f2; + f2.open("/Users/ken/Desktop/s2.off"); + f2 << s2 << std::endl; + f2.close(); + if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { + std::cout << "Difference" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } cgal_shape_t result; nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { + std::cout << "Union" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } cgal_shape_t result; nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { + std::cout << "Intersection" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + if (!nef_result.is_simple()) { + std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; + return false; + } cgal_shape_t result; nef_result.convert_to_polyhedron(result); + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/result.off"); + fresult << result << std::endl; + fresult.close(); shape = result; return true; @@ -502,7 +538,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -562,7 +598,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -582,7 +618,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, std::list face_list; - const int segments = 10; + const int segments = 25; // Base face_list.push_back(cgal_face_t()); @@ -620,7 +656,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; @@ -640,7 +676,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal std::list face_list; - const int segments = 10; + const int segments = 25; // Base face_list.push_back(cgal_face_t()); @@ -670,7 +706,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal CGAL::Polygon_mesh_processing::stitch_borders(polyhedron); if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); - } CGAL_postcondition(polyhedron.is_closed()); + } CGAL_postcondition(polyhedron.is_valid() && polyhedron.is_closed()); // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; cgal_placement_t trsf; From c59ae03cb3beee36d6ef3d2a288349384234dbd7 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 13:12:05 -0600 Subject: [PATCH 09/11] Fixed bug in cylinders/cones --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 87acdd4394..7b0b5d173a 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -623,15 +623,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, // Base face_list.push_back(cgal_face_t()); for (int current_segment = 0; current_segment < segments; ++current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); } // Side faces for (int current_segment = 0; current_segment < segments; ++current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); int next_segment = (current_segment+1)%segments; - double next_angle = next_segment*3.141592653589793/((double)segments); + double next_angle = next_segment*2.0*3.141592653589793/((double)segments); face_list.push_back(cgal_face_t()); face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); @@ -642,7 +642,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, // Top face_list.push_back(cgal_face_t()); for (int current_segment = segments-1; current_segment >= 0; --current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), h)); } @@ -681,15 +681,15 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal // Base face_list.push_back(cgal_face_t()); for (int current_segment = 0; current_segment < segments; ++current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); } // Side faces for (int current_segment = 0; current_segment < segments; ++current_segment) { - double current_angle = current_segment*3.141592653589793/((double)segments); + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); int next_segment = (current_segment+1)%segments; - double next_angle = next_segment*3.141592653589793/((double)segments); + double next_angle = next_segment*2.0*3.141592653589793/((double)segments); face_list.push_back(cgal_face_t()); face_list.back().outer.push_back(Kernel::Point_3(r*cos(next_angle), r*sin(next_angle), 0)); face_list.back().outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); From efb8bce25aa6a95e07a3e3bb00aa33123056c34f Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 13:20:47 -0600 Subject: [PATCH 10/11] =?UTF-8?q?Didn=E2=80=99t=20save=20sphere=20output?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 7b0b5d173a..ec1c1d4170 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -550,6 +550,12 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s vertex->point().z()*r).transform(trsf); } +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/sphere.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + + shape = polyhedron; return true; } From bbe0b74f83a760db650f01d5064bc54f24f18fbe Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Fri, 3 Mar 2017 13:56:08 -0600 Subject: [PATCH 11/11] Boolean ops working? --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 97 ++++++++++++++----- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index ec1c1d4170..95fe301e15 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -339,18 +339,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha return false; } - std::ofstream f1; - f1.open("/Users/ken/Desktop/s1.off"); - f1 << s1 << std::endl; - f1.close(); - std::ofstream f2; - f2.open("/Users/ken/Desktop/s2.off"); - f2 << s2 << std::endl; - f2.close(); +// std::ofstream f1; +// f1.open("/Users/ken/Desktop/s1.off"); +// f1 << s1 << std::endl; +// f1.close(); +// std::ofstream f2; +// f2.open("/Users/ken/Desktop/s2.off"); +// f2 << s2 << std::endl; +// f2.close(); if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { - std::cout << "Difference" << std::endl; +// std::cout << "Difference" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -358,16 +358,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } cgal_shape_t result; nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { - std::cout << "Union" << std::endl; +// std::cout << "Union" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -375,16 +375,16 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } cgal_shape_t result; nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); shape = result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { - std::cout << "Intersection" << std::endl; +// std::cout << "Intersection" << std::endl; CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; if (!nef_result.is_simple()) { std::cout << "Not simple: " << nef_result.number_of_volumes() << " volumes" << std::endl; @@ -392,10 +392,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha } cgal_shape_t result; nef_result.convert_to_polyhedron(result); - std::ofstream fresult; - fresult.open("/Users/ken/Desktop/result.off"); - fresult << result << std::endl; - fresult.close(); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/result.off"); +// fresult << result << std::endl; +// fresult.close(); shape = result; return true; @@ -527,12 +527,63 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s face_list.back().outer.push_back(icosahedron_vertices[1]); // TODO: Refine icosahedron to create icosphere + const unsigned int refinements = 3; + for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { + std::list refined_face_list; + for (auto &face: face_list) { + Kernel::Point_3 vertex0 = face.outer[0]; + Kernel::Point_3 vertex1 = face.outer[1]; + Kernel::Point_3 vertex2 = face.outer[2]; + + Kernel::Point_3 midpoint01 = CGAL::midpoint(vertex0, vertex1); + Kernel::Point_3 midpoint12 = CGAL::midpoint(vertex1, vertex2); + Kernel::Point_3 midpoint20 = CGAL::midpoint(vertex2, vertex0); + + double midpoint01_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint01, Kernel::Point_3(0, 0, 0)))); + midpoint01 = Kernel::Point_3(midpoint01.x()/midpoint01_distance_to_origin, + midpoint01.y()/midpoint01_distance_to_origin, + midpoint01.z()/midpoint01_distance_to_origin); + double midpoint12_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint12, Kernel::Point_3(0, 0, 0)))); + midpoint12 = Kernel::Point_3(midpoint12.x()/midpoint12_distance_to_origin, + midpoint12.y()/midpoint12_distance_to_origin, + midpoint12.z()/midpoint12_distance_to_origin); + double midpoint20_distance_to_origin = sqrt(CGAL::to_double(CGAL::squared_distance(midpoint20, Kernel::Point_3(0, 0, 0)))); + midpoint20 = Kernel::Point_3(midpoint20.x()/midpoint20_distance_to_origin, + midpoint20.y()/midpoint20_distance_to_origin, + midpoint20.z()/midpoint20_distance_to_origin); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex0); + refined_face_list.back().outer.push_back(midpoint01); + refined_face_list.back().outer.push_back(midpoint20); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex1); + refined_face_list.back().outer.push_back(midpoint12); + refined_face_list.back().outer.push_back(midpoint01); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(vertex2); + refined_face_list.back().outer.push_back(midpoint20); + refined_face_list.back().outer.push_back(midpoint12); + + refined_face_list.push_back(cgal_face_t()); + refined_face_list.back().outer.push_back(midpoint01); + refined_face_list.back().outer.push_back(midpoint12); + refined_face_list.back().outer.push_back(midpoint20); + } face_list = refined_face_list; + } // Naive creation cgal_shape_t polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/sphere.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); + // Stitch edges // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; CGAL::Polygon_mesh_processing::stitch_borders(polyhedron);