1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/BRepMesh/BRepMesh_IncrementalMesh.cxx

696 lines
21 KiB
C++

// 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 <BRepMesh_IncrementalMesh.hxx>
#include <OSD_Parallel.hxx>
#include <Precision.hxx>
#include <Standard_ErrorHandler.hxx>
#include <BRepMesh_ShapeTool.hxx>
#include <BRepMesh_Edge.hxx>
#include <BRepMesh_PluginMacro.hxx>
#include <Bnd_Box.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <BRepTools.hxx>
#include <BRepLib.hxx>
#include <BRepBndLib.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <Poly_Triangulation.hxx>
#include <Poly_Polygon3D.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Shape.hxx>
#include <TopAbs.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TColgp_Array1OfPnt.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_MapOfTransient.hxx>
#include <TopTools_HArray1OfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <GCPnts_TangentialDeflection.hxx>
#include <Message_ProgressSentry.hxx>
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<TopoDS_Face>::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<TopoDS_Face>::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)