diff --git a/src/ifcgeom/IfcGeomFaces.cpp b/src/ifcgeom/IfcGeomFaces.cpp index 31e4a80e44..7adc9eb998 100644 --- a/src/ifcgeom/IfcGeomFaces.cpp +++ b/src/ifcgeom/IfcGeomFaces.cpp @@ -320,7 +320,7 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcArbitraryProfileDefWithVoids* bool IfcGeom::Kernel::convert(const IfcSchema::IfcRectangleProfileDef* l, TopoDS_Shape& 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 y = l->YDim() / 2.0f * getValue(GV_LENGTH_UNIT); if ( x < ALMOST_ZERO || y < ALMOST_ZERO ) { Logger::Message(Logger::LOG_NOTICE,"Skipping zero sized profile:",l->entity); diff --git a/src/ifcgeom/IfcGeomShapes.cpp b/src/ifcgeom/IfcGeomShapes.cpp index 16c90666e8..9abc58eeb9 100644 --- a/src/ifcgeom/IfcGeomShapes.cpp +++ b/src/ifcgeom/IfcGeomShapes.cpp @@ -74,6 +74,7 @@ #include #include #include +#include #include #include @@ -824,4 +825,112 @@ bool IfcGeom::Kernel::convert(const IfcSchema::IfcAdvancedBrep* l, TopoDS_Shape& return convert(l->Outer(), shape); } +bool IfcGeom::Kernel::convert(const IfcSchema::IfcTriangulatedFaceSet* l, TopoDS_Shape& 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(gp_Pnt(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::vector faces; + faces.reserve(indices.size()); + + 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 > points.size()) { + Logger::Message(Logger::LOG_ERROR, "Contents of CoordIndex out of bounds", l->entity); + return false; + } + + const gp_Pnt& a = points[tri[0] - 1]; // account for zero- vs + const gp_Pnt& b = points[tri[1] - 1]; // one-based indices in + const gp_Pnt& c = points[tri[2] - 1]; // c++ and express + + TopoDS_Wire wire = BRepBuilderAPI_MakePolygon(a, b, c, true).Wire(); + TopoDS_Face face = BRepBuilderAPI_MakeFace(wire).Face(); + + TopoDS_Iterator face_it(face, false); + const TopoDS_Wire& w = TopoDS::Wire(face_it.Value()); + const bool reversed = w.Orientation() == TopAbs_REVERSED; + if (reversed) { + face.Reverse(); + } + + if (face_area(face) > getValue(GV_MINIMAL_FACE_AREA)) { + faces.push_back(face); + } + } + + if (faces.empty()) return false; + + const unsigned int num_faces = indices.size(); + bool valid_shell = false; + + if (faces.size() < getValue(GV_MAX_FACES_TO_SEW)) { + BRepOffsetAPI_Sewing builder; + builder.SetTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + builder.SetMaxTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + builder.SetMinTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + + for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) { + builder.Add(*it); + } + + try { + builder.Perform(); + shape = builder.SewedShape(); + valid_shell = BRepCheck_Analyzer(shape).IsValid(); + } catch(...) {} + + if (valid_shell) { + try { + ShapeFix_Solid solid; + solid.LimitTolerance(getValue(GV_POINT_EQUALITY_TOLERANCE)); + TopoDS_Solid solid_shape = solid.SolidFromShell(TopoDS::Shell(shape)); + if (!solid_shape.IsNull()) { + try { + BRepClass3d_SolidClassifier classifier(solid_shape); + shape = solid_shape; + } catch (...) {} + } + } catch(...) {} + } else { + Logger::Message(Logger::LOG_WARNING, "Failed to sew faceset:", l->entity); + } + } + + if (!valid_shell) { + TopoDS_Compound compound; + BRep_Builder builder; + builder.MakeCompound(compound); + + for (std::vector::const_iterator it = faces.begin(); it != faces.end(); ++it) { + builder.Add(compound, *it); + } + + shape = compound; + } + + return true; +} + #endif diff --git a/src/ifcgeom/IfcRegister.h b/src/ifcgeom/IfcRegister.h index 9e09104ec3..dc231b2b40 100644 --- a/src/ifcgeom/IfcRegister.h +++ b/src/ifcgeom/IfcRegister.h @@ -54,6 +54,7 @@ SHAPE(IfcAdvancedBrep); // FIXME: Surfaces should have a shape type of their own SHAPE(IfcBSplineSurfaceWithKnots); SHAPE(IfcPlane); +SHAPE(IfcTriangulatedFaceSet); #endif SHAPE(IfcExtrudedAreaSolid); SHAPE(IfcRevolvedAreaSolid);