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();