From 4a340027bf475dc7c81aae10b2da5fa6f8ea2aad Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 20:12:23 -0600 Subject: [PATCH 1/5] IfcExtrudedAreaSolidTapered (with problems?) --- src/ifcgeom/kernels/cgal/CgalEntityMapping.h | 2 +- .../kernels/cgal/CgalIfcGeomShapes.cpp | 127 +++++++++++++++++- 2 files changed, 126 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index 3dc4b9c95e..22f52e6f2d 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -44,7 +44,7 @@ SHAPES(IfcGeometricSet); //SHAPE(IfcAdvancedBrep); //SHAPE(IfcBSplineSurfaceWithKnots); SHAPE(IfcTriangulatedFaceSet); -//SHAPE(IfcExtrudedAreaSolidTapered); +SHAPE(IfcExtrudedAreaSolidTapered); #endif //SHAPE(IfcPlane); SHAPE(IfcExtrudedAreaSolid); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 4ad278c939..227d45825c 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -52,7 +52,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal if (bottom_face.inner.empty()) { shape = create_polyhedron(face_list); - for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); + if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } @@ -66,6 +66,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal 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(); @@ -93,11 +94,133 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal nef_shape -= create_nef_polyhedron(face_list); } - nef_shape.transform(trsf); + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + } + nef_shape.convert_to_polyhedron(shape); return true; } +#ifdef USE_IFC4 +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* l, cgal_shape_t& shape) { + const double height = l->Depth() * getValue(GV_LENGTH_UNIT); + if (height < getValue(GV_PRECISION)) { + Logger::Message(Logger::LOG_ERROR, "Non-positive extrusion height encountered for:", l->entity); + return false; + } + + cgal_face_t face1, face2; + if (!convert_face(l->SweptArea(), face1)) return false; + if (!convert_face(l->EndSweptArea(), face2)) return false; + + cgal_placement_t trsf; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf); + } + + cgal_direction_t dir; + convert(l->ExtrudedDirection(), dir); + + for (auto &vertex: face2.outer) vertex = vertex + height*dir; + for (auto &ring: face2.inner) { + for (auto &vertex: ring) vertex = vertex + height*dir; + } + + // Outer + std::list face_list; + face_list.push_back(face1); + face_list.push_back(face2); + + std::vector::const_iterator current_face1_vertex = face1.outer.begin(); + std::vector::const_iterator current_face2_vertex = face2.outer.begin(); + while (current_face1_vertex != face1.outer.end() && + current_face2_vertex != face2.outer.end()) { + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::const_iterator next_face2_vertex = current_face2_vertex; + ++next_face1_vertex; + ++next_face2_vertex; + if (next_face1_vertex == face1.outer.end()) next_face1_vertex = face1.outer.begin(); + if (next_face2_vertex == face2.outer.end()) next_face2_vertex = face2.outer.begin(); + cgal_face_t side_face; + side_face.outer.push_back(*next_face1_vertex); + side_face.outer.push_back(*current_face1_vertex); + side_face.outer.push_back(*current_face2_vertex); + side_face.outer.push_back(*next_face2_vertex); + face_list.push_back(side_face); + ++current_face1_vertex; + ++current_face2_vertex; + } + + if (face1.inner.empty() || face2.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 + std::vector::iterator inner_face1 = face1.inner.begin(); + std::vector::iterator inner_face2 = face2.inner.begin(); + while (inner_face1 != face1.inner.end() && + inner_face2 != face2.inner.end()) { + face_list.clear(); + + cgal_face_t hole_face1; + hole_face1.outer = *inner_face1; + remove_duplicate_points_from_loop(hole_face1.outer); + face_list.push_back(hole_face1); + + cgal_face_t hole_face2; + hole_face2.outer = *inner_face2; + remove_duplicate_points_from_loop(hole_face2.outer); + face_list.push_back(hole_face2); + + current_face1_vertex = hole_face1.outer.begin(); + current_face2_vertex = hole_face2.outer.begin(); + while (current_face1_vertex != hole_face1.outer.end() && + current_face2_vertex != hole_face2.outer.end()) { + std::vector::const_iterator next_face1_vertex = current_face1_vertex; + std::vector::const_iterator next_face2_vertex = current_face2_vertex; + ++next_face1_vertex; + ++next_face2_vertex; + if (next_face1_vertex == hole_face1.outer.end()) next_face1_vertex = hole_face1.outer.begin(); + if (next_face2_vertex == hole_face2.outer.end()) next_face2_vertex = hole_face2.outer.begin(); + cgal_face_t side_face; + side_face.outer.push_back(*next_face1_vertex); + side_face.outer.push_back(*current_face1_vertex); + side_face.outer.push_back(*current_face2_vertex); + side_face.outer.push_back(*next_face2_vertex); + face_list.push_back(side_face); + ++current_face1_vertex; + ++current_face2_vertex; + } + + nef_shape -= create_nef_polyhedron(face_list); + + ++inner_face1; + ++inner_face2; + } + + if (has_position) { + // IfcSweptAreaSolid.Position (trsf) is an IfcAxis2Placement3D + // and therefore has a unit scale factor + nef_shape.transform(trsf); + } + + nef_shape.convert_to_polyhedron(shape); + return true; +} +#endif + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_shape_t& shape) { IfcSchema::IfcFace::list::ptr faces = l->CfsFaces(); From c9267d7ace8584bca4997ad2bb1db8d38413d6cf Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Thu, 30 Mar 2017 21:11:05 -0600 Subject: [PATCH 2/5] Fixed orientation bug in tapered extrusions --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 227d45825c..e3264e78ec 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -136,7 +136,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* // Outer std::list face_list; face_list.push_back(face1); - face_list.push_back(face2); std::vector::const_iterator current_face1_vertex = face1.outer.begin(); std::vector::const_iterator current_face2_vertex = face2.outer.begin(); @@ -158,12 +157,27 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* ++current_face2_vertex; } + cgal_face_t top_face; + for (std::vector::const_reverse_iterator vertex = face2.outer.rbegin(); + vertex != face2.outer.rend(); + ++vertex) { + top_face.outer.push_back(*vertex); + } face_list.push_back(top_face); + if (face1.inner.empty() || face2.inner.empty()) { shape = create_polyhedron(face_list); if (has_position) for (auto &vertex: vertices(shape)) vertex->point() = vertex->point().transform(trsf); return true; } +// std::ofstream f1; +// CGAL::Polyhedron_3 outer_polyhedron; +// PolyhedronBuilder builder(&face_list); +// outer_polyhedron.delegate(builder); +// f1.open("/Users/ken/Desktop/outer.off"); +// f1 << outer_polyhedron << std::endl; +// f1.close(); + CGAL::Nef_polyhedron_3 nef_shape = create_nef_polyhedron(face_list); // Inner @@ -182,7 +196,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* cgal_face_t hole_face2; hole_face2.outer = *inner_face2; remove_duplicate_points_from_loop(hole_face2.outer); - face_list.push_back(hole_face2); current_face1_vertex = hole_face1.outer.begin(); current_face2_vertex = hole_face2.outer.begin(); @@ -204,6 +217,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* ++current_face2_vertex; } + cgal_face_t top_hole_face; + for (std::vector::const_reverse_iterator vertex = hole_face2.outer.rbegin(); + vertex != hole_face2.outer.rend(); + ++vertex) { + top_hole_face.outer.push_back(*vertex); + } face_list.push_back(top_hole_face); + +// std::ofstream f2; +// CGAL::Polyhedron_3 inner_polyhedron; +// PolyhedronBuilder builder(&face_list); +// inner_polyhedron.delegate(builder); +// f2.open("/Users/ken/Desktop/inner.off"); +// f2 << inner_polyhedron << std::endl; +// f2.close(); + nef_shape -= create_nef_polyhedron(face_list); ++inner_face1; From 248c73c2ab945b06924bf9fddc7e0c44faa1e82e Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 10 Apr 2017 18:53:28 -0500 Subject: [PATCH 3/5] Catch failures to convert Nef to Polyhedron_3 --- .../kernels/cgal/CgalIfcGeomShapes.cpp | 46 +++++++++++++++---- src/ifcgeom/kernels/cgal/CgalKernel.cpp | 12 ++++- 2 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index e3264e78ec..7b64a21321 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -100,8 +100,14 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal nef_shape.transform(trsf); } - nef_shape.convert_to_polyhedron(shape); - return true; + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcExtrudedAreaSolid: cannot convert Nef to polyhedron!" << std::endl; + return false; + } + } #ifdef USE_IFC4 @@ -244,8 +250,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolidTapered* nef_shape.transform(trsf); } - nef_shape.convert_to_polyhedron(shape); - return true; + try { + nef_shape.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcExtrudedAreaSolidTapered: cannot convert Nef to polyhedron!" << std::endl; + return false; + } } #endif @@ -458,8 +469,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } nef_result.convert_to_polyhedron(shape); - return true; + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { @@ -475,8 +491,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } nef_result.convert_to_polyhedron(shape); - return true; + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { @@ -492,8 +513,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha // fresult.open("/Users/ken/Desktop/result.off"); // fresult << result << std::endl; // fresult.close(); - } nef_result.convert_to_polyhedron(shape); - return true; + } try { + nef_result.convert_to_polyhedron(shape); + return true; + } catch (...) { + std::cout << "IfcBooleanResult: cannot convert Nef to polyhedron!" << std::endl; + return false; + } } return false; } diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.cpp b/src/ifcgeom/kernels/cgal/CgalKernel.cpp index 9c9512ceac..d13dab80ec 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.cpp +++ b/src/ifcgeom/kernels/cgal/CgalKernel.cpp @@ -300,8 +300,16 @@ bool IfcGeom::CgalKernel::convert_openings(const IfcSchema::IfcProduct* entity, } if (brep_cut_result.is_valid()) { - nef_brep_cut_result.convert_to_Polyhedron(brep_cut_result); - cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); + try { + nef_brep_cut_result.convert_to_polyhedron(brep_cut_result); + cut_shapes.push_back(IfcGeom::ConversionResult(new CgalShape(brep_cut_result), &it3->Style())); + } catch (...) { + // Apparently processing the boolean operation failed or resulted in an invalid result + // in which case the original shape without the subtractions is returned instead + // we try convert the openings in the original way, one by one. + Logger::Message(Logger::LOG_WARNING, "Subtracting combined openings compound failed:", entity->entity); + return false; + } } else { // Apparently processing the boolean operation failed or resulted in an invalid result // in which case the original shape without the subtractions is returned instead From 26bd03e4073b52b570ab77f13c58c96206df287c Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 10 Apr 2017 18:53:52 -0500 Subject: [PATCH 4/5] Ditto --- src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 69003d9aa1..c01c6e8576 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -45,9 +45,14 @@ CGAL::Polyhedron_3 IfcGeom::CgalKernel::create_polyhedron(std::list IfcGeom::CgalKernel::create_polyhedron(CGAL::Nef_polyhedron_3 &nef_polyhedron) { if (nef_polyhedron.is_simple()) { - CGAL::Polyhedron_3 polyhedron; - nef_polyhedron.convert_to_polyhedron(polyhedron); - return polyhedron; + try { + CGAL::Polyhedron_3 polyhedron; + nef_polyhedron.convert_to_polyhedron(polyhedron); + return polyhedron; + } catch (...) { + std::cout << "Conversion from Nef to polyhedron failed!" << std::endl; + return CGAL::Polyhedron_3(); + } } else { std::cout << "Nef polyhedron not simple: cannot create polyhedron!" << std::endl; return CGAL::Polyhedron_3(); From 9f2a617ad740995195711737da5e51826ae82124 Mon Sep 17 00:00:00 2001 From: Ken Arroyo Ohori Date: Mon, 10 Apr 2017 18:54:30 -0500 Subject: [PATCH 5/5] Catch a few nasty cases in triangulation, more efficient to only compute face normals --- .../kernels/cgal/CgalConversionResult.cpp | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index ba6e1fa5b2..8aa38cbee1 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -10,29 +10,52 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, vertex->point() = vertex->point().transform(trsf); } + if (!s.is_valid() || !s.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (before triangulation)"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s << std::endl; + ferror.close(); + return; + } + // std::ofstream fbefore; // fbefore.open("/Users/ken/Desktop/before.off"); // fbefore << s << std::endl; // fbefore.close(); // Triangulate the shape and compute the normals - std::map vertex_normals; - boost::associative_property_map> vertex_normals_map(vertex_normals); +// std::map vertex_normals; +// boost::associative_property_map> vertex_normals_map(vertex_normals); std::map face_normals; boost::associative_property_map> face_normals_map(face_normals); - if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { -// std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; - } else { - Logger::Message(Logger::LOG_ERROR, "Failed to triangulate shape"); + cgal_shape_t s_copy(s); + if (!CGAL::Polygon_mesh_processing::triangulate_faces(s) ) { + Logger::Message(Logger::LOG_ERROR, "Triangulation failed"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s << std::endl; + ferror.close(); return; } + // std::cout << "Triangulated model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; // std::ofstream fafter; // fafter.open("/Users/ken/Desktop/after.off"); // fafter << s << std::endl; // fafter.close(); - - CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + + if (!s.is_valid() || !s.is_closed()) { + Logger::Message(Logger::LOG_ERROR, "Invalid Polyhedron_3 in object (after triangulation)"); + std::ofstream ferror; + ferror.open("/Users/ken/Desktop/error.off"); + ferror << s_copy << std::endl; + ferror.close(); + return; + } + +// CGAL::Polygon_mesh_processing::compute_normals(s, vertex_normals_map, face_normals_map); + CGAL::Polygon_mesh_processing::compute_face_normals(s, face_normals_map); for (auto &face: faces(s)) { if (!face->is_triangle()) {