/*************************************************************************** * Copyright (c) Jürgen Riegel (juergen.riegel@web.de) 2002 * * * * This file is part of the FreeCAD CAx development system. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; see the file COPYING.LIB. If not, * * write to the Free Software Foundation, Inc., 59 Temple Place, * * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ #include "PreCompiled.h" #ifndef _PreComp_ # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include #endif # include # include # include # include # include # include # include # include # include # include # include # include #include #include #include #include #include #include "TopoShape.h" #include "CrossSection.h" #include "TopoShapeFacePy.h" #include "TopoShapeEdgePy.h" #include "TopoShapeVertexPy.h" #include "ProgressIndicator.h" #include "modelRefine.h" #include "Tools.h" #include "encodeFilename.h" using namespace Part; const char* BRepBuilderAPI_FaceErrorText(BRepBuilderAPI_FaceError et) { switch (et) { case BRepBuilderAPI_FaceDone: return "Construction was successful"; case BRepBuilderAPI_NoFace: return "No face"; case BRepBuilderAPI_NotPlanar: return "Face is not planar"; case BRepBuilderAPI_CurveProjectionFailed: return "Curve projection failed"; case BRepBuilderAPI_ParametersOutOfRange: return "Parameters out of range"; #if OCC_VERSION_HEX < 0x060500 case BRepBuilderAPI_SurfaceNotC2: return "Surface not C2-continous"; #endif default: return "Unknown creation error"; } } // ------------------------------------------------ TYPESYSTEM_SOURCE(Part::ShapeSegment , Data::Segment); std::string ShapeSegment::getName() const { return std::string(); } // ------------------------------------------------ TYPESYSTEM_SOURCE(Part::TopoShape , Data::ComplexGeoData); TopoShape::TopoShape() { } TopoShape::~TopoShape() { } TopoShape::TopoShape(const TopoDS_Shape& shape) : _Shape(shape) { } TopoShape::TopoShape(const TopoShape& shape) : _Shape(shape._Shape) { } std::vector TopoShape::getElementTypes(void) const { std::vector temp(3); temp.push_back("Vertex"); temp.push_back("Edge"); temp.push_back("Face"); return temp; } unsigned long TopoShape::countSubElements(const char* Type) const { return countSubShapes(Type); } Data::Segment* TopoShape::getSubElement(const char* Type, unsigned long n) const { std::stringstream str; str << Type << n; std::string temp = str.str(); return new ShapeSegment(getSubShape(temp.c_str())); } void TopoShape::getLinesFromSubelement(const Data::Segment* element, std::vector &Points, std::vector &lines) const { } void TopoShape::getFacesFromSubelement(const Data::Segment* element, std::vector &Points, std::vector &PointNormals, std::vector &faces) const { if (element->getTypeId() == ShapeSegment::getClassTypeId()) { const TopoDS_Shape& shape = static_cast(element)->Shape; if (shape.IsNull() || shape.ShapeType() != TopAbs_FACE) return; TopLoc_Location aLoc; // doing the meshing and checking the result Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(TopoDS::Face(shape),aLoc); if (aPoly.IsNull()) return; // geting the transformation of the shape/face gp_Trsf myTransf; Standard_Boolean identity = true; if (!aLoc.IsIdentity()) { identity = false; myTransf = aLoc.Transformation(); } Standard_Integer i; // geting size and create the array int nbNodesInFace = aPoly->NbNodes(); int nbTriInFace = aPoly->NbTriangles(); Points.resize(nbNodesInFace); PointNormals.resize(nbNodesInFace); // fills up already the array faces.resize(nbTriInFace); // check orientation TopAbs_Orientation orient = shape.Orientation(); // cycling through the poly mesh const Poly_Array1OfTriangle& Triangles = aPoly->Triangles(); const TColgp_Array1OfPnt& Nodes = aPoly->Nodes(); for (i=1; i<=nbTriInFace; i++) { // Get the triangle Standard_Integer N1,N2,N3; Triangles(i).Get(N1,N2,N3); // change orientation of the triangles if (orient != TopAbs_FORWARD) { Standard_Integer tmp = N1; N1 = N2; N2 = tmp; } gp_Pnt V1 = Nodes(N1); gp_Pnt V2 = Nodes(N2); gp_Pnt V3 = Nodes(N3); // transform the vertices to the place of the face if (!identity) { V1.Transform(myTransf); V2.Transform(myTransf); V3.Transform(myTransf); } // Calculate triangle normal gp_Vec v1(V1.X(),V1.Y(),V1.Z()),v2(V2.X(),V2.Y(),V2.Z()),v3(V3.X(),V3.Y(),V3.Z()); gp_Vec Normal = (v2-v1)^(v3-v1); //Standard_Real Area = 0.5 * Normal.Magnitude(); // add the triangle normal to the vertex normal for all points of this triangle PointNormals[N1-1] += Base::Vector3d(Normal.X(),Normal.Y(),Normal.Z()); PointNormals[N2-1] += Base::Vector3d(Normal.X(),Normal.Y(),Normal.Z()); PointNormals[N3-1] += Base::Vector3d(Normal.X(),Normal.Y(),Normal.Z()); Points[N1-1].Set(V1.X(),V1.Y(),V1.Z()); Points[N2-1].Set(V2.X(),V2.Y(),V2.Z()); Points[N3-1].Set(V3.X(),V3.Y(),V3.Z()); int j = i - 1; N1--; N2--; N3--; faces[j].I1 = N1; faces[j].I2 = N2; faces[j].I3 = N3; } // normalize all vertex normals for (i=0; i < nbNodesInFace; i++) { gp_Dir clNormal; try { Handle_Geom_Surface Surface = BRep_Tool::Surface(TopoDS::Face(shape)); gp_Pnt vertex(Base::convertTo(Points[i])); GeomAPI_ProjectPointOnSurf ProPntSrf(vertex, Surface); Standard_Real fU, fV; ProPntSrf.Parameters(1, fU, fV); GeomLProp_SLProps clPropOfFace(Surface, fU, fV, 2, gp::Resolution()); clNormal = clPropOfFace.Normal(); Base::Vector3d temp = Base::convertTo(clNormal); if (temp * Points[i] < 0) temp = -temp; Points[i] = temp; } catch (...) { } Points[i].Normalize(); } } } TopoDS_Shape TopoShape::getSubShape(const char* Type) const { if (!Type) Standard_Failure::Raise("No sub-shape type given"); if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot get sub-shape from empty shape"); std::string shapetype(Type); if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face") { int index=std::atoi(&shapetype[4]); TopTools_IndexedMapOfShape anIndices; TopExp::MapShapes(this->_Shape, TopAbs_FACE, anIndices); // To avoid a segmentation fault we have to check if container is empty if (anIndices.IsEmpty()) Standard_Failure::Raise("Shape has no faces"); return anIndices.FindKey(index); } else if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") { int index=std::atoi(&shapetype[4]); TopTools_IndexedMapOfShape anIndices; TopExp::MapShapes(this->_Shape, TopAbs_EDGE, anIndices); // To avoid a segmentation fault we have to check if container is empty if (anIndices.IsEmpty()) Standard_Failure::Raise("Shape has no edges"); return anIndices.FindKey(index); } else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex") { int index=std::atoi(&shapetype[6]); TopTools_IndexedMapOfShape anIndices; TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, anIndices); // To avoid a segmentation fault we have to check if container is empty if (anIndices.IsEmpty()) Standard_Failure::Raise("Shape has no vertexes"); return anIndices.FindKey(index); } Standard_Failure::Raise("Not supported sub-shape type"); return TopoDS_Shape(); // avoid compiler warning } unsigned long TopoShape::countSubShapes(const char* Type) const { std::string shapetype(Type); if (shapetype == "Face") { TopTools_IndexedMapOfShape anIndices; TopExp::MapShapes(this->_Shape, TopAbs_FACE, anIndices); return anIndices.Extent(); } else if (shapetype == "Edge") { TopTools_IndexedMapOfShape anIndices; TopExp::MapShapes(this->_Shape, TopAbs_EDGE, anIndices); return anIndices.Extent(); } else if (shapetype == "Vertex") { TopTools_IndexedMapOfShape anIndices; TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, anIndices); return anIndices.Extent(); } return 0; } PyObject * TopoShape::getPySubShape(const char* Type) const { // get the shape TopoDS_Shape Shape = getSubShape(Type); // destinquish the return type std::string shapetype(Type); if (shapetype.size() > 4 && shapetype.substr(0,4) == "Face") return new TopoShapeFacePy(new TopoShape(Shape)); else if (shapetype.size() > 4 && shapetype.substr(0,4) == "Edge") return new TopoShapeEdgePy(new TopoShape(Shape)); else if (shapetype.size() > 6 && shapetype.substr(0,6) == "Vertex") return new TopoShapeVertexPy(new TopoShape(Shape)); else return 0; } void TopoShape::operator = (const TopoShape& sh) { if (this != &sh) { this->_Shape = sh._Shape; } } void TopoShape::convertTogpTrsf(const Base::Matrix4D& mtrx, gp_Trsf& trsf) { trsf.SetValues(mtrx[0][0],mtrx[0][1],mtrx[0][2],mtrx[0][3], mtrx[1][0],mtrx[1][1],mtrx[1][2],mtrx[1][3], mtrx[2][0],mtrx[2][1],mtrx[2][2],mtrx[2][3] #if OCC_VERSION_HEX < 0x060800 , 0.00001,0.00001 #endif ); //precision was removed in OCCT CR0025194 } void TopoShape::convertToMatrix(const gp_Trsf& trsf, Base::Matrix4D& mtrx) { gp_Mat m = trsf._CSFDB_Getgp_Trsfmatrix(); gp_XYZ p = trsf._CSFDB_Getgp_Trsfloc(); Standard_Real scale = trsf._CSFDB_Getgp_Trsfscale(); // set Rotation matrix mtrx[0][0] = scale * m._CSFDB_Getgp_Matmatrix(0,0); mtrx[0][1] = scale * m._CSFDB_Getgp_Matmatrix(0,1); mtrx[0][2] = scale * m._CSFDB_Getgp_Matmatrix(0,2); mtrx[1][0] = scale * m._CSFDB_Getgp_Matmatrix(1,0); mtrx[1][1] = scale * m._CSFDB_Getgp_Matmatrix(1,1); mtrx[1][2] = scale * m._CSFDB_Getgp_Matmatrix(1,2); mtrx[2][0] = scale * m._CSFDB_Getgp_Matmatrix(2,0); mtrx[2][1] = scale * m._CSFDB_Getgp_Matmatrix(2,1); mtrx[2][2] = scale * m._CSFDB_Getgp_Matmatrix(2,2); // set pos vector mtrx[0][3] = p._CSFDB_Getgp_XYZx(); mtrx[1][3] = p._CSFDB_Getgp_XYZy(); mtrx[2][3] = p._CSFDB_Getgp_XYZz(); } void TopoShape::setTransform(const Base::Matrix4D& rclTrf) { gp_Trsf mov; convertTogpTrsf(rclTrf, mov); TopLoc_Location loc(mov); _Shape.Location(loc); } Base::Matrix4D TopoShape::getTransform(void) const { Base::Matrix4D mtrx; gp_Trsf Trf = _Shape.Location().Transformation(); convertToMatrix(Trf, mtrx); return mtrx; } void TopoShape::read(const char *FileName) { Base::FileInfo File(FileName); // checking on the file if (!File.isReadable()) throw Base::FileException("File to load not existing or not readable", FileName); if (File.hasExtension("igs") || File.hasExtension("iges")) { // read iges file importIges(File.filePath().c_str()); } else if (File.hasExtension("stp") || File.hasExtension("step")) { importStep(File.filePath().c_str()); } else if (File.hasExtension("brp") || File.hasExtension("brep")) { // read brep-file importBrep(File.filePath().c_str()); } else{ throw Base::Exception("Unknown extension"); } } /*! Example code to get the labels for each face in an IGES file. \code #include #include #include #include #include #include #include IGESControl_Reader aReader; ... // Gets the labels of all face items if defined in the IGES file Handle_XSControl_WorkSession ws = aReader.WS(); Handle_XSControl_TransferReader tr = ws->TransferReader(); std::string name; Handle(IGESData_IGESModel) aModel = aReader.IGESModel(); Standard_Integer all = aModel->NbEntities(); TopExp_Explorer ex; for (ex.Init(this->_Shape, TopAbs_FACE); ex.More(); ex.Next()) { const TopoDS_Face& aFace = TopoDS::Face(ex.Current()); Handle_Standard_Transient ent = tr->EntityFromShapeResult(aFace, 1); if (!ent.IsNull()) { int i = aModel->Number(ent); if (i > 0) { Handle_IGESData_IGESEntity ie = aModel->Entity(i); if (ie->HasShortLabel()) name = ie->ShortLabel()->ToCString(); } } } \endcode */ void TopoShape::importIges(const char *FileName) { try { // read iges file IGESControl_Controller::Init(); IGESControl_Reader aReader; // Ignore construction elements // http://www.opencascade.org/org/forum/thread_20603/?forum=3 aReader.SetReadVisible(Standard_True); if (aReader.ReadFile(encodeFilename(FileName).c_str()) != IFSelect_RetDone) throw Base::Exception("Error in reading IGES"); Handle_Message_ProgressIndicator pi = new ProgressIndicator(100); pi->NewScope(100, "Reading IGES file..."); pi->Show(); aReader.WS()->MapReader()->SetProgress(pi); // make brep aReader.ClearShapes(); aReader.TransferRoots(); // one shape that contains all subshapes this->_Shape = aReader.OneShape(); pi->EndScope(); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); throw Base::Exception(aFail->GetMessageString()); } } void TopoShape::importStep(const char *FileName) { try { STEPControl_Reader aReader; if (aReader.ReadFile(encodeFilename(FileName).c_str()) != IFSelect_RetDone) throw Base::Exception("Error in reading STEP"); Handle_Message_ProgressIndicator pi = new ProgressIndicator(100); aReader.WS()->MapReader()->SetProgress(pi); pi->NewScope(100, "Reading STEP file..."); pi->Show(); // Root transfers aReader.TransferRoots(); // one shape that contains all subshapes this->_Shape = aReader.OneShape(); pi->EndScope(); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); throw Base::Exception(aFail->GetMessageString()); } } void TopoShape::importBrep(const char *FileName) { try { // read brep-file BRep_Builder aBuilder; TopoDS_Shape aShape; #if OCC_VERSION_HEX >= 0x060300 Handle_Message_ProgressIndicator pi = new ProgressIndicator(100); pi->NewScope(100, "Reading BREP file..."); pi->Show(); BRepTools::Read(aShape,encodeFilename(FileName).c_str(),aBuilder,pi); pi->EndScope(); #else BRepTools::Read(aShape,(const Standard_CString)FileName,aBuilder); #endif this->_Shape = aShape; } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); throw Base::Exception(aFail->GetMessageString()); } } void TopoShape::importBrep(std::istream& str) { try { // read brep-file BRep_Builder aBuilder; TopoDS_Shape aShape; #if OCC_VERSION_HEX >= 0x060300 Handle_Message_ProgressIndicator pi = new ProgressIndicator(100); pi->NewScope(100, "Reading BREP file..."); pi->Show(); BRepTools::Read(aShape,str,aBuilder,pi); pi->EndScope(); #else BRepTools::Read(aShape,str,aBuilder); #endif this->_Shape = aShape; } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); throw Base::Exception(aFail->GetMessageString()); } catch (const std::exception& e) { throw Base::Exception(e.what()); } } void TopoShape::importBinary(std::istream& str) { BinTools_ShapeSet set; set.Read(str); Standard_Integer index; BinTools::GetInteger(str, index); try { this->_Shape = set.Shape(index); } catch (Standard_Failure) { throw Base::RuntimeError("Failed to read shape from binary stream"); } } void TopoShape::write(const char *FileName) const { Base::FileInfo File(FileName); if (File.hasExtension("igs") || File.hasExtension("iges")) { // write iges file exportIges(File.filePath().c_str()); } else if (File.hasExtension("stp") || File.hasExtension("step")) { exportStep(File.filePath().c_str()); } else if (File.hasExtension("brp") || File.hasExtension("brep")) { // read brep-file exportBrep(File.filePath().c_str()); } else if (File.hasExtension("stl")) { // read brep-file exportStl(File.filePath().c_str(),0); } else{ throw Base::Exception("Unknown extension"); } } void TopoShape::exportIges(const char *filename) const { try { // write iges file IGESControl_Controller::Init(); IGESControl_Writer aWriter; IGESData_GlobalSection header = aWriter.Model()->GlobalSection(); header.SetAuthorName(new TCollection_HAsciiString(Interface_Static::CVal("write.iges.header.author"))); header.SetCompanyName(new TCollection_HAsciiString(Interface_Static::CVal("write.iges.header.company"))); header.SetSendName(new TCollection_HAsciiString(Interface_Static::CVal("write.iges.header.product"))); aWriter.Model()->SetGlobalSection(header); aWriter.AddShape(this->_Shape); aWriter.ComputeModel(); if (aWriter.Write(encodeFilename(filename).c_str()) != IFSelect_RetDone) throw Base::Exception("Writing of IGES failed"); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); throw Base::Exception(aFail->GetMessageString()); } } void TopoShape::exportStep(const char *filename) const { try { // write step file STEPControl_Writer aWriter; Handle_Message_ProgressIndicator pi = new ProgressIndicator(100); aWriter.WS()->MapWriter()->SetProgress(pi); pi->NewScope(100, "Writing STEP file..."); pi->Show(); if (aWriter.Transfer(this->_Shape, STEPControl_AsIs) != IFSelect_RetDone) throw Base::Exception("Error in transferring STEP"); APIHeaderSection_MakeHeader makeHeader(aWriter.Model()); makeHeader.SetName(new TCollection_HAsciiString((const Standard_CString)(encodeFilename(filename).c_str()))); makeHeader.SetAuthorValue (1, new TCollection_HAsciiString("FreeCAD")); makeHeader.SetOrganizationValue (1, new TCollection_HAsciiString("FreeCAD")); makeHeader.SetOriginatingSystem(new TCollection_HAsciiString("FreeCAD")); makeHeader.SetDescriptionValue(1, new TCollection_HAsciiString("FreeCAD Model")); if (aWriter.Write(encodeFilename(filename).c_str()) != IFSelect_RetDone) throw Base::Exception("Writing of STEP failed"); pi->EndScope(); } catch (Standard_Failure) { Handle(Standard_Failure) aFail = Standard_Failure::Caught(); throw Base::Exception(aFail->GetMessageString()); } } void TopoShape::exportBrep(const char *filename) const { if (!BRepTools::Write(this->_Shape,encodeFilename(filename).c_str())) throw Base::Exception("Writing of BREP failed"); } void TopoShape::exportBrep(std::ostream& out) const { BRepTools::Write(this->_Shape, out); } void TopoShape::exportBinary(std::ostream& out) { BinTools_ShapeSet set; Standard_Integer index = set.Add(this->_Shape); set.Write(out); BinTools::PutInteger(out, index); } void TopoShape::dump(std::ostream& out) const { BRepTools::Dump(this->_Shape, out); } void TopoShape::exportStl(const char *filename, double deflection) const { StlAPI_Writer writer; #if OCC_VERSION_HEX < 0x060801 if (deflection > 0) { writer.RelativeMode() = false; writer.SetDeflection(deflection); } #else BRepMesh_IncrementalMesh aMesh(this->_Shape, deflection); #endif writer.Write(this->_Shape,encodeFilename(filename).c_str()); } void TopoShape::exportFaceSet(double dev, double ca, std::ostream& str) const { Base::InventorBuilder builder(str); TopExp_Explorer ex; BRepMesh_IncrementalMesh MESH(this->_Shape,dev); for (ex.Init(this->_Shape, TopAbs_FACE); ex.More(); ex.Next()) { // get the shape and mesh it const TopoDS_Face& aFace = TopoDS::Face(ex.Current()); Standard_Integer nbNodesInFace,nbTriInFace; std::vector vertices; std::vector indices; // doing the meshing and checking the result TopLoc_Location aLoc; Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation(aFace,aLoc); if (aPoly.IsNull()) continue; // getting the transformation of the shape/face gp_Trsf myTransf; Standard_Boolean identity = true; if (!aLoc.IsIdentity()) { identity = false; myTransf = aLoc.Transformation(); } // getting size and create the array nbNodesInFace = aPoly->NbNodes(); nbTriInFace = aPoly->NbTriangles(); vertices.resize(nbNodesInFace); indices.resize(4*nbTriInFace); // check orientation TopAbs_Orientation orient = aFace.Orientation(); // cycling through the poly mesh const Poly_Array1OfTriangle& Triangles = aPoly->Triangles(); const TColgp_Array1OfPnt& Nodes = aPoly->Nodes(); for (int i=1;i<=nbTriInFace;i++) { // Get the triangle Standard_Integer N1,N2,N3; Triangles(i).Get(N1,N2,N3); // change orientation of the triangles if (orient != TopAbs_FORWARD) { Standard_Integer tmp = N1; N1 = N2; N2 = tmp; } gp_Pnt V1 = Nodes(N1); gp_Pnt V2 = Nodes(N2); gp_Pnt V3 = Nodes(N3); // transform the vertices to the place of the face if (!identity) { V1.Transform(myTransf); V2.Transform(myTransf); V3.Transform(myTransf); } vertices[N1-1].Set((float)(V1.X()),(float)(V1.Y()),(float)(V1.Z())); vertices[N2-1].Set((float)(V2.X()),(float)(V2.Y()),(float)(V2.Z())); vertices[N3-1].Set((float)(V3.X()),(float)(V3.Y()),(float)(V3.Z())); int j = i - 1; N1--; N2--; N3--; indices[4*j] = N1; indices[4*j+1] = N2; indices[4*j+2] = N3; indices[4*j+3] = -1; } builder.addIndexedFaceSet(vertices, indices, (float)ca); } // end of face loop } void TopoShape::exportLineSet(std::ostream& str) const { Base::InventorBuilder builder(str); // get a indexed map of edges TopTools_IndexedMapOfShape M; TopExp::MapShapes(this->_Shape, TopAbs_EDGE, M); // build up map edge->face TopTools_IndexedDataMapOfShapeListOfShape edge2Face; TopExp::MapShapesAndAncestors(this->_Shape, TopAbs_EDGE, TopAbs_FACE, edge2Face); for (int i=0; i vertices; Standard_Integer nbNodesInFace; // triangulation succeeded? if (!aPoly.IsNull()) { if (!aLoc.IsIdentity()) { myTransf = aLoc.Transformation(); } nbNodesInFace = aPoly->NbNodes(); vertices.resize(nbNodesInFace); const TColgp_Array1OfPnt& Nodes = aPoly->Nodes(); gp_Pnt V; for (Standard_Integer i=0;i < nbNodesInFace;i++) { V = Nodes(i+1); V.Transform(myTransf); vertices[i].Set((float)(V.X()),(float)(V.Y()),(float)(V.Z())); } } else { // the edge has not its own triangulation, but then a face the edge is attached to // must provide this triangulation // Look for one face in our map (it doesn't care which one we take) const TopoDS_Face& aFace = TopoDS::Face(edge2Face.FindFromKey(aEdge).First()); // take the face's triangulation instead Handle(Poly_Triangulation) aPolyTria = BRep_Tool::Triangulation(aFace,aLoc); if (!aLoc.IsIdentity()) { myTransf = aLoc.Transformation(); } if (aPolyTria.IsNull()) break; // this holds the indices of the edge's triangulation to the actual points Handle(Poly_PolygonOnTriangulation) aPoly = BRep_Tool::PolygonOnTriangulation(aEdge, aPolyTria, aLoc); if (aPoly.IsNull()) continue; // polygon does not exist // getting size and create the array nbNodesInFace = aPoly->NbNodes(); vertices.resize(nbNodesInFace); const TColStd_Array1OfInteger& indices = aPoly->Nodes(); const TColgp_Array1OfPnt& Nodes = aPolyTria->Nodes(); gp_Pnt V; int pos = 0; // go through the index array for (Standard_Integer i=indices.Lower();i <= indices.Upper();i++) { V = Nodes(indices(i)); V.Transform(myTransf); vertices[pos++].Set((float)(V.X()),(float)(V.Y()),(float)(V.Z())); } } builder.addLineSet(vertices, 2, 0, 0, 0); } } Base::BoundBox3d TopoShape::getBoundBox(void) const { Base::BoundBox3d box; try { // If the shape is empty an exception may be thrown Bnd_Box bounds; BRepBndLib::Add(_Shape, bounds); bounds.SetGap(0.0); Standard_Real xMin, yMin, zMin, xMax, yMax, zMax; bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax); box.MinX = xMin; box.MaxX = xMax; box.MinY = yMin; box.MaxY = yMax; box.MinZ = zMin; box.MaxZ = zMax; } catch (Standard_Failure) { } return box; } void TopoShape::Save (Base::Writer & writer) const { } void TopoShape::Restore(Base::XMLReader &reader) { } void TopoShape::SaveDocFile (Base::Writer &writer) const { } void TopoShape::RestoreDocFile(Base::Reader &reader) { } unsigned int TopoShape_RefCountShapes(const TopoDS_Shape& aShape) { unsigned int size = 1; // this shape TopoDS_Iterator it; // go through all direct children for (it.Initialize(aShape, false, false);it.More(); it.Next()) { size += TopoShape_RefCountShapes(it.Value()); } return size; } unsigned int TopoShape::getMemSize (void) const { if (!_Shape.IsNull()) { // Count total amount of references of TopoDS_Shape objects unsigned int memsize = (sizeof(TopoDS_Shape)+sizeof(TopoDS_TShape)) * TopoShape_RefCountShapes(_Shape); // Now get a map of TopoDS_Shape objects without duplicates TopTools_IndexedMapOfShape M; TopExp::MapShapes(_Shape, M); for (int i=0; iDynamicType()->Size(); switch (shape.ShapeType()) { case TopAbs_FACE: { // first, last, tolerance memsize += 5*sizeof(Standard_Real); const TopoDS_Face& face = TopoDS::Face(shape); BRepAdaptor_Surface surface(face); switch (surface.GetType()) { case GeomAbs_Plane: memsize += sizeof(Geom_Plane); break; case GeomAbs_Cylinder: memsize += sizeof(Geom_CylindricalSurface); break; case GeomAbs_Cone: memsize += sizeof(Geom_ConicalSurface); break; case GeomAbs_Sphere: memsize += sizeof(Geom_SphericalSurface); break; case GeomAbs_Torus: memsize += sizeof(Geom_ToroidalSurface); break; case GeomAbs_BezierSurface: memsize += sizeof(Geom_BezierSurface); memsize += (surface.NbUPoles()*surface.NbVPoles()) * sizeof(Standard_Real); memsize += (surface.NbUPoles()*surface.NbVPoles()) * sizeof(Geom_CartesianPoint); break; case GeomAbs_BSplineSurface: memsize += sizeof(Geom_BSplineSurface); memsize += (surface.NbUKnots()+surface.NbVKnots()) * sizeof(Standard_Real); memsize += (surface.NbUPoles()*surface.NbVPoles()) * sizeof(Standard_Real); memsize += (surface.NbUPoles()*surface.NbVPoles()) * sizeof(Geom_CartesianPoint); break; case GeomAbs_SurfaceOfRevolution: memsize += sizeof(Geom_SurfaceOfRevolution); break; case GeomAbs_SurfaceOfExtrusion: memsize += sizeof(Geom_SurfaceOfLinearExtrusion); break; case GeomAbs_OtherSurface: // What kind of surface should this be? memsize += sizeof(Geom_Surface); break; default: break; } } break; case TopAbs_EDGE: { // first, last, tolerance memsize += 3*sizeof(Standard_Real); const TopoDS_Edge& edge = TopoDS::Edge(shape); BRepAdaptor_Curve curve(edge); switch (curve.GetType()) { case GeomAbs_Line: memsize += sizeof(Geom_Line); break; case GeomAbs_Circle: memsize += sizeof(Geom_Circle); break; case GeomAbs_Ellipse: memsize += sizeof(Geom_Ellipse); break; case GeomAbs_Hyperbola: memsize += sizeof(Geom_Hyperbola); break; case GeomAbs_Parabola: memsize += sizeof(Geom_Parabola); break; case GeomAbs_BezierCurve: memsize += sizeof(Geom_BezierCurve); memsize += curve.NbPoles() * sizeof(Standard_Real); memsize += curve.NbPoles() * sizeof(Geom_CartesianPoint); break; case GeomAbs_BSplineCurve: memsize += sizeof(Geom_BSplineCurve); memsize += curve.NbKnots() * sizeof(Standard_Real); memsize += curve.NbPoles() * sizeof(Standard_Real); memsize += curve.NbPoles() * sizeof(Geom_CartesianPoint); break; case GeomAbs_OtherCurve: // What kind of curve should this be? memsize += sizeof(Geom_Curve); break; default: break; } } break; case TopAbs_VERTEX: { // tolerance memsize += sizeof(Standard_Real); memsize += sizeof(Geom_CartesianPoint); } break; default: break; } } // estimated memory usage return memsize; } // in case the shape is invalid return sizeof(TopoDS_Shape); } bool TopoShape::isNull() const { return this->_Shape.IsNull() ? true : false; } bool TopoShape::isValid() const { BRepCheck_Analyzer aChecker(this->_Shape); return aChecker.IsValid() ? true : false; } bool TopoShape::analyze(std::ostream& str) const { if (!this->_Shape.IsNull()) { BRepCheck_Analyzer aChecker(this->_Shape); if (!aChecker.IsValid()) { std::vector shapes; TopTools_IndexedMapOfShape vertexOfShape; TopExp::MapShapes(this->_Shape, TopAbs_VERTEX, vertexOfShape); for (int i = 1; i <= vertexOfShape.Extent();++i) shapes.push_back(vertexOfShape(i)); TopTools_IndexedMapOfShape edgeOfShape; TopExp::MapShapes(this->_Shape, TopAbs_EDGE, edgeOfShape); for (int i = 1; i <= edgeOfShape.Extent();++i) shapes.push_back(edgeOfShape(i)); TopTools_IndexedMapOfShape wireOfShape; TopExp::MapShapes(this->_Shape, TopAbs_WIRE, wireOfShape); for (int i = 1; i <= wireOfShape.Extent();++i) shapes.push_back(wireOfShape(i)); TopTools_IndexedMapOfShape faceOfShape; TopExp::MapShapes(this->_Shape, TopAbs_FACE, faceOfShape); for (int i = 1; i <= faceOfShape.Extent();++i) shapes.push_back(faceOfShape(i)); TopTools_IndexedMapOfShape shellOfShape; TopExp::MapShapes(this->_Shape, TopAbs_SHELL, shellOfShape); for (int i = 1; i <= shellOfShape.Extent();++i) shapes.push_back(shellOfShape(i)); TopTools_IndexedMapOfShape solidOfShape; TopExp::MapShapes(this->_Shape, TopAbs_SOLID, solidOfShape); for (int i = 1; i <= solidOfShape.Extent();++i) shapes.push_back(solidOfShape(i)); TopTools_IndexedMapOfShape compOfShape; TopExp::MapShapes(this->_Shape, TopAbs_COMPOUND, compOfShape); for (int i = 1; i <= compOfShape.Extent();++i) shapes.push_back(compOfShape(i)); TopTools_IndexedMapOfShape compsOfShape; TopExp::MapShapes(this->_Shape, TopAbs_COMPSOLID, compsOfShape); for (int i = 1; i <= compsOfShape.Extent();++i) shapes.push_back(compsOfShape(i)); for (std::vector::iterator xp = shapes.begin(); xp != shapes.end(); ++xp) { if (!aChecker.IsValid(*xp)) { const Handle_BRepCheck_Result& result = aChecker.Result(*xp); if (result.IsNull()) continue; const BRepCheck_ListOfStatus& status = result->StatusOnShape(*xp); BRepCheck_ListIteratorOfListOfStatus it(status); while (it.More()) { BRepCheck_Status& val = it.Value(); switch (val) { case BRepCheck_NoError: str << "No error" << std::endl; break; case BRepCheck_InvalidPointOnCurve: str << "Invalid point on curve" << std::endl; break; case BRepCheck_InvalidPointOnCurveOnSurface: str << "Invalid point on curve on surface" << std::endl; break; case BRepCheck_InvalidPointOnSurface: str << "Invalid point on surface" << std::endl; break; case BRepCheck_No3DCurve: str << "No 3D curve" << std::endl; break; case BRepCheck_Multiple3DCurve: str << "Multiple 3D curve" << std::endl; break; case BRepCheck_Invalid3DCurve: str << "Invalid 3D curve" << std::endl; break; case BRepCheck_NoCurveOnSurface: str << "No curve on surface" << std::endl; break; case BRepCheck_InvalidCurveOnSurface: str << "Invalid curve on surface" << std::endl; break; case BRepCheck_InvalidCurveOnClosedSurface: str << "Invalid curve on closed surface" << std::endl; break; case BRepCheck_InvalidSameRangeFlag: str << "Invalid same-range flag" << std::endl; break; case BRepCheck_InvalidSameParameterFlag: str << "Invalid same-parameter flag" << std::endl; break; case BRepCheck_InvalidDegeneratedFlag: str << "Invalid degenerated flag" << std::endl; break; case BRepCheck_FreeEdge: str << "Free edge" << std::endl; break; case BRepCheck_InvalidMultiConnexity: str << "Invalid multi-connexity" << std::endl; break; case BRepCheck_InvalidRange: str << "Invalid range" << std::endl; break; case BRepCheck_EmptyWire: str << "Empty wire" << std::endl; break; case BRepCheck_RedundantEdge: str << "Redundant edge" << std::endl; break; case BRepCheck_SelfIntersectingWire: str << "Self-intersecting wire" << std::endl; break; case BRepCheck_NoSurface: str << "No surface" << std::endl; break; case BRepCheck_InvalidWire: str << "Invalid wires" << std::endl; break; case BRepCheck_RedundantWire: str << "Redundant wires" << std::endl; break; case BRepCheck_IntersectingWires: str << "Intersecting wires" << std::endl; break; case BRepCheck_InvalidImbricationOfWires: str << "Invalid imbrication of wires" << std::endl; break; case BRepCheck_EmptyShell: str << "Empty shell" << std::endl; break; case BRepCheck_RedundantFace: str << "Redundant face" << std::endl; break; case BRepCheck_UnorientableShape: str << "Unorientable shape" << std::endl; break; case BRepCheck_NotClosed: str << "Not closed" << std::endl; break; case BRepCheck_NotConnected: str << "Not connected" << std::endl; break; case BRepCheck_SubshapeNotInShape: str << "Sub-shape not in shape" << std::endl; break; case BRepCheck_BadOrientation: str << "Bad orientation" << std::endl; break; case BRepCheck_BadOrientationOfSubshape: str << "Bad orientation of sub-shape" << std::endl; break; case BRepCheck_InvalidToleranceValue: str << "Invalid tolerance value" << std::endl; break; case BRepCheck_CheckFail: str << "Check failed" << std::endl; break; default: str << "Undetermined error" << std::endl; break; } it.Next(); } } } return false; // errors detected } } return true; } bool TopoShape::isClosed() const { return BRep_Tool::IsClosed(this->_Shape) ? true : false; } TopoDS_Shape TopoShape::cut(TopoDS_Shape shape) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Base shape is null"); if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Cut mkCut(this->_Shape, shape); return mkCut.Shape(); } TopoDS_Shape TopoShape::common(TopoDS_Shape shape) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Base shape is null"); if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Common mkCommon(this->_Shape, shape); return mkCommon.Shape(); } TopoDS_Shape TopoShape::fuse(TopoDS_Shape shape) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Base shape is null"); if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Fuse mkFuse(this->_Shape, shape); return mkFuse.Shape(); } TopoDS_Shape TopoShape::multiFuse(const std::vector& shapes, Standard_Real tolerance) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Base shape is null"); #if OCC_VERSION_HEX <= 0x060800 if (tolerance > 0.0) Standard_Failure::Raise("Fuzzy Booleans are not supported in this version of OCCT"); TopoDS_Shape resShape = this->_Shape; if (resShape.IsNull()) throw Base::Exception("Object shape is null"); for (std::vector::const_iterator it = shapes.begin(); it != shapes.end(); ++it) { if (it->IsNull()) throw Base::Exception("Input shape is null"); // Let's call algorithm computing a fuse operation: BRepAlgoAPI_Fuse mkFuse(resShape, *it); // Let's check if the fusion has been successful if (!mkFuse.IsDone()) throw Base::Exception("Fusion failed"); resShape = mkFuse.Shape(); } #else BRepAlgoAPI_Fuse mkFuse; TopTools_ListOfShape shapeArguments,shapeTools; shapeArguments.Append(this->_Shape); for (std::vector::const_iterator it = shapes.begin(); it != shapes.end(); ++it) { if (it->IsNull()) throw Base::Exception("Tool shape is null"); if (tolerance > 0.0) // workaround for http://dev.opencascade.org/index.php?q=node/1056#comment-520 shapeTools.Append(BRepBuilderAPI_Copy(*it).Shape()); else shapeTools.Append(*it); } mkFuse.SetArguments(shapeArguments); mkFuse.SetTools(shapeTools); if (tolerance > 0.0) mkFuse.SetFuzzyValue(tolerance); mkFuse.Build(); if (!mkFuse.IsDone()) throw Base::Exception("MultiFusion failed"); TopoDS_Shape resShape = mkFuse.Shape(); #endif return resShape; } TopoDS_Shape TopoShape::oldFuse(TopoDS_Shape shape) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Base shape is null"); if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgo_Fuse mkFuse(this->_Shape, shape); return mkFuse.Shape(); } TopoDS_Shape TopoShape::section(TopoDS_Shape shape) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Base shape is null"); if (shape.IsNull()) Standard_Failure::Raise("Tool shape is null"); BRepAlgoAPI_Section mkSection(this->_Shape, shape); return mkSection.Shape(); } std::list TopoShape::slice(const Base::Vector3d& dir, double d) const { CrossSection cs(dir.x, dir.y, dir.z, this->_Shape); return cs.slice(d); } TopoDS_Compound TopoShape::slices(const Base::Vector3d& dir, const std::vector& d) const { std::vector< std::list > wire_list; CrossSection cs(dir.x, dir.y, dir.z, this->_Shape); for (std::vector::const_iterator jt = d.begin(); jt != d.end(); ++jt) { wire_list.push_back(cs.slice(*jt)); } std::vector< std::list >::const_iterator ft; TopoDS_Compound comp; BRep_Builder builder; builder.MakeCompound(comp); for (ft = wire_list.begin(); ft != wire_list.end(); ++ft) { const std::list& w = *ft; for (std::list::const_iterator wt = w.begin(); wt != w.end(); ++wt) { if (!wt->IsNull()) builder.Add(comp, *wt); } } return comp; } TopoDS_Shape TopoShape::makePipe(const TopoDS_Shape& profile) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); if (this->_Shape.ShapeType() != TopAbs_WIRE) Standard_Failure::Raise("Spine shape is not a wire"); if (profile.IsNull()) Standard_Failure::Raise("Cannot sweep empty profile"); BRepOffsetAPI_MakePipe mkPipe(TopoDS::Wire(this->_Shape), profile); return mkPipe.Shape(); } TopoDS_Shape TopoShape::makePipeShell(const TopTools_ListOfShape& profiles, const Standard_Boolean make_solid, const Standard_Boolean isFrenet, int transition) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); if (this->_Shape.ShapeType() != TopAbs_WIRE) Standard_Failure::Raise("Spine shape is not a wire"); BRepOffsetAPI_MakePipeShell mkPipeShell(TopoDS::Wire(this->_Shape)); BRepBuilderAPI_TransitionMode transMode; switch (transition) { case 1: transMode = BRepBuilderAPI_RightCorner; break; case 2: transMode = BRepBuilderAPI_RoundCorner; break; default: transMode = BRepBuilderAPI_Transformed; break; } mkPipeShell.SetMode(isFrenet); mkPipeShell.SetTransitionMode(transMode); TopTools_ListIteratorOfListOfShape it; for (it.Initialize(profiles); it.More(); it.Next()) { mkPipeShell.Add(TopoDS_Shape(it.Value())); } if (!mkPipeShell.IsReady()) Standard_Failure::Raise("shape is not ready to build"); else mkPipeShell.Build(); if (make_solid) mkPipeShell.MakeSolid(); return mkPipeShell.Shape(); } #if 0 TopoDS_Shape TopoShape::makeTube() const { // http://opencascade.blogspot.com/2009/11/surface-modeling-part3.html if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); if (this->_Shape.ShapeType() != TopAbs_EDGE) Standard_Failure::Raise("Spine shape is not an edge"); const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); BRepAdaptor_Curve path_adapt(path_edge); double umin = path_adapt.FirstParameter(); double umax = path_adapt.LastParameter(); Handle_Geom_Curve hPath = path_adapt.Curve().Curve(); // Apply placement of the shape to the curve TopLoc_Location loc1 = path_edge.Location(); hPath = Handle_Geom_Curve::DownCast(hPath->Transformed(loc1.Transformation())); if (hPath.IsNull()) Standard_Failure::Raise("Invalid curve in path edge"); GeomFill_Pipe mkTube(hPath, radius); mkTube.Perform(tol, Standard_False, GeomAbs_C1, BSplCLib::MaxDegree(), 1000); const Handle_Geom_Surface& surf = mkTube.Surface(); double u1,u2,v1,v2; surf->Bounds(u1,u2,v1,v2); BRepBuilderAPI_MakeFace mkBuilder(surf, umin, umax, v1, v2 #if OCC_VERSION_HEX >= 0x060502 , Precision::Confusion() #endif ); return mkBuilder.Face(); } #else static Handle(Law_Function) CreateBsFunction (const Standard_Real theFirst, const Standard_Real theLast, const Standard_Real theRadius) { //Handle_Law_BSpline aBs; //Handle_Law_BSpFunc aFunc = new Law_BSpFunc (aBs, theFirst, theLast); Handle_Law_Constant aFunc = new Law_Constant(); aFunc->Set(1, theFirst, theLast); return aFunc; } TopoDS_Shape TopoShape::makeTube(double radius, double tol, int cont, int maxdegree, int maxsegm) const { // http://opencascade.blogspot.com/2009/11/surface-modeling-part3.html Standard_Real theTol = tol; Standard_Real theRadius = radius; //Standard_Boolean theIsPolynomial = Standard_True; Standard_Boolean myIsElem = Standard_True; GeomAbs_Shape theContinuity = GeomAbs_Shape(cont); Standard_Integer theMaxDegree = maxdegree; Standard_Integer theMaxSegment = maxsegm; if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); Handle(Adaptor3d_HCurve) myPath; if (this->_Shape.ShapeType() == TopAbs_EDGE) { const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); BRepAdaptor_Curve path_adapt(path_edge); myPath = new BRepAdaptor_HCurve(path_adapt); } //else if (this->_Shape.ShapeType() == TopAbs_WIRE) { // const TopoDS_Wire& path_wire = TopoDS::Wire(this->_Shape); // BRepAdaptor_CompCurve path_adapt(path_wire); // myPath = new BRepAdaptor_HCompCurve(path_adapt); //} //else { // Standard_Failure::Raise("Spine shape is neither an edge nor a wire"); //} else { Standard_Failure::Raise("Spine shape is not an edge"); } //circular profile Handle(Geom_Circle) aCirc = new Geom_Circle (gp::XOY(), theRadius); aCirc->Rotate (gp::OZ(), M_PI/2.); //perpendicular section Handle(Law_Function) myEvol = ::CreateBsFunction (myPath->FirstParameter(), myPath->LastParameter(), theRadius); Handle(GeomFill_SectionLaw) aSec = new GeomFill_EvolvedSection(aCirc, myEvol); Handle(GeomFill_LocationLaw) aLoc = new GeomFill_CurveAndTrihedron(new GeomFill_CorrectedFrenet); aLoc->SetCurve (myPath); GeomFill_Sweep mkSweep (aLoc, myIsElem); mkSweep.SetTolerance (theTol); mkSweep.Build (aSec, GeomFill_Location, theContinuity, theMaxDegree, theMaxSegment); if (mkSweep.IsDone()) { Handle_Geom_Surface mySurface = mkSweep.Surface(); //Standard_Real myError = mkSweep.ErrorOnSurface(); Standard_Real u1,u2,v1,v2; mySurface->Bounds(u1,u2,v1,v2); BRepBuilderAPI_MakeFace mkBuilder(mySurface, u1, u2, v1, v2 #if OCC_VERSION_HEX >= 0x060502 , Precision::Confusion() #endif ); return mkBuilder.Shape(); } return TopoDS_Shape(); } #endif TopoDS_Shape TopoShape::makeSweep(const TopoDS_Shape& profile, double tol, int fillMode) const { // http://opencascade.blogspot.com/2009/10/surface-modeling-part2.html if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot sweep along empty spine"); if (this->_Shape.ShapeType() != TopAbs_EDGE) Standard_Failure::Raise("Spine shape is not an edge"); if (profile.IsNull()) Standard_Failure::Raise("Cannot sweep with empty profile"); if (profile.ShapeType() != TopAbs_EDGE) Standard_Failure::Raise("Profile shape is not an edge"); const TopoDS_Edge& path_edge = TopoDS::Edge(this->_Shape); const TopoDS_Edge& prof_edge = TopoDS::Edge(profile); BRepAdaptor_Curve path_adapt(path_edge); double umin = path_adapt.FirstParameter(); double umax = path_adapt.LastParameter(); Handle_Geom_Curve hPath = path_adapt.Curve().Curve(); // Apply placement of the shape to the curve TopLoc_Location loc1 = path_edge.Location(); hPath = Handle_Geom_Curve::DownCast(hPath->Transformed(loc1.Transformation())); if (hPath.IsNull()) Standard_Failure::Raise("invalid curve in path edge"); BRepAdaptor_Curve prof_adapt(prof_edge); double vmin = prof_adapt.FirstParameter(); double vmax = prof_adapt.LastParameter(); Handle_Geom_Curve hProfile = prof_adapt.Curve().Curve(); // Apply placement of the shape to the curve TopLoc_Location loc2 = prof_edge.Location(); hProfile = Handle_Geom_Curve::DownCast(hProfile->Transformed(loc2.Transformation())); if (hProfile.IsNull()) Standard_Failure::Raise("invalid curve in profile edge"); GeomFill_Pipe mkSweep(hPath, hProfile, (GeomFill_Trihedron)fillMode); mkSweep.GenerateParticularCase(Standard_True); mkSweep.Perform(tol, Standard_False, GeomAbs_C1, BSplCLib::MaxDegree(), 1000); const Handle_Geom_Surface& surf = mkSweep.Surface(); BRepBuilderAPI_MakeFace mkBuilder(surf, umin, umax, vmin, vmax #if OCC_VERSION_HEX >= 0x060502 , Precision::Confusion() #endif ); return mkBuilder.Face(); } TopoDS_Shape TopoShape::makeHelix(Standard_Real pitch, Standard_Real height, Standard_Real radius, Standard_Real angle, Standard_Boolean leftHanded, Standard_Boolean newStyle) const { if (pitch < Precision::Confusion()) Standard_Failure::Raise("Pitch of helix too small"); if (height < Precision::Confusion()) Standard_Failure::Raise("Height of helix too small"); gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); Handle_Geom_Surface surf; if (angle < Precision::Confusion()) { if (radius < Precision::Confusion()) Standard_Failure::Raise("Radius of helix too small"); surf = new Geom_CylindricalSurface(cylAx2, radius); } else { angle = Base::toRadians(angle); if (angle < Precision::Confusion()) Standard_Failure::Raise("Angle of helix too small"); surf = new Geom_ConicalSurface(gp_Ax3(cylAx2), angle, radius); } gp_Pnt2d aPnt(0, 0); gp_Dir2d aDir(2. * M_PI, pitch); Standard_Real coneDir = 1.0; if (leftHanded) { aDir.SetCoord(-2. * M_PI, pitch); coneDir = -1.0; } gp_Ax2d aAx2d(aPnt, aDir); Handle(Geom2d_Line) line = new Geom2d_Line(aAx2d); gp_Pnt2d beg = line->Value(0); gp_Pnt2d end = line->Value(sqrt(4.0*M_PI*M_PI+pitch*pitch)*(height/pitch)); if (newStyle) { // See discussion at 0001247: Part Conical Helix Height/Pitch Incorrect if (angle >= Precision::Confusion()) { // calculate end point for conical helix Standard_Real v = height / cos(angle); Standard_Real u = coneDir * (height/pitch) * 2.0 * M_PI; gp_Pnt2d cend(u, v); end = cend; } } Handle(Geom2d_TrimmedCurve) segm = GCE2d_MakeSegment(beg , end); TopoDS_Edge edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edgeOnSurf); BRepLib::BuildCurves3d(wire); return wire; } //*********** // makeLongHelix is a workaround for an OCC problem found in helices with more than // some magic number of turns. See Mantis #0954. //*********** TopoDS_Shape TopoShape::makeLongHelix(Standard_Real pitch, Standard_Real height, Standard_Real radius, Standard_Real angle, Standard_Boolean leftHanded) const { if (pitch < Precision::Confusion()) Standard_Failure::Raise("Pitch of helix too small"); if (height < Precision::Confusion()) Standard_Failure::Raise("Height of helix too small"); gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); Handle_Geom_Surface surf; Standard_Boolean isCylinder; if (angle < Precision::Confusion()) { // Cylindrical helix if (radius < Precision::Confusion()) Standard_Failure::Raise("Radius of helix too small"); surf= new Geom_CylindricalSurface(cylAx2, radius); isCylinder = true; } else { // Conical helix angle = Base::toRadians(angle); if (angle < Precision::Confusion()) Standard_Failure::Raise("Angle of helix too small"); surf = new Geom_ConicalSurface(gp_Ax3(cylAx2), angle, radius); isCylinder = false; } Standard_Real turns = height/pitch; unsigned long wholeTurns = floor(turns); Standard_Real partTurn = turns - wholeTurns; gp_Pnt2d aPnt(0, 0); gp_Dir2d aDir(2. * M_PI, pitch); Standard_Real coneDir = 1.0; if (leftHanded) { aDir.SetCoord(-2. * M_PI, pitch); coneDir = -1.0; } gp_Ax2d aAx2d(aPnt, aDir); Handle(Geom2d_Line) line = new Geom2d_Line(aAx2d); gp_Pnt2d beg = line->Value(0); gp_Pnt2d end; Standard_Real u,v; BRepBuilderAPI_MakeWire mkWire; Handle(Geom2d_TrimmedCurve) segm; TopoDS_Edge edgeOnSurf; for (unsigned long i = 0; i < wholeTurns; i++) { if (isCylinder) { end = line->Value(sqrt(4.0*M_PI*M_PI+pitch*pitch)*(i+1)); } else { u = coneDir * (i+1) * 2.0 * M_PI; v = ((i+1) * pitch) / cos(angle); end = gp_Pnt2d(u, v); } segm = GCE2d_MakeSegment(beg , end); edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); mkWire.Add(edgeOnSurf); beg = end; } if (partTurn > Precision::Confusion()) { if (isCylinder) { end = line->Value(sqrt(4.0*M_PI*M_PI+pitch*pitch)*turns); } else { u = coneDir * turns * 2.0 * M_PI; v = height / cos(angle); end = gp_Pnt2d(u, v); } segm = GCE2d_MakeSegment(beg , end); edgeOnSurf = BRepBuilderAPI_MakeEdge(segm , surf); mkWire.Add(edgeOnSurf); } TopoDS_Wire wire = mkWire.Wire(); BRepLib::BuildCurves3d(wire); return wire; } TopoDS_Shape TopoShape::makeThread(Standard_Real pitch, Standard_Real depth, Standard_Real height, Standard_Real radius) const { if (pitch < Precision::Confusion()) Standard_Failure::Raise("Pitch of thread too small"); if (depth < Precision::Confusion()) Standard_Failure::Raise("Depth of thread too small"); if (height < Precision::Confusion()) Standard_Failure::Raise("Height of thread too small"); if (radius < Precision::Confusion()) Standard_Failure::Raise("Radius of thread too small"); //Threading : Create Surfaces gp_Ax2 cylAx2(gp_Pnt(0.0,0.0,0.0) , gp::DZ()); Handle(Geom_CylindricalSurface) aCyl1 = new Geom_CylindricalSurface(cylAx2 , radius); Handle(Geom_CylindricalSurface) aCyl2 = new Geom_CylindricalSurface(cylAx2 , radius+depth); //Threading : Define 2D Curves gp_Pnt2d aPnt(2. * M_PI , height / 2.); gp_Dir2d aDir(2. * M_PI , height / 4.); gp_Ax2d aAx2d(aPnt , aDir); Standard_Real aMajor = 2. * M_PI; Standard_Real aMinor = pitch; Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(aAx2d , aMajor , aMinor); Handle(Geom2d_Ellipse) anEllipse2 = new Geom2d_Ellipse(aAx2d , aMajor , aMinor / 4); Handle(Geom2d_TrimmedCurve) aArc1 = new Geom2d_TrimmedCurve(anEllipse1 , 0 , M_PI); Handle(Geom2d_TrimmedCurve) aArc2 = new Geom2d_TrimmedCurve(anEllipse2 , 0 , M_PI); gp_Pnt2d anEllipsePnt1 = anEllipse1->Value(0); gp_Pnt2d anEllipsePnt2 = anEllipse1->Value(M_PI); Handle(Geom2d_TrimmedCurve) aSegment = GCE2d_MakeSegment(anEllipsePnt1 , anEllipsePnt2); //Threading : Build Edges and Wires TopoDS_Edge aEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(aArc1 , aCyl1); TopoDS_Edge aEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment , aCyl1); TopoDS_Edge aEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(aArc2 , aCyl2); TopoDS_Edge aEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment , aCyl2); TopoDS_Wire threadingWire1 = BRepBuilderAPI_MakeWire(aEdge1OnSurf1 , aEdge2OnSurf1); TopoDS_Wire threadingWire2 = BRepBuilderAPI_MakeWire(aEdge1OnSurf2 , aEdge2OnSurf2); BRepLib::BuildCurves3d(threadingWire1); BRepLib::BuildCurves3d(threadingWire2); BRepOffsetAPI_ThruSections aTool(Standard_True); aTool.AddWire(threadingWire1); aTool.AddWire(threadingWire2); aTool.CheckCompatibility(Standard_False); return aTool.Shape(); } TopoDS_Shape TopoShape::makeLoft(const TopTools_ListOfShape& profiles, Standard_Boolean isSolid, Standard_Boolean isRuled, Standard_Boolean isClosed) const { // http://opencascade.blogspot.com/2010/01/surface-modeling-part5.html BRepOffsetAPI_ThruSections aGenerator (isSolid,isRuled); TopTools_ListIteratorOfListOfShape it; int countShapes = 0; for (it.Initialize(profiles); it.More(); it.Next()) { const TopoDS_Shape& item = it.Value(); if (!item.IsNull() && item.ShapeType() == TopAbs_VERTEX) { aGenerator.AddVertex(TopoDS::Vertex (item)); countShapes++; } else if (!item.IsNull() && item.ShapeType() == TopAbs_EDGE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(item)); aGenerator.AddWire(mkWire.Wire()); countShapes++; } else if (!item.IsNull() && item.ShapeType() == TopAbs_WIRE) { aGenerator.AddWire(TopoDS::Wire (item)); countShapes++; } } if (countShapes < 2) { Standard_Failure::Raise("Need at least two vertices, edges or wires to create loft face"); } else { // close loft by duplicating initial profile as last profile. not perfect. if (isClosed) { /* can only close loft in certain combinations of Vertex/Wire(Edge): - V1-W1-W2-W3-V2 ==> V1-W1-W2-W3-V2-V1 invalid closed - V1-W1-W2-W3 ==> V1-W1-W2-W3-V1 valid closed - W1-W2-W3-V1 ==> W1-W2-W3-V1-W1 invalid closed - W1-W2-W3 ==> W1-W2-W3-W1 valid closed*/ if (profiles.Last().ShapeType() == TopAbs_VERTEX) { Base::Console().Message("TopoShape::makeLoft: can't close Loft with Vertex as last profile. 'Closed' ignored.\n"); } else { // repeat Add logic above for first profile const TopoDS_Shape& firstProfile = profiles.First(); if (firstProfile.ShapeType() == TopAbs_VERTEX) { aGenerator.AddVertex(TopoDS::Vertex (firstProfile)); countShapes++; } else if (firstProfile.ShapeType() == TopAbs_EDGE) { aGenerator.AddWire(TopoDS::Wire (firstProfile)); countShapes++; } else if (firstProfile.ShapeType() == TopAbs_WIRE) { aGenerator.AddWire(TopoDS::Wire (firstProfile)); countShapes++; } } } } Standard_Boolean anIsCheck = Standard_True; aGenerator.CheckCompatibility (anIsCheck); // use BRepFill_CompatibleWires on profiles. force #edges, orientation, "origin" to match. aGenerator.Build(); if (!aGenerator.IsDone()) Standard_Failure::Raise("Failed to create loft face"); //Base::Console().Message("DEBUG: TopoShape::makeLoft returns.\n"); return aGenerator.Shape(); } TopoDS_Shape TopoShape::makePrism(const gp_Vec& vec) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("cannot sweep empty shape"); BRepPrimAPI_MakePrism mkPrism(this->_Shape, vec); return mkPrism.Shape(); } TopoDS_Shape TopoShape::revolve(const gp_Ax1& axis, double d, Standard_Boolean isSolid) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("cannot revolve empty shape"); TopoDS_Face f; TopoDS_Wire w; TopoDS_Edge e; Standard_Boolean convertFailed = false; TopoDS_Shape base = this->_Shape; if ((isSolid) && (BRep_Tool::IsClosed(base)) && ((base.ShapeType() == TopAbs_EDGE) || (base.ShapeType() == TopAbs_WIRE))) { if (base.ShapeType() == TopAbs_EDGE) { BRepBuilderAPI_MakeWire mkWire(TopoDS::Edge(base)); if (mkWire.IsDone()) { w = mkWire.Wire(); } else { convertFailed = true; } } else { w = TopoDS::Wire(base);} if (!convertFailed) { BRepBuilderAPI_MakeFace mkFace(w); if (mkFace.IsDone()) { f = mkFace.Face(); base = f; } else { convertFailed = true; } } } if (convertFailed) { Base::Console().Message("TopoShape::revolve could not make Solid from Wire/Edge.\n");} BRepPrimAPI_MakeRevol mkRevol(base, axis,d); return mkRevol.Shape(); } TopoDS_Shape TopoShape::makeOffsetShape(double offset, double tol, bool intersection, bool selfInter, short offsetMode, short join, bool fill) const { BRepOffsetAPI_MakeOffsetShape mkOffset(this->_Shape, offset, tol, BRepOffset_Mode(offsetMode), intersection ? Standard_True : Standard_False, selfInter ? Standard_True : Standard_False, GeomAbs_JoinType(join)); if (!mkOffset.IsDone()) Standard_Failure::Raise("BRepOffsetAPI_MakeOffsetShape not done"); const TopoDS_Shape& res = mkOffset.Shape(); if (!fill) return res; //get perimeter wire of original shape. //Wires returned seem to have edges in connection order. ShapeAnalysis_FreeBoundsProperties freeCheck(this->_Shape); freeCheck.Perform(); if (freeCheck.NbClosedFreeBounds() < 1) { Standard_Failure::Raise("no closed bounds"); } BRep_Builder builder; TopoDS_Compound perimeterCompound; builder.MakeCompound(perimeterCompound); for (int index = 1; index <= freeCheck.NbClosedFreeBounds(); ++index) { TopoDS_Wire originalWire = freeCheck.ClosedFreeBound(index)->FreeBound(); const BRepAlgo_Image& img = mkOffset.MakeOffset().OffsetEdgesFromShapes(); //build offset wire. TopoDS_Wire offsetWire; builder.MakeWire(offsetWire); TopExp_Explorer xp; for (xp.Init(originalWire, TopAbs_EDGE); xp.More(); xp.Next()) { if (!img.HasImage(xp.Current())) { Standard_Failure::Raise("no image for shape"); } const TopTools_ListOfShape& currentImage = img.Image(xp.Current()); TopTools_ListIteratorOfListOfShape listIt; int edgeCount(0); TopoDS_Edge mappedEdge; for (listIt.Initialize(currentImage); listIt.More(); listIt.Next()) { if (listIt.Value().ShapeType() != TopAbs_EDGE) continue; edgeCount++; mappedEdge = TopoDS::Edge(listIt.Value()); } if (edgeCount != 1) { std::ostringstream stream; stream << "wrong edge count: " << edgeCount << std::endl; Standard_Failure::Raise(stream.str().c_str()); } builder.Add(offsetWire, mappedEdge); } //It would be nice if we could get thruSections to build planar faces //in all areas possible, so we could run through refine. I tried setting //ruled to standard_true, but that didn't have the desired affect. BRepOffsetAPI_ThruSections aGenerator; aGenerator.AddWire(originalWire); aGenerator.AddWire(offsetWire); aGenerator.Build(); if (!aGenerator.IsDone()) { Standard_Failure::Raise("ThruSections failed"); } builder.Add(perimeterCompound, aGenerator.Shape()); } //still had to sew. not using the passed in parameter for sew. //Sew has it's own default tolerance. Opinions? BRepBuilderAPI_Sewing sewTool; sewTool.Add(this->_Shape); sewTool.Add(perimeterCompound); sewTool.Add(res); sewTool.Perform(); //Perform Sewing TopoDS_Shape outputShape = sewTool.SewedShape(); if ((outputShape.ShapeType() == TopAbs_SHELL) && (outputShape.Closed())) { BRepBuilderAPI_MakeSolid solidMaker(TopoDS::Shell(outputShape)); if (solidMaker.IsDone()) { TopoDS_Solid temp = solidMaker.Solid(); //contrary to the occ docs the return value OrientCloseSolid doesn't //indicate whether the shell was open or not. It returns true with an //open shell and we end up with an invalid solid. if (BRepLib::OrientClosedSolid(temp)) outputShape = temp; } } return outputShape; } TopoDS_Shape TopoShape::makeThickSolid(const TopTools_ListOfShape& remFace, double offset, double tol, bool intersection, bool selfInter, short offsetMode, short join) const { BRepOffsetAPI_MakeThickSolid mkThick(this->_Shape, remFace, offset, tol, BRepOffset_Mode(offsetMode), intersection ? Standard_True : Standard_False, selfInter ? Standard_True : Standard_False, GeomAbs_JoinType(join)); return mkThick.Shape(); } void TopoShape::transformGeometry(const Base::Matrix4D &rclMat) { this->_Shape = transformGShape(rclMat); } TopoDS_Shape TopoShape::transformGShape(const Base::Matrix4D& rclTrf) const { if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot transform null shape"); gp_GTrsf mat; mat.SetValue(1,1,rclTrf[0][0]); mat.SetValue(2,1,rclTrf[1][0]); mat.SetValue(3,1,rclTrf[2][0]); mat.SetValue(1,2,rclTrf[0][1]); mat.SetValue(2,2,rclTrf[1][1]); mat.SetValue(3,2,rclTrf[2][1]); mat.SetValue(1,3,rclTrf[0][2]); mat.SetValue(2,3,rclTrf[1][2]); mat.SetValue(3,3,rclTrf[2][2]); mat.SetValue(1,4,rclTrf[0][3]); mat.SetValue(2,4,rclTrf[1][3]); mat.SetValue(3,4,rclTrf[2][3]); // geometric transformation BRepBuilderAPI_GTransform mkTrf(this->_Shape, mat); return mkTrf.Shape(); } void TopoShape::transformShape(const Base::Matrix4D& rclTrf, bool copy) { if (this->_Shape.IsNull()) Standard_Failure::Raise("Cannot transform null shape"); gp_Trsf mat; mat.SetValues(rclTrf[0][0],rclTrf[0][1],rclTrf[0][2],rclTrf[0][3], rclTrf[1][0],rclTrf[1][1],rclTrf[1][2],rclTrf[1][3], rclTrf[2][0],rclTrf[2][1],rclTrf[2][2],rclTrf[2][3] #if OCC_VERSION_HEX < 0x060800 , 0.00001,0.00001 #endif ); //precision was removed in OCCT CR0025194 // location transformation BRepBuilderAPI_Transform mkTrf(this->_Shape, mat, copy ? Standard_True : Standard_False); this->_Shape = mkTrf.Shape(); } TopoDS_Shape TopoShape::mirror(const gp_Ax2& ax2) const { gp_Trsf mat; mat.SetMirror(ax2); BRepBuilderAPI_Transform mkTrf(this->_Shape, mat); return mkTrf.Shape(); } TopoDS_Shape TopoShape::toNurbs() const { BRepBuilderAPI_NurbsConvert mkNurbs(this->_Shape); return mkNurbs.Shape(); } TopoDS_Shape TopoShape::replaceShape(const std::vector< std::pair >& s) const { BRepTools_ReShape reshape; std::vector< std::pair >::const_iterator it; for (it = s.begin(); it != s.end(); ++it) reshape.Replace(it->first, it->second); return reshape.Apply(this->_Shape, TopAbs_SHAPE); } TopoDS_Shape TopoShape::removeShape(const std::vector& s) const { BRepTools_ReShape reshape; for (std::vector::const_iterator it = s.begin(); it != s.end(); ++it) reshape.Remove(*it); return reshape.Apply(this->_Shape, TopAbs_SHAPE); } void TopoShape::sewShape() { BRepBuilderAPI_Sewing sew; sew.Load(this->_Shape); sew.Perform(); this->_Shape = sew.SewedShape(); } bool TopoShape::fix(double precision, double mintol, double maxtol) { if (this->_Shape.IsNull()) return false; TopAbs_ShapeEnum type = this->_Shape.ShapeType(); ShapeFix_Shape fix(this->_Shape); fix.SetPrecision(precision); fix.SetMinTolerance(mintol); fix.SetMaxTolerance(maxtol); fix.Perform(); if (type == TopAbs_SOLID) { //fix.FixEdgeTool(); fix.FixWireTool()->Perform(); fix.FixFaceTool()->Perform(); fix.FixShellTool()->Perform(); fix.FixSolidTool()->Perform(); this->_Shape = fix.FixSolidTool()->Shape(); } else if (type == TopAbs_SHELL) { fix.FixWireTool()->Perform(); fix.FixFaceTool()->Perform(); fix.FixShellTool()->Perform(); this->_Shape = fix.FixShellTool()->Shape(); } else if (type == TopAbs_FACE) { fix.FixWireTool()->Perform(); fix.FixFaceTool()->Perform(); this->_Shape = fix.Shape(); } else if (type == TopAbs_WIRE) { fix.FixWireTool()->Perform(); this->_Shape = fix.Shape(); } else { this->_Shape = fix.Shape(); } return isValid(); } bool TopoShape::removeInternalWires(double minArea) { ShapeUpgrade_RemoveInternalWires fix(this->_Shape); fix.MinArea() = minArea; bool ok = fix.Perform() ? true : false; this->_Shape = fix.GetResult(); return ok; } TopoDS_Shape TopoShape::removeSplitter() const { if (_Shape.IsNull()) Standard_Failure::Raise("Cannot remove splitter from empty shape"); if (_Shape.ShapeType() == TopAbs_SOLID) { const TopoDS_Solid &solid = TopoDS::Solid(_Shape); BRepBuilderAPI_MakeSolid mkSolid; TopExp_Explorer it; for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); ModelRefine::FaceUniter uniter(currentShell); if (uniter.process()) { if (uniter.isModified()) { const TopoDS_Shell &newShell = uniter.getShell(); mkSolid.Add(newShell); } else { mkSolid.Add(currentShell); } } else { Standard_Failure::Raise("Removing splitter failed"); return _Shape; } } return mkSolid.Solid(); } else if (_Shape.ShapeType() == TopAbs_SHELL) { const TopoDS_Shell& shell = TopoDS::Shell(_Shape); ModelRefine::FaceUniter uniter(shell); if (uniter.process()) { return uniter.getShell(); } else { Standard_Failure::Raise("Removing splitter failed"); } } else if (_Shape.ShapeType() == TopAbs_COMPOUND) { BRep_Builder builder; TopoDS_Compound comp; builder.MakeCompound(comp); TopExp_Explorer xp; // solids for (xp.Init(_Shape, TopAbs_SOLID); xp.More(); xp.Next()) { const TopoDS_Solid &solid = TopoDS::Solid(xp.Current()); BRepTools_ReShape reshape; TopExp_Explorer it; for (it.Init(solid, TopAbs_SHELL); it.More(); it.Next()) { const TopoDS_Shell ¤tShell = TopoDS::Shell(it.Current()); ModelRefine::FaceUniter uniter(currentShell); if (uniter.process()) { if (uniter.isModified()) { const TopoDS_Shell &newShell = uniter.getShell(); reshape.Replace(currentShell, newShell); } } } builder.Add(comp, reshape.Apply(solid)); } // free shells for (xp.Init(_Shape, TopAbs_SHELL, TopAbs_SOLID); xp.More(); xp.Next()) { const TopoDS_Shell& shell = TopoDS::Shell(xp.Current()); ModelRefine::FaceUniter uniter(shell); if (uniter.process()) { builder.Add(comp, uniter.getShell()); } } // the rest for (xp.Init(_Shape, TopAbs_FACE, TopAbs_SHELL); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } for (xp.Init(_Shape, TopAbs_WIRE, TopAbs_FACE); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } for (xp.Init(_Shape, TopAbs_EDGE, TopAbs_WIRE); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } for (xp.Init(_Shape, TopAbs_VERTEX, TopAbs_EDGE); xp.More(); xp.Next()) { if (!xp.Current().IsNull()) builder.Add(comp, xp.Current()); } return comp; } return _Shape; } namespace Part { struct MeshVertex { Standard_Real x,y,z; Standard_Integer i; MeshVertex(Standard_Real X, Standard_Real Y, Standard_Real Z) : x(X),y(Y),z(Z) { } MeshVertex(const gp_Pnt& p) : x(p.X()),y(p.Y()),z(p.Z()) { } gp_Pnt toPoint() const { return gp_Pnt(x,y,z); } bool operator < (const MeshVertex &rclPt) const { if (fabs ( this->x - rclPt.x) >= MESH_MIN_PT_DIST) return this->x < rclPt.x; if (fabs ( this->y - rclPt.y) >= MESH_MIN_PT_DIST) return this->y < rclPt.y; if (fabs ( this->z - rclPt.z) >= MESH_MIN_PT_DIST) return this->z < rclPt.z; return false; // points are considered to be equal } private: // use the same value as used inside the Mesh module static const double MESH_MIN_PT_DIST; }; } //const double Vertex::MESH_MIN_PT_DIST = 1.0e-6; const double MeshVertex::MESH_MIN_PT_DIST = gp::Resolution(); #include #include #include void TopoShape::getFaces(std::vector &aPoints, std::vector &aTopo, float accuracy, uint16_t flags) const { if (this->_Shape.IsNull()) return; std::set vertices; Standard_Real x1, y1, z1; Standard_Real x2, y2, z2; Standard_Real x3, y3, z3; Handle_StlMesh_Mesh aMesh = new StlMesh_Mesh(); #if OCC_VERSION_HEX >= 0x060801 BRepMesh_IncrementalMesh bMesh(this->_Shape, accuracy); StlTransfer::RetrieveMesh(this->_Shape,aMesh); #else StlTransfer::BuildIncrementalMesh(this->_Shape, accuracy, #if OCC_VERSION_HEX >= 0x060503 Standard_True, #endif aMesh); #endif StlMesh_MeshExplorer xp(aMesh); for (Standard_Integer nbd=1;nbd<=aMesh->NbDomains();nbd++) { for (xp.InitTriangle (nbd); xp.MoreTriangle (); xp.NextTriangle ()) { xp.TriangleVertices (x1,y1,z1,x2,y2,z2,x3,y3,z3); Data::ComplexGeoData::Facet face; std::set::iterator it; // 1st vertex MeshVertex v1(x1,y1,z1); it = vertices.find(v1); if (it == vertices.end()) { v1.i = vertices.size(); face.I1 = v1.i; vertices.insert(v1); } else { face.I1 = it->i; } // 2nd vertex MeshVertex v2(x2,y2,z2); it = vertices.find(v2); if (it == vertices.end()) { v2.i = vertices.size(); face.I2 = v2.i; vertices.insert(v2); } else { face.I2 = it->i; } // 3rd vertex MeshVertex v3(x3,y3,z3); it = vertices.find(v3); if (it == vertices.end()) { v3.i = vertices.size(); face.I3 = v3.i; vertices.insert(v3); } else { face.I3 = it->i; } // make sure that we don't insert invalid facets if (face.I1 != face.I2 && face.I2 != face.I3 && face.I3 != face.I1) aTopo.push_back(face); } } std::vector points; points.resize(vertices.size()); for (std::set::iterator it = vertices.begin(); it != vertices.end(); ++it) points[it->i] = it->toPoint(); for (std::vector::iterator it = points.begin(); it != points.end(); ++it) aPoints.push_back(Base::Vector3d(it->X(),it->Y(),it->Z())); } void TopoShape::setFaces(const std::vector &Points, const std::vector &Topo, float Accuracy) { gp_XYZ p1, p2, p3; TopoDS_Vertex Vertex1, Vertex2, Vertex3; TopoDS_Face newFace; TopoDS_Wire newWire; BRepBuilderAPI_Sewing aSewingTool; Standard_Real x1, y1, z1; Standard_Real x2, y2, z2; Standard_Real x3, y3, z3; aSewingTool.Init(Accuracy,Standard_True); TopoDS_Compound aComp; BRep_Builder BuildTool; BuildTool.MakeCompound(aComp); unsigned int ctPoints = Points.size(); for (std::vector::const_iterator it = Topo.begin(); it != Topo.end(); ++it) { if (it->I1 >= ctPoints || it->I2 >= ctPoints || it->I3 >= ctPoints) continue; x1 = Points[it->I1].x; y1 = Points[it->I1].y; z1 = Points[it->I1].z; x2 = Points[it->I2].x; y2 = Points[it->I2].y; z2 = Points[it->I2].z; x3 = Points[it->I3].x; y3 = Points[it->I3].y; z3 = Points[it->I3].z; p1.SetCoord(x1,y1,z1); p2.SetCoord(x2,y2,z2); p3.SetCoord(x3,y3,z3); if ((!(p1.IsEqual(p2,0.0))) && (!(p1.IsEqual(p3,0.0)))) { Vertex1 = BRepBuilderAPI_MakeVertex(p1); Vertex2 = BRepBuilderAPI_MakeVertex(p2); Vertex3 = BRepBuilderAPI_MakeVertex(p3); newWire = BRepBuilderAPI_MakePolygon(Vertex1, Vertex2, Vertex3, Standard_True); if (!newWire.IsNull()) { newFace = BRepBuilderAPI_MakeFace(newWire); if (!newFace.IsNull()) BuildTool.Add(aComp, newFace); } } } aSewingTool.Load(aComp); aSewingTool.Perform(); _Shape = aSewingTool.SewedShape(); // TopAbs_Orientation o = _Shape.Orientation(); _Shape.Reverse(); // seems that we have to reverse the orientation if (_Shape.IsNull()) _Shape = aComp; }