// Created on: 1995-06-20 // Created by: Stagiaire Alain JOURDAIN // Copyright (c) 1995-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #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 IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_IncrementalMesh,BRepMesh_DiscretRoot) namespace { //! Default flag to control parallelization for BRepMesh_IncrementalMesh //! tool returned for Mesh Factory static Standard_Boolean IS_IN_PARALLEL = Standard_False; } class BRepMesh_IncrementalMesh::FaceListFunctor { public: FaceListFunctor (BRepMesh_IncrementalMesh* theAlgo, const Handle(Message_ProgressIndicator)& theProgress, Standard_Boolean theParallel) : myAlgo (theAlgo), mySentry (theProgress, "Mesh faces", 0, theAlgo->myFaces.Size(), 1), myThreadId (OSD_Thread::Current()), myIsParallel (theParallel), myHasProgress (!theProgress.IsNull()) { } void operator() (const Standard_Integer theFaceIndex) const { if (!mySentry.More()) { return; } TopoDS_Face& aFace = myAlgo->myFaces.ChangeValue (theFaceIndex); myAlgo->myMesh->Process (aFace, &mySentry); if (myIsParallel) { // use a trick to avoid mutex locks - increment the progress only within main thread if (myHasProgress && myThreadId == OSD_Thread::Current()) { mySentry.Next (OSD_Parallel::NbLogicalProcessors()); } } else { mySentry.Next(); } } private: mutable BRepMesh_IncrementalMesh* myAlgo; mutable Message_ProgressSentry mySentry; Standard_ThreadId myThreadId; Standard_Boolean myIsParallel; Standard_Boolean myHasProgress; }; //======================================================================= //function : Default constructor //purpose : //======================================================================= BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh() : myMaxShapeSize(0.), myModified(Standard_False), myStatus(0) { } //======================================================================= //function : Constructor //purpose : //======================================================================= BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh( const TopoDS_Shape& theShape, const Standard_Real theLinDeflection, const Standard_Boolean isRelative, const Standard_Real theAngDeflection, const Standard_Boolean isInParallel, const Standard_Boolean adaptiveMin) : myMaxShapeSize(0.), myModified(Standard_False), myStatus(0) { myParameters.Deflection = theLinDeflection; myParameters.Relative = isRelative; myParameters.Angle = theAngDeflection; myParameters.InParallel = isInParallel; myParameters.AdaptiveMin = adaptiveMin; myShape = theShape; Perform(); } //======================================================================= //function : Constructor //purpose : //======================================================================= BRepMesh_IncrementalMesh::BRepMesh_IncrementalMesh(const TopoDS_Shape& theShape, const BRepMesh_FastDiscret::Parameters& theParameters) : myParameters(theParameters) { myShape = theShape; Perform(); } //======================================================================= //function : Destructor //purpose : //======================================================================= BRepMesh_IncrementalMesh::~BRepMesh_IncrementalMesh() { } //======================================================================= //function : clear //purpose : //======================================================================= void BRepMesh_IncrementalMesh::clear() { // the allocator will be alive while the structures are alive Handle(NCollection_BaseAllocator) anAlloc = new NCollection_IncAllocator(BRepMesh::MEMORY_BLOCK_SIZE_HUGE); myEdges.Clear(anAlloc); myEdgeDeflection.Clear(anAlloc); myFaces.Clear(); myMesh.Nullify(); } //======================================================================= //function : init //purpose : //======================================================================= void BRepMesh_IncrementalMesh::init() { myStatus = 0; myModified = Standard_False; setDone(); clear(); collectFaces(); Bnd_Box aBox; if ( myParameters.Relative ) { BRepBndLib::Add(myShape, aBox, Standard_False); if (aBox.IsVoid()) { // Nothing to mesh. return; } BRepMesh_ShapeTool::BoxMaxDimension(aBox, myMaxShapeSize); } myMesh = new BRepMesh_FastDiscret (aBox, myParameters); myMesh->InitSharedFaces(myShape); } //======================================================================= //function : collectFaces //purpose : //======================================================================= void BRepMesh_IncrementalMesh::collectFaces() { Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator; TopTools_ListOfShape aFaceList(anAlloc); BRepLib::ReverseSortFaces(myShape, aFaceList); TColStd_MapOfTransient aTFaceMap(1, anAlloc); // make array of faces suitable for processing (excluding faces without surface) TopLoc_Location aDummyLoc; TopTools_ListIteratorOfListOfShape aFaceIter(aFaceList); for (; aFaceIter.More(); aFaceIter.Next()) { const TopoDS_Face& aFace = TopoDS::Face(aFaceIter.Value()); const Handle(TopoDS_TShape)& aTFace = aFace.TShape(); if (!aTFaceMap.Add (aTFace)) continue; // already processed const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace, aDummyLoc); if (aSurf.IsNull()) continue; myFaces.Append(aFace); } } //======================================================================= //function : Perform //purpose : //======================================================================= void BRepMesh_IncrementalMesh::Perform() { Perform (Handle(Message_ProgressIndicator)()); } //======================================================================= //function : Perform //purpose : //======================================================================= void BRepMesh_IncrementalMesh::Perform (const Handle(Message_ProgressIndicator)& theProgress) { init(); if (myMesh.IsNull()) return; update (theProgress); } //======================================================================= //function : update() //purpose : //======================================================================= void BRepMesh_IncrementalMesh::update (const Handle(Message_ProgressIndicator)& theProgress) { Message_ProgressSentry anOuterSentry (theProgress, "Updating", 0, 100, 1); // Update edges data anOuterSentry.Next(9); { int aNbEdges = 0; for (TopExp_Explorer aExplorer (myShape, TopAbs_EDGE); aExplorer.More(); aExplorer.Next()) { ++aNbEdges; } Message_ProgressSentry anEdgeSentry (theProgress, "Update edges data", 0, aNbEdges, 1); for (TopExp_Explorer aExplorer (myShape, TopAbs_EDGE); aExplorer.More() && anEdgeSentry.More(); aExplorer.Next(), anEdgeSentry.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(aExplorer.Current()); if(!BRep_Tool::IsGeometric(aEdge)) continue; update(aEdge); } } if (!anOuterSentry.More()) { myStatus = BRepMesh_UserBreak; return; } anOuterSentry.Next(5); // Update faces data NCollection_Vector::Iterator aFaceIt(myFaces); for (Message_ProgressSentry aFacesSentry (theProgress, "Update faces data", 0, myFaces.Size(), 1); aFaceIt.More() && aFacesSentry.More(); aFaceIt.Next(), aFacesSentry.Next()) { update(aFaceIt.Value()); } if (!anOuterSentry.More()) { myStatus = BRepMesh_UserBreak; return; } anOuterSentry.Next(80); { // Mesh faces FaceListFunctor aFacesFunctor (this, theProgress, myParameters.InParallel); OSD_Parallel::For (0, myFaces.Size(), aFacesFunctor, !myParameters.InParallel); } if (!anOuterSentry.More()) { myStatus = BRepMesh_UserBreak; return; } anOuterSentry.Next(5); { Message_ProgressSentry aSentry (theProgress, "Commit", 0, myFaces.Size(), 1); commit (aSentry); } anOuterSentry.Next(); clear(); } //======================================================================= //function : discretizeFreeEdges //purpose : //======================================================================= void BRepMesh_IncrementalMesh::discretizeFreeEdges() { TopExp_Explorer aExplorer(myShape ,TopAbs_EDGE, TopAbs_FACE); for (; aExplorer.More(); aExplorer.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(aExplorer.Current()); if(!BRep_Tool::IsGeometric(aEdge)) continue; TopLoc_Location aLoc; Standard_Real aEdgeDeflection = edgeDeflection(aEdge); Handle(Poly_Polygon3D) aPoly3D = BRep_Tool::Polygon3D(aEdge, aLoc); if (!aPoly3D.IsNull() && aPoly3D->Deflection() < 1.1 * aEdgeDeflection) continue; BRepAdaptor_Curve aCurve(aEdge); GCPnts_TangentialDeflection aDiscret(aCurve, aCurve.FirstParameter(), aCurve.LastParameter(), myParameters.Angle, aEdgeDeflection, 2, Precision::PConfusion(), myParameters.MinSize); Standard_Integer aNodesNb = aDiscret.NbPoints(); TColgp_Array1OfPnt aNodes (1, aNodesNb); TColStd_Array1OfReal aUVNodes(1, aNodesNb); for (Standard_Integer i = 1; i <= aNodesNb; ++i) { aNodes (i) = aDiscret.Value(i); aUVNodes(i) = aDiscret.Parameter(i); } aPoly3D = new Poly_Polygon3D(aNodes, aUVNodes); aPoly3D->Deflection(myParameters.Deflection); BRep_Builder aBuilder; aBuilder.UpdateEdge(aEdge, aPoly3D); } } //======================================================================= //function : edgeDeflection //purpose : //======================================================================= Standard_Real BRepMesh_IncrementalMesh::edgeDeflection( const TopoDS_Edge& theEdge) { const Standard_Real* pDef = myEdgeDeflection.Seek(theEdge); if (pDef) return *pDef; Standard_Real aEdgeDeflection; if ( myParameters.Relative ) { Standard_Real aScale; aEdgeDeflection = BRepMesh_ShapeTool::RelativeEdgeDeflection(theEdge, myParameters.Deflection, myMaxShapeSize, aScale); } else aEdgeDeflection = myParameters.Deflection; myEdgeDeflection.Bind(theEdge, aEdgeDeflection); return aEdgeDeflection; } //======================================================================= //function : faceDeflection //purpose : //======================================================================= Standard_Real BRepMesh_IncrementalMesh::faceDeflection( const TopoDS_Face& theFace) { if ( !myParameters.Relative ) return myParameters.Deflection; Standard_Integer aEdgesNb = 0; Standard_Real aFaceDeflection = 0.; TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE); for (; aEdgeIt.More(); aEdgeIt.Next(), ++aEdgesNb) { const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current()); aFaceDeflection += edgeDeflection(aEdge); } return (aEdgesNb == 0) ? myParameters.Deflection : (aFaceDeflection / aEdgesNb); } //======================================================================= //function : update(edge) //purpose : //======================================================================= void BRepMesh_IncrementalMesh::update(const TopoDS_Edge& theEdge) { if (!myEdges.IsBound(theEdge)) myEdges.Bind(theEdge, BRepMesh::DMapOfTriangulationBool(3, myEdges.Allocator())); Standard_Real aEdgeDeflection = edgeDeflection(theEdge); // Check that triangulation relies to face of the given shape. const TopTools_IndexedDataMapOfShapeListOfShape& aMapOfSharedFaces = myMesh->SharedFaces(); const TopTools_ListOfShape& aSharedFaces = aMapOfSharedFaces.FindFromKey(theEdge); TopTools_ListIteratorOfListOfShape aSharedFaceIt(aSharedFaces); for (; aSharedFaceIt.More(); aSharedFaceIt.Next()) { TopLoc_Location aLoc; const TopoDS_Face& aFace = TopoDS::Face(aSharedFaceIt.Value()); const Handle(Poly_Triangulation)& aFaceTriangulation = BRep_Tool::Triangulation(aFace, aLoc); if (aFaceTriangulation.IsNull()) continue; Standard_Boolean isConsistent = Standard_False; const Handle(Poly_PolygonOnTriangulation)& aPolygon = BRep_Tool::PolygonOnTriangulation(theEdge, aFaceTriangulation, aLoc); if (!aPolygon.IsNull()) { isConsistent = aPolygon->Deflection() < 1.1 * aEdgeDeflection && aPolygon->HasParameters(); if (!isConsistent) { myModified = Standard_True; BRepMesh_ShapeTool::NullifyEdge(theEdge, aFaceTriangulation, aLoc); } } myEdges(theEdge).Bind(aFaceTriangulation, isConsistent); } } //======================================================================= //function : isToBeMeshed //purpose : //======================================================================= Standard_Boolean BRepMesh_IncrementalMesh::toBeMeshed( const TopoDS_Face& theFace, const Standard_Boolean isWithCheck) { TopLoc_Location aLoc; const Handle(Poly_Triangulation)& aTriangulation = BRep_Tool::Triangulation(theFace, aLoc); if (aTriangulation.IsNull()) return Standard_True; if (isWithCheck) { Standard_Real aFaceDeflection = faceDeflection(theFace); if (aTriangulation->Deflection() < 1.1 * aFaceDeflection) { Standard_Boolean isEdgesConsistent = Standard_True; TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE); for (; aEdgeIt.More() && isEdgesConsistent; aEdgeIt.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current()); if (!myEdges.IsBound(aEdge)) continue; BRepMesh::DMapOfTriangulationBool& aTriMap = myEdges(aEdge); isEdgesConsistent &= aTriMap.IsBound(aTriangulation) && aTriMap(aTriangulation); } if (isEdgesConsistent) { // #25080: check that indices of links forming triangles are in range. Standard_Boolean isTriangulationConsistent = Standard_True; const Standard_Integer aNodesNb = aTriangulation->NbNodes(); const Poly_Array1OfTriangle& aTriangles = aTriangulation->Triangles(); Standard_Integer i = aTriangles.Lower(); for (; i <= aTriangles.Upper() && isTriangulationConsistent; ++i) { const Poly_Triangle& aTriangle = aTriangles(i); Standard_Integer n[3]; aTriangle.Get(n[0], n[1], n[2]); for (Standard_Integer j = 0; j < 3 && isTriangulationConsistent; ++j) isTriangulationConsistent = (n[j] >= 1 && n[j] <= aNodesNb); } if (isTriangulationConsistent) return Standard_False; } } } // Nullify edges TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE); for (; aEdgeIt.More(); aEdgeIt.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current()); BRepMesh_ShapeTool::NullifyEdge(aEdge, aTriangulation, aLoc); } BRepMesh_ShapeTool::NullifyFace(theFace); return Standard_True; } //======================================================================= //function : update(face) //purpose : //======================================================================= void BRepMesh_IncrementalMesh::update(const TopoDS_Face& theFace) { if (!toBeMeshed(theFace, Standard_True)) return; myModified = Standard_True; Standard_Integer aStatus = myMesh->Add(theFace); myStatus |= aStatus; if (aStatus != BRepMesh_ReMesh) return; BRepMesh::MapOfShape aUsedFaces; aUsedFaces.Add(theFace); const TopTools_IndexedDataMapOfShapeListOfShape& aMapOfSharedFaces = myMesh->SharedFaces(); TopExp_Explorer aEdgeIt(theFace, TopAbs_EDGE); for (; aEdgeIt.More(); aEdgeIt.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current()); if (aMapOfSharedFaces.FindIndex(aEdge) == 0) continue; const TopTools_ListOfShape& aSharedFaces = aMapOfSharedFaces.FindFromKey(aEdge); TopTools_ListIteratorOfListOfShape aSharedFaceIt(aSharedFaces); for (; aSharedFaceIt.More(); aSharedFaceIt.Next()) { const TopoDS_Face& aFace = TopoDS::Face(aSharedFaceIt.Value()); if (aUsedFaces.Contains(aFace)) continue; aUsedFaces.Add(aFace); toBeMeshed(aFace, Standard_False); myStatus |= myMesh->Add(aFace); } } } //======================================================================= //function : commit //purpose : //======================================================================= void BRepMesh_IncrementalMesh::commit (Message_ProgressSentry& theSentry) { NCollection_Vector::Iterator aFaceIt(myFaces); for (; aFaceIt.More() && theSentry.More(); aFaceIt.Next(), theSentry.Next()) commitEdges(aFaceIt.Value()); discretizeFreeEdges(); } //======================================================================= //function : commitEdges //purpose : //======================================================================= void BRepMesh_IncrementalMesh::commitEdges(const TopoDS_Face& theFace) { TopoDS_Face aFace = theFace; aFace.Orientation(TopAbs_FORWARD); Handle(BRepMesh_FaceAttribute) aFaceAttribute; if (!myMesh->GetFaceAttribute(aFace, aFaceAttribute)) return; if (!aFaceAttribute->IsValid()) { myStatus |= aFaceAttribute->GetStatus(); return; } TopLoc_Location aLoc; Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(aFace, aLoc); if (aTriangulation.IsNull()) return; try { OCC_CATCH_SIGNALS // Store discretization of edges BRepMesh::HDMapOfShapePairOfPolygon& aInternalEdges = aFaceAttribute->ChangeInternalEdges(); BRepMesh::DMapOfShapePairOfPolygon::Iterator aEdgeIt(*aInternalEdges); for (; aEdgeIt.More(); aEdgeIt.Next()) { const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Key()); const BRepMesh_PairOfPolygon& aPolyPair = aEdgeIt.Value(); const Handle(Poly_PolygonOnTriangulation)& aPolygon1 = aPolyPair.First(); const Handle(Poly_PolygonOnTriangulation)& aPolygon2 = aPolyPair.Last(); if (aPolygon1 == aPolygon2) BRepMesh_ShapeTool::UpdateEdge(aEdge, aPolygon1, aTriangulation, aLoc); else BRepMesh_ShapeTool::UpdateEdge(aEdge, aPolygon1, aPolygon2, aTriangulation, aLoc); } } catch (Standard_Failure) { myStatus |= BRepMesh_Failure; } } //======================================================================= //function : Discret //purpose : //======================================================================= Standard_Integer BRepMesh_IncrementalMesh::Discret( const TopoDS_Shape& theShape, const Standard_Real theDeflection, const Standard_Real theAngle, BRepMesh_DiscretRoot* &theAlgo) { BRepMesh_IncrementalMesh* anAlgo = new BRepMesh_IncrementalMesh(); anAlgo->ChangeParameters().Deflection = theDeflection; anAlgo->ChangeParameters().Angle = theAngle; anAlgo->ChangeParameters().InParallel = IS_IN_PARALLEL; anAlgo->SetShape (theShape); theAlgo = anAlgo; return 0; // no error } //======================================================================= //function : IsParallelDefault //purpose : //======================================================================= Standard_Boolean BRepMesh_IncrementalMesh::IsParallelDefault() { return IS_IN_PARALLEL; } //======================================================================= //function : Discret //purpose : //======================================================================= void BRepMesh_IncrementalMesh::SetParallelDefault( const Standard_Boolean theInParallel) { IS_IN_PARALLEL = theInParallel; } //! Export Mesh Plugin entry function DISCRETPLUGIN(BRepMesh_IncrementalMesh)