diff --git a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp index 040b09bd59..eb6561c890 100644 --- a/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp +++ b/src/ifcgeom/kernels/cgal/CgalConversionFunctions.cpp @@ -49,6 +49,18 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcDirection* l, cgal_directi return true; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcPlane* pln, cgal_plane_t& plane) { +// IN_CACHE(IfcPlane,pln,gp_Pln,plane) + IfcSchema::IfcAxis2Placement3D* l = pln->Position(); + cgal_point_t o; + cgal_direction_t axis = Kernel::Vector_3(0,0,1); + IfcGeom::CgalKernel::convert(l->Location(),o); + if ( l->hasAxis() ) IfcGeom::CgalKernel::convert(l->Axis(),axis); + plane = Kernel::Plane_3(o, axis); +// CACHE(IfcPlane,pln,plane) + return true; +} + bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcAxis2Placement2D* l, cgal_placement_t& trsf) { // IN_CACHE(IfcAxis2Placement3D,l,gp_Trsf,trsf) cgal_point_t o; @@ -173,6 +185,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe 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)); +// std::cout << std::endl; // for (int i = 0; i < 3; ++i) { // for (int j = 0; j < 4; ++j) { // std::cout << trsf.cartesian(i, j) << " "; @@ -183,6 +196,35 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOpe return true; } +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCartesianTransformationOperator3DnonUniform* l, cgal_placement_t& gtrsf) { +// IN_CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gp_GTrsf,gtrsf) + 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); + const double scale1 = l->hasScale() ? l->Scale() : 1.0f; + const double scale2 = l->hasScale2() ? l->Scale2() : scale1; + const double scale3 = l->hasScale3() ? l->Scale3() : scale1; + + // TODO: Untested + gtrsf = Kernel::Aff_transformation_3(scale1*axis1.cartesian(0), axis2.cartesian(0), axis3.cartesian(0), origin.cartesian(0), + axis1.cartesian(1), scale2*axis2.cartesian(1), axis3.cartesian(1), origin.cartesian(1), + axis1.cartesian(2), axis2.cartesian(2), scale3*axis3.cartesian(2), origin.cartesian(2)); + +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << gtrsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } + +// CACHE(IfcCartesianTransformationOperator3DnonUniform,l,gtrsf) + 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; diff --git a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h index b85f741966..379d855231 100644 --- a/src/ifcgeom/kernels/cgal/CgalEntityMapping.h +++ b/src/ifcgeom/kernels/cgal/CgalEntityMapping.h @@ -47,6 +47,7 @@ SHAPE(IfcRectangularPyramid); SHAPE(IfcRightCircularCylinder); SHAPE(IfcRightCircularCone); SHAPE(IfcTriangulatedFaceSet); +SHAPE(IfcHalfSpaceSolid); FACE(IfcArbitraryClosedProfileDef); FACE(IfcCircleHollowProfileDef); @@ -57,15 +58,21 @@ FACE(IfcRectangleHollowProfileDef); FACE(IfcRectangleProfileDef); FACE(IfcTrapeziumProfileDef); FACE(IfcEllipseProfileDef); +FACE(IfcCShapeProfileDef); +FACE(IfcIShapeProfileDef); +FACE(IfcLShapeProfileDef); WIRE(IfcEdgeLoop); WIRE(IfcOrientedEdge); WIRE(IfcPolyLoop); WIRE(IfcPolyline); +WIRE(IfcCompositeCurve); CLASS(IfcCartesianPoint,cgal_point_t); CLASS(IfcDirection,cgal_direction_t); +CLASS(IfcPlane,cgal_plane_t); CLASS(IfcAxis2Placement2D,cgal_placement_t); CLASS(IfcAxis2Placement3D,cgal_placement_t); CLASS(IfcObjectPlacement,cgal_placement_t); CLASS(IfcCartesianTransformationOperator3D,cgal_placement_t); +CLASS(IfcCartesianTransformationOperator3DnonUniform,cgal_placement_t); diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp index 9e8fe9fecf..69e50cde35 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomFaces.cpp @@ -376,3 +376,282 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcFace* l, cgal_face_t& face return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCShapeProfileDef* l, cgal_face_t& face) { + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double x = l->Width() / 2.0f * getValue(GV_LENGTH_UNIT); + const double d1 = l->WallThickness() * getValue(GV_LENGTH_UNIT); + const double d2 = l->Girth() * getValue(GV_LENGTH_UNIT); + bool doFillet = l->hasInternalFilletRadius(); + double f1 = 0; + double f2 = 0; + if ( doFillet ) { + f1 = l->InternalFilletRadius() * getValue(GV_LENGTH_UNIT); + f2 = f1 + d1; + } + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || d2 < 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 (!doFillet || f1 == 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+d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, -y+d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, -y+d1, 0.0)); + face.outer.push_back(Kernel::Point_3(-x+d1, -y+d1, 0.0)); + face.outer.push_back(Kernel::Point_3(-x+d1, y-d1, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, y-d1, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, y-d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x, y-d2, 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 = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-x+f2+f2*cos(current_angle), -y+f2+f2*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-f2+f2*cos(current_angle), -y+f2+f2*sin(current_angle), 0)); + } + face.outer.push_back(Kernel::Point_3(x, -y+d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x-d1, -y+d2, 0.0)); + for (int current_segment = segments; current_segment >= 0; --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-f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0)); + } + for (int current_segment = segments; current_segment >= 0; --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+f2+f1*cos(current_angle), -y+f2+f1*sin(current_angle), 0)); + } + for (int current_segment = segments; current_segment >= 0; --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+f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0)); + } + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(x-f2+f1*cos(current_angle), y-f2+f1*sin(current_angle), 0)); + } + face.outer.push_back(Kernel::Point_3(x-d1, y-d2, 0.0)); + face.outer.push_back(Kernel::Point_3(x, y-d2, 0.0)); + 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-f2+f2*cos(current_angle), y-f2+f2*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+f2+f2*cos(current_angle), y-f2+f2*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::IfcLShapeProfileDef* l, cgal_face_t& face) { + const bool hasSlope = l->hasLegSlope(); + const bool doEdgeFillet = l->hasEdgeRadius(); + const bool doFillet = l->hasFilletRadius(); + + const double y = l->Depth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double x = (l->hasWidth() ? l->Width() : l->Depth()) / 2.0f * getValue(GV_LENGTH_UNIT); + const double d = l->Thickness() * getValue(GV_LENGTH_UNIT); + const double slope = hasSlope ? (l->LegSlope() * getValue(GV_PLANEANGLE_UNIT)) : 0.; + + double f1 = 0.0f; + double f2 = 0.0f; + if (doFillet) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + if ( doEdgeFillet) { + f2 = l->EdgeRadius() * getValue(GV_LENGTH_UNIT); + } + + if ( x < ALMOST_ZERO || y < ALMOST_ZERO || d < ALMOST_ZERO ) { + Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); + return false; + } + + double xx = -x+d; + double xy = -y+d; + double dy1 = 0.; + double dy2 = 0.; + double dx1 = 0.; + double dx2 = 0.; + if (hasSlope) { + dy1 = tan(slope) * x; + dy2 = tan(slope) * (x - d); + dx1 = tan(slope) * y; + dx2 = tan(slope) * (y - d); + + const double x1s = x; const double y1s = -y + d - dy1; + const double x1e = -x + d; const double y1e = -y + d + dy2; + const double x2s = -x + d - dx1; const double y2s = y; + const double x2e = -x + d + dx2; const double y2e = -y + d; + + const double a1 = y1e - y1s; + const double b1 = x1s - x1e; + const double c1 = a1*x1s + b1*y1s; + + const double a2 = y2e - y2s; + const double b2 = x2s - x2e; + const double c2 = a2*x2s + b2*y2s; + + const double det = a1*b2 - a2*b1; + + if (ALMOST_THE_SAME(det, 0.)) { + Logger::Message(Logger::LOG_NOTICE, "Legs do not intersect for:",l->entity); + return false; + } + + xx = (b2*c1 - b1*c2) / det; + xy = (a1*c2 - a2*c1) / det; + } + + cgal_placement_t trsf2d; + bool has_position = true; +#ifdef USE_IFC4 + has_position = l->hasPosition(); +#endif + + const int segments = 3; + + 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)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(x, -y+d-dy1, 0.0)); + } else { + 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-f2+f2*cos(current_angle), -y+d-dy1-f2+f2*sin(current_angle), 0)); + } + } if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(xx, xy, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(xx+f1+f1*cos(current_angle), xy+f1+f1*sin(current_angle), 0)); + } + } if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(-x+d-dx1, y, 0.0)); + } else { + 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+d-dx1-f2+f2*cos(current_angle), y-f2+f2*sin(current_angle), 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; +} + +// TODO: Untested +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcIShapeProfileDef* l, cgal_face_t& face) { + const double x1 = l->OverallWidth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double y = l->OverallDepth() / 2.0f * getValue(GV_LENGTH_UNIT); + const double d1 = l->WebThickness() / 2.0f * getValue(GV_LENGTH_UNIT); + const double dy1 = l->FlangeThickness() * getValue(GV_LENGTH_UNIT); + + bool doFillet1 = l->hasFilletRadius(); + double f1 = 0.; + if ( doFillet1 ) { + f1 = l->FilletRadius() * getValue(GV_LENGTH_UNIT); + } + + bool doFillet2 = doFillet1; + double x2 = x1, dy2 = dy1, f2 = f1; + + if (l->is(IfcSchema::Type::IfcAsymmetricIShapeProfileDef)) { + IfcSchema::IfcAsymmetricIShapeProfileDef* assym = (IfcSchema::IfcAsymmetricIShapeProfileDef*) l; + x2 = assym->TopFlangeWidth() / 2. * getValue(GV_LENGTH_UNIT); + doFillet2 = assym->hasTopFlangeFilletRadius(); + if (doFillet2) { + f2 = assym->TopFlangeFilletRadius() * getValue(GV_LENGTH_UNIT); + } + if (assym->hasTopFlangeThickness()) { + dy2 = assym->TopFlangeThickness() * getValue(GV_LENGTH_UNIT); + } + } + + if ( x1 < ALMOST_ZERO || x2 < ALMOST_ZERO || y < ALMOST_ZERO || d1 < ALMOST_ZERO || dy1 < ALMOST_ZERO || dy2 < 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; + + 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(x1, -y+dy1, 0.0)); + if (f1 == 0.0) { + face.outer.push_back(Kernel::Point_3(d1, -y+dy1, 0.0)); + face.outer.push_back(Kernel::Point_3(d1, y-dy2, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.0*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(d1+f1+f1*cos(current_angle), -y+dy1+f1+f1*sin(current_angle), 0)); + } for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 0.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(d1+f1+f1*cos(current_angle), y-dy2-f1+f1*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(x2, y-dy2, 0.0)); + face.outer.push_back(Kernel::Point_3(x2, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x2, y, 0.0)); + face.outer.push_back(Kernel::Point_3(-x2, y-dy2, 0.0)); + if (f2 == 0.0) { + face.outer.push_back(Kernel::Point_3(-d1, y-dy2, 0.0)); + face.outer.push_back(Kernel::Point_3(-d1, -y+dy1, 0.0)); + } else { + for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-d1-f2+f2*cos(current_angle), y-dy2-f2+f2*sin(current_angle), 0)); + } for (int current_segment = segments; current_segment >= 0; --current_segment) { + double current_angle = 1.5*3.141592653589793+current_segment*0.5*3.141592653589793/((double)segments); + face.outer.push_back(Kernel::Point_3(-d1-f2+f2*cos(current_angle), -y+dy1+f2+f2*sin(current_angle), 0)); + } + } face.outer.push_back(Kernel::Point_3(-x1, -y+dy1, 0.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 f028fec103..e419996de2 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomShapes.cpp @@ -36,8 +36,9 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR cgal_placement_t gtrsf; IfcSchema::IfcCartesianTransformationOperator* transform = l->MappingTarget(); if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator3DnonUniform) ) { + IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); -// IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3DnonUniform*)transform,gtrsf); + return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2DnonUniform) ) { Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); return false; @@ -45,6 +46,8 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR cgal_placement_t trsf; IfcGeom::CgalKernel::convert((IfcSchema::IfcCartesianTransformationOperator3D*)transform,trsf); gtrsf = trsf; +// Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); +// return false; } else if ( transform->is(IfcSchema::Type::IfcCartesianTransformationOperator2D) ) { cgal_placement_t trsf_2d; Logger::Message(Logger::LOG_ERROR, "Unsupported MappingTarget:", transform->entity); @@ -61,9 +64,17 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcMappedItem* l, ConversionR IfcGeom::CgalKernel::convert((IfcSchema::IfcAxis2Placement2D*)placement,trsf_2d); trsf = trsf_2d; } + // TODO: Check gtrsf = trsf * gtrsf; +// std::cout << std::endl; +// for (int i = 0; i < 3; ++i) { +// for (int j = 0; j < 4; ++j) { +// std::cout << gtrsf.cartesian(i, j) << " "; +// } std::cout << std::endl; +// } + const IfcGeom::SurfaceStyle* mapped_item_style = get_style(l); const size_t previous_size = shapes.size(); @@ -127,7 +138,7 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal face_list.push_back(bottom_face); // if (true) { -// cgal_shape_t polyhedron = CGAL::Polyhedron_3(); +// CGAL::Polyhedron_3 polyhedron; // PolyhedronBuilder builder(&face_list); // polyhedron.delegate(builder); // @@ -166,12 +177,13 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcExtrudedAreaSolid *l, cgal // Stitch edges // std::cout << "Before: " << polyhedron.size_of_vertices() << " vertices and " << polyhedron.size_of_facets() << " facets" << std::endl; + CGAL::Polyhedron_3 old_polyhedron(polyhedron); 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 << old_polyhedron << std::endl; fresult.close(); } @@ -925,3 +937,21 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, cg shape = CGAL::Nef_polyhedron_3(polyhedron); return true; } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcHalfSpaceSolid* l, cgal_shape_t& shape) { + IfcSchema::IfcSurface* surface = l->BaseSurface(); + if ( ! surface->is(IfcSchema::Type::IfcPlane) ) { + Logger::Message(Logger::LOG_ERROR, "Unsupported BaseSurface:", surface->entity); + return false; + } + cgal_plane_t pln; + IfcGeom::CgalKernel::convert((IfcSchema::IfcPlane*)surface,pln); + + // TODO: This might be the other way around? + if (!l->AgreementFlag()) pln = pln.opposite(); +// const gp_Pnt pnt = pln.Location().Translated( l->AgreementFlag() ? -pln.Axis().Direction() : pln.Axis().Direction()); +// shape = BRepPrimAPI_MakeHalfSpace(BRepBuilderAPI_MakeFace(pln),pnt).Solid(); + + shape = CGAL::Nef_polyhedron_3(pln); + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp index 220b854930..72ac78fa2d 100644 --- a/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp +++ b/src/ifcgeom/kernels/cgal/CgalIfcGeomWires.cpp @@ -85,3 +85,93 @@ bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcOrientedEdge* l, cgal_wire return false; } } + +bool IfcGeom::CgalKernel::convert(const IfcSchema::IfcCompositeCurve* l, cgal_wire_t& wire) { + if ( getValue(GV_PLANEANGLE_UNIT)<0 ) { + Logger::Message(Logger::LOG_WARNING,"Creating a composite curve without unit information:",l->entity); + + // Temporarily pretend we do have unit information + setValue(GV_PLANEANGLE_UNIT,1.0); + + bool succes_radians = false; + bool succes_degrees = false; + bool use_radians = false; + bool use_degrees = false; + + // First try radians + cgal_wire_t wire_radians, wire_degrees; + try { + succes_radians = IfcGeom::CgalKernel::convert(l,wire_radians); + } catch (...) {} + + // Now try degrees + setValue(GV_PLANEANGLE_UNIT,0.0174532925199433); + try { + succes_degrees = IfcGeom::CgalKernel::convert(l,wire_degrees); + } catch (...) {} + + // Restore to unknown unit state + setValue(GV_PLANEANGLE_UNIT,-1.0); + + if ( succes_degrees && ! succes_radians ) { + use_degrees = true; + } else if ( succes_radians && ! succes_degrees ) { + use_radians = true; + } else if ( succes_radians && succes_degrees ) { + if ( wire_degrees.back() == wire_degrees.front() && wire_radians.back() != wire_radians.front() ) { + use_degrees = true; + } else if ( wire_radians.back() == wire_radians.front() && wire_degrees.back() != wire_degrees.front() ) { + use_radians = true; + } else { + // No heuristic left to prefer the one over the other, + // apparently both variants are equally succesful. + // The curve might be composed of only straight segments. + // Let's go with the wire created using radians as that + // at least is a SI unit. + use_radians = true; + } + } + + if ( use_radians ) { + Logger::Message(Logger::LOG_NOTICE,"Used radians to create composite curve"); + wire = wire_radians; + } else if ( use_degrees ) { + Logger::Message(Logger::LOG_NOTICE,"Used degrees to create composite curve"); + wire = wire_degrees; + } + + return use_radians || use_degrees; + } + IfcSchema::IfcCompositeCurveSegment::list::ptr segments = l->Segments(); + cgal_wire_t w; + //TopoDS_Vertex last_vertex; + for( IfcSchema::IfcCompositeCurveSegment::list::it it = segments->begin(); it != segments->end(); ++ it ) { + IfcSchema::IfcCurve* curve = (*it)->ParentCurve(); + cgal_wire_t wire2; + if ( !convert_wire(curve,wire2) ) { + Logger::Message(Logger::LOG_ERROR,"Failed to convert curve:",curve->entity); + continue; + } + if ( ! (*it)->SameSense() ) std::reverse(wire2.begin(),wire2.end()); + + if (wire2.empty()) { + continue; + } else if (w.empty()) { + w = wire2; + } else if (w.back() == w.front()) { + std::vector::const_iterator vertex = wire2.begin(); + ++vertex; + while (vertex != wire2.end()) { + w.push_back(*vertex); + ++vertex; + } + } else { + for (auto &vertex: wire2) w.push_back(vertex); + } + } + + remove_duplicate_points_from_loop(w, false); + + wire = w; + return true; +} diff --git a/src/ifcgeom/kernels/cgal/CgalKernel.h b/src/ifcgeom/kernels/cgal/CgalKernel.h index ada2fdd91c..7a27ae854e 100644 --- a/src/ifcgeom/kernels/cgal/CgalKernel.h +++ b/src/ifcgeom/kernels/cgal/CgalKernel.h @@ -54,6 +54,7 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef Kernel::Aff_transformation_3 cgal_placement_t; typedef Kernel::Point_3 cgal_point_t; typedef Kernel::Vector_3 cgal_direction_t; +typedef Kernel::Plane_3 cgal_plane_t; typedef std::vector cgal_curve_t; typedef std::vector cgal_wire_t;