diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index d0d6be43bc..040b09bd59 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -152,3 +152,51 @@ bool IfcGeom::CgalKernel::convert_wire_to_face(const cgal_wire_t& wire, cgal_fac face.outer = wire; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3D* l, cgal_placement_t& trsf) { +// IN_CACHE(IfcCartesianTransformationOperator3D,l,gp_Trsf,trsf) + cgal_point_t origin; + IfcGeom::CgalKernel::convert(l->LocalOrigin(),origin); + cgal_direction_t axis1 (1.,0.,0.); + cgal_direction_t axis2 (0.,1.,0.); + cgal_direction_t axis3 (0.,0.,1.); + if ( l->hasAxis1() ) IfcGeom::CgalKernel::convert(l->Axis1(),axis1); + if ( l->hasAxis2() ) IfcGeom::CgalKernel::convert(l->Axis2(),axis2); + if ( l->hasAxis3() ) IfcGeom::CgalKernel::convert(l->Axis3(),axis3); + double scale = 1.0; + if (l->hasScale()) { + scale = l->Scale(); + } + + // TODO: Untested + trsf = Kernel::Aff_transformation_3(scale*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0), + axis1.cartesian(1), scale*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1), + axis1.cartesian(2), axis2.cartesian(2), scale*axis3.cartesian(2), origin.cartesian(2)); + +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << trsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } + +// CACHE(IfcCartesianTransformationOperator3D,l,trsf) + return true; +} + +void IfcGeom::CgalKernel::remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol) { + if (tol <= 0.) tol = getValue(GV_PRECISION); + tol *= tol; + + for (int i = 0; i < polygon.size(); ++i) { + for (int j = i+1; j < polygon.size(); ++j) { + if (CGAL::squared_distance(polygon[i], polygon[j]) < tol) { + polygon.erase(polygon.begin()+j); + --j; + } + } if (closed) { + if (CGAL::squared_distance(polygon.front(), polygon.back()) < tol) { + polygon.erase(polygon.begin()+polygon.size()-1); + } + } + } +} diff --git a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp index 59225e53f0..171b7ee2e8 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionResult.cpp @@ -7,42 +7,53 @@ void IfcGeom::CgalShape::Triangulate(const IfcGeom::IteratorSettings & settings, // std::cout << "Model: " << s.size_of_facets() << " facets and " << s.size_of_vertices() << " vertices" << std::endl; // std::cout << "Valid: " << s.is_valid() << std::endl; + CGAL::Polyhedron_3 polyhedron; + s.convert_to_polyhedron(polyhedron); + // Apply transformation - if (place != NULL) for (auto &vertex: vertices(s)) { + if (place != NULL) for (auto &vertex: vertices(polyhedron)) { vertex->point() = vertex->point().transform(trsf); } +// 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 face_normals; boost::associative_property_map> face_normals_map(face_normals); - if (CGAL::Polygon_mesh_processing::triangulate_faces(s)) { + if (CGAL::Polygon_mesh_processing::triangulate_faces(polyhedron)) { // 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"); return; } + +// 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); - - // Iterates over the faces of the shape - int num_faces = 0, num_vertices = 0; - for (auto &face: faces(s)) { + CGAL::Polygon_mesh_processing::compute_normals(polyhedron, vertex_normals_map, face_normals_map); + + for (auto &face: faces(polyhedron)) { + if (!face->is_triangle()) { + std::cout << "Warning: non-triangular face!" << std::endl; + continue; + } CGAL::Polyhedron_3::Halfedge_around_facet_const_circulator current_halfedge = face->facet_begin(); do { + t->faces().push_back((int)t->verts().size()/3); t->addVertex(surface_style_id, CGAL::to_double(current_halfedge->vertex()->point().cartesian(0)), CGAL::to_double(current_halfedge->vertex()->point().cartesian(1)), CGAL::to_double(current_halfedge->vertex()->point().cartesian(2))); for (int i = 0; i < 3; ++i) t->normals().push_back(CGAL::to_double(face_normals_map[face].cartesian(i))); - t->faces().push_back(num_vertices); - ++num_vertices; ++current_halfedge; } while (current_halfedge != face->facet_begin()); t->material_ids().push_back(surface_style_id); - ++num_faces; } - -// std::cout << num_faces << " faces" << std::endl; } diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index afbb9db9f5..b85f741966 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -35,6 +35,7 @@ SHAPES(IfcRepresentation); // IfcAdvancedBrepWithVoids included SHAPES(IfcManifoldSolidBrep); SHAPES(IfcMappedItem); +SHAPES(IfcFaceBasedSurfaceModel); SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcConnectedFaceSet); @@ -45,11 +46,20 @@ SHAPE(IfcSphere); SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); +SHAPE(IfcTriangulatedFaceSet); FACE(IfcArbitraryClosedProfileDef); +FACE(IfcCircleHollowProfileDef); +FACE(IfcCircleProfileDef); FACE(IfcFace); +FACE(IfcRoundedRectangleProfileDef); +FACE(IfcRectangleHollowProfileDef); FACE(IfcRectangleProfileDef); +FACE(IfcTrapeziumProfileDef); +FACE(IfcEllipseProfileDef); +WIRE(IfcEdgeLoop); +WIRE(IfcOrientedEdge); WIRE(IfcPolyLoop); WIRE(IfcPolyline); @@ -58,3 +68,4 @@ CLASS(IfcDirection,cgal_direction_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 7c4e64337f..9e8fe9fecf 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -24,9 +24,6 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg #ifdef USE_IFC4 has_position = l->hasPosition(); #endif - if (has_position) { - IfcGeom::CgalKernel::convert(l->Position(), trsf2d); - } face = cgal_face_t(); face.outer.push_back(Kernel::Point_3(-x, -y, 0.0)); @@ -34,6 +31,303 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleProfileDef* l, cg face.outer.push_back(Kernel::Point_3( x, y, 0.0)); face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRoundedRectangleProfileDef* 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); + const double r = l->RoundingRadius() * getValue(GV_LENGTH_UNIT); + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || r < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 3; + + if (r == 0.0) { + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-x, -y, 0.0)); + face.outer.push_back(Kernel::Point_3( x, -y, 0.0)); + face.outer.push_back(Kernel::Point_3( x, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + } + + else { + face = cgal_face_t(); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r+r*cos(current_angle), y-r+r*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r+r*cos(current_angle), y-r+r*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r+r*cos(current_angle), -y+r+r*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r+r*cos(current_angle), -y+r+r*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangleHollowProfileDef* 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); + const double d = l->WallThickness() * getValue(GV_LENGTH_UNIT); + + const bool fr1 = l->hasOuterFilletRadius(); + const bool fr2 = l->hasInnerFilletRadius(); + + const double r1 = fr1 ? l->OuterFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.; + const double r2 = fr2 ? l->InnerFilletRadius() * getValue(GV_LENGTH_UNIT) : 0.; + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 3; + + if (!fr1 || r1 == 0.0) { + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-x, -y, 0.0)); + face.outer.push_back(Kernel::Point_3( x, -y, 0.0)); + face.outer.push_back(Kernel::Point_3( x, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x, y, 0.0)); + } + + else { + face = cgal_face_t(); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r1+r1*cos(current_angle), y-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-r1+r1*cos(current_angle), -y+r1+r1*sin(current_angle), 0)); + } + } + + if (!fr2 || r2 == 0.0) { + face.inner.push_back(cgal_wire_t()); + face.inner.back().push_back(Kernel::Point_3(-x+d, -y+d, 0.0)); + face.inner.back().push_back(Kernel::Point_3( x-d, -y+d, 0.0)); + face.inner.back().push_back(Kernel::Point_3( x-d, y-d, 0.0)); + face.inner.back().push_back(Kernel::Point_3(-x+d, y-d, 0.0)); + } + + else { + face.inner.push_back(cgal_wire_t()); + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(x-d-r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(-x+d+r1+r1*cos(current_angle), y-d-r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(-x+d+r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0)); + } + for (int current_segment = 0; current_segment <= segments; ++current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3(x-d-r1+r1*cos(current_angle), -y+d+r1+r1*sin(current_angle), 0)); + } + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } for (auto &inner: face.inner) { + for (auto &vertex: inner) { + vertex = vertex.transform(trsf2d); + } + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTrapeziumProfileDef* l, cgal_face_t& face) { + const double x1 = l->BottomXDim() / 2.0f * getValue(GV_LENGTH_UNIT); + const double w = l->TopXDim() * getValue(GV_LENGTH_UNIT); + const double dx = l->TopXOffset() * getValue(GV_LENGTH_UNIT); + const double y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); + + if ( x1 < ALMOST_ZERO || w < ALMOST_ZERO || y < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + face = cgal_face_t(); + face.outer.push_back(Kernel::Point_3(-x1, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(x1, -y, 0.0)); + face.outer.push_back(Kernel::Point_3(dx+w-x1, y, 0.0)); + face.outer.push_back(Kernel::Point_3(dx-x1, y, 0.0)); + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleProfileDef* l, cgal_face_t& face) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + if ( r == 0.0f ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 12; + + face = cgal_face_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCircleHollowProfileDef* l, cgal_face_t& face) { + const double r = l->Radius() * getValue(GV_LENGTH_UNIT); + const double t = l->WallThickness() * getValue(GV_LENGTH_UNIT); + + if ( r == 0.0f || t == 0.0f ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 12; + + face = cgal_face_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(r*cos(current_angle), r*sin(current_angle), 0)); + } + + face.inner.push_back(cgal_wire_t()); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.inner.back().push_back(Kernel::Point_3((r-t)*cos(current_angle), (r-t)*sin(current_angle), 0)); + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } for (auto &inner: face.inner) { + for (auto &vertex: inner) { + vertex = vertex.transform(trsf2d); + } + } + } + + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEllipseProfileDef* l, cgal_face_t& face) { + double rx = l->SemiAxis1() * getValue(GV_LENGTH_UNIT); + double ry = l->SemiAxis2() * getValue(GV_LENGTH_UNIT); + + if ( rx < ALMOST_ZERO || ry < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 12; + + face = cgal_face_t(); + for (int current_segment = 0; current_segment < segments; ++current_segment) { + double current_angle = current_segment*2.0*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(rx*cos(current_angle), ry*sin(current_angle), 0)); + } + + if (has_position) { + IfcGeom::CgalKernel::convert(l->Position(), trsf2d); + for (auto &vertex: face.outer) { + vertex = vertex.transform(trsf2d); + } + } + return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp index 95fe301e15..f028fec103 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -43,8 +43,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR 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); + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); gtrsf = trsf; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { cgal_placement_t trsf_2d; @@ -84,6 +83,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR return b; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFaceBasedSurfaceModel* l, ConversionResults& shapes) { + bool part_success = false; + IfcSchema::IfcConnectedFaceSet::list::ptr facesets = l->FbsmFaces(); + const SurfaceStyle* collective_style = get_style(l); + for( IfcSchema::IfcConnectedFaceSet::list::it it = facesets->begin(); it != facesets->end(); ++ it ) { + cgal_shape_t s; + const SurfaceStyle* shell_style = get_style(*it); + if (convert_shape(*it,s)) { + shapes.push_back(ConversionResult(new CgalShape(s), shell_style ? shell_style : collective_style)); + part_success |= true; + } + } + return part_success; +} + 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)) { @@ -91,8 +105,10 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal return false; } - cgal_face_t face; - if ( !convert_face(l->SweptArea(),face) ) return false; + // Outer + cgal_face_t bottom_face; + if ( !convert_face(l->SweptArea(),bottom_face) ) return false; +// std::cout << "Face vertices: " << face.outer.size() << std::endl; cgal_placement_t trsf; bool has_position = true; @@ -108,15 +124,26 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // std::cout << "Direction: " << dir << std::endl; std::list face_list; - face_list.push_back(face); + face_list.push_back(bottom_face); - for (std::vector::const_iterator current_vertex = face.outer.begin(); - current_vertex != face.outer.end(); +// if (true) { +// cgal_shape_t polyhedron = CGAL::Polyhedron_3(); +// PolyhedronBuilder builder(&face_list); +// polyhedron.delegate(builder); +// +// std::ofstream fresult; +// fresult.open("/Users/ken/Desktop/profile.off"); +// fresult << polyhedron << std::endl; +// fresult.close(); +// } + + 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 == face.outer.end()) { - next_vertex = face.outer.begin(); + 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); @@ -126,26 +153,91 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal } cgal_face_t top_face; - for (std::vector::const_reverse_iterator vertex = face.outer.rbegin(); - vertex != face.outer.rend(); + 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); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 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 (!polyhedron.is_valid()) { + std::cout << "Invalid polyhedron!" << std::endl; + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/invalid.off"); + fresult << polyhedron << std::endl; + fresult.close(); + } + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(polyhedron)) { CGAL::Polygon_mesh_processing::reverse_face_orientations(polyhedron); } 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; + shape = CGAL::Nef_polyhedron_3(polyhedron); + + // 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; + 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); + + // Naive creation + CGAL::Polyhedron_3 hole_polyhedron = CGAL::Polyhedron_3(); + PolyhedronBuilder builder(&face_list); + hole_polyhedron.delegate(builder); + + // Stitch edges + // std::cout << "Before: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polygon_mesh_processing::stitch_borders(hole_polyhedron); + if (!hole_polyhedron.is_valid()) { + std::cout << "Invalid hole polyhedron!" << std::endl; + std::ofstream fresult; + fresult.open("/Users/ken/Desktop/invalid.off"); + fresult << hole_polyhedron << std::endl; + fresult.close(); + } + + if (!CGAL::Polygon_mesh_processing::is_outward_oriented(hole_polyhedron)) { + CGAL::Polygon_mesh_processing::reverse_face_orientations(hole_polyhedron); + } CGAL_postcondition(hole_polyhedron.is_valid() && hole_polyhedron.is_closed()); + // std::cout << "After: " << hole_polyhedron.size_of_vertices() << " vertices and " << hole_polyhedron.size_of_facets() << " facets" << std::endl; + + shape -= CGAL::Nef_polyhedron_3(hole_polyhedron); + } + return true; } @@ -175,7 +267,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -187,7 +279,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcConnectedFaceSet* l, cgal_ } // std::cout << "After: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -245,7 +337,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh face_list.back().outer.push_back(Kernel::Point_3(dx, 0, dz)); // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -264,7 +356,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBlock* l, cgal_shape_t& sh vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -325,16 +417,12 @@ 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()) { + if (!s1.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()) { + if (!s2.is_simple()) { Logger::Message(Logger::LOG_ERROR, "s2: Not simple Nef?", operand2->entity); return false; } @@ -351,52 +439,52 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcBooleanResult* l, cgal_sha if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_DIFFERENCE) { // std::cout << "Difference" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = nef1-nef2; + CGAL::Nef_polyhedron_3 nef_result = s1-s2; 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); +// 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; + shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_UNION) { // std::cout << "Union" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = nef1+nef2; + CGAL::Nef_polyhedron_3 nef_result = s1+s2; 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); +// 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; + shape = nef_result; return true; } else if (op == IfcSchema::IfcBooleanOperator::IfcBooleanOperator_INTERSECTION) { // std::cout << "Intersection" << std::endl; - CGAL::Nef_polyhedron_3 nef_result = nef1*nef2; + CGAL::Nef_polyhedron_3 nef_result = s1*s2; 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); +// 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; + shape = nef_result; return true; } @@ -526,8 +614,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s face_list.back().outer.push_back(icosahedron_vertices[8]); face_list.back().outer.push_back(icosahedron_vertices[1]); - // TODO: Refine icosahedron to create icosphere - const unsigned int refinements = 3; + const unsigned int refinements = 2; for (unsigned int current_refinement = 0; current_refinement < refinements; ++current_refinement) { std::list refined_face_list; for (auto &face: face_list) { @@ -575,7 +662,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -606,7 +693,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcSphere* l, cgal_shape_t& s // fresult << polyhedron << std::endl; // fresult.close(); - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -646,7 +733,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga 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(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -665,7 +752,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRectangularPyramid* l, cga vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -675,7 +762,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, std::list face_list; - const int segments = 25; + const int segments = 12; // Base face_list.push_back(cgal_face_t()); @@ -704,7 +791,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -723,7 +810,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCylinder* l, vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } @@ -733,7 +820,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal std::list face_list; - const int segments = 25; + const int segments = 12; // Base face_list.push_back(cgal_face_t()); @@ -754,7 +841,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal } // Naive creation - cgal_shape_t polyhedron = CGAL::Polyhedron_3(); + CGAL::Polyhedron_3 polyhedron = CGAL::Polyhedron_3(); PolyhedronBuilder builder(&face_list); polyhedron.delegate(builder); @@ -773,6 +860,68 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcRightCircularCone* l, cgal vertex->point() = vertex->point().transform(trsf); } - shape = polyhedron; + shape = CGAL::Nef_polyhedron_3(polyhedron); + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cgal_shape_t& shape) { + IfcSchema::IfcCartesianPointList3D* point_list = l->Coordinates(); + const std::vector< std::vector > coordinates = point_list->CoordList(); + std::vector points; + points.reserve(coordinates.size()); + for (std::vector< std::vector >::const_iterator it = coordinates.begin(); it != coordinates.end(); ++it) { + const std::vector& coords = *it; + if (coords.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on Coordinates", l->entity); + return false; + } + points.push_back(Kernel::Point_3(coords[0] * getValue(GV_LENGTH_UNIT), + coords[1] * getValue(GV_LENGTH_UNIT), + coords[2] * getValue(GV_LENGTH_UNIT))); + } + + std::vector< std::vector > indices = l->CoordIndex(); + + std::list face_list; + + for(std::vector< std::vector >::const_iterator it = indices.begin(); it != indices.end(); ++ it) { + const std::vector& tri = *it; + if (tri.size() != 3) { + Logger::Message(Logger::LOG_ERROR, "Invalid dimensions encountered on CoordIndex", l->entity); + return false; + } + + const int min_index = *std::min_element(tri.begin(), tri.end()); + const int max_index = *std::max_element(tri.begin(), tri.end()); + + if (min_index < 1 || max_index > (int) points.size()) { + Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l->entity); + return false; + } + + const Kernel::Point_3& a = points[tri[0] - 1]; // account for zero- vs + const Kernel::Point_3& b = points[tri[1] - 1]; // one-based indices in + const Kernel::Point_3& c = points[tri[2] - 1]; // c++ and express + + face_list.push_back(cgal_face_t()); + face_list.back().outer.push_back(a); + face_list.back().outer.push_back(b); + face_list.back().outer.push_back(c); + } + + // Naive creation + CGAL::Polyhedron_3 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); + } 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 = CGAL::Nef_polyhedron_3(polyhedron); return true; } diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index c6d8820c65..220b854930 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -18,8 +18,8 @@ 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 - // remove_duplicate_points_from_loop(polygon, true); + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon, true); std::size_t count = polygon.size(); if (original_count - count != 0) { @@ -53,9 +53,35 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPolyline* l, cgal_wire_t& polygon.push_back(pnt); } - // TODO: Remove points that are too close to one another - // remove_duplicate_points_from_loop(polygon, false); + // Remove points that are too close to one another + remove_duplicate_points_from_loop(polygon, false); result = polygon; return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcEdgeLoop* l, cgal_wire_t& result) { + IfcSchema::IfcOrientedEdge::list::ptr li = l->EdgeList(); + cgal_wire_t mw; + for (IfcSchema::IfcOrientedEdge::list::it it = li->begin(); it != li->end(); ++it) { + cgal_wire_t w; + if (convert_wire(*it, w)) { + // TODO: What to do here? Add some points only? +// mw.Add(TopoDS::Edge(TopoDS_Iterator(w).Value())); + return false; + } + } + result = mw; + return true; +} + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire_t& result) { + if (convert_wire(l->EdgeElement(), result)) { + if (!l->Orientation()) { + std::reverse(result.begin(),result.end()); + } + return true; + } else { + return false; + } +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index 748fd4fbb3..ada2fdd91c 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -62,7 +62,7 @@ struct cgal_face_t { std::vector inner; }; -typedef CGAL::Polyhedron_3 cgal_shape_t; +typedef CGAL::Nef_polyhedron_3 cgal_shape_t; typedef boost::graph_traits>::vertex_descriptor cgal_vertex_descriptor_t; typedef boost::graph_traits>::face_descriptor cgal_face_descriptor_t; @@ -133,6 +133,8 @@ namespace IfcGeom { 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); + + void remove_duplicate_points_from_loop(cgal_wire_t& polygon, bool closed, double tol = -1.); // 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);