1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

Compare commits

...

1 Commits

Author SHA1 Message Date
oan
8c3e6633b8 0031586: BRepMesh hangs up
Use NCollection_UBTree to detect intersections between newly added links and contour of the polygon;
Perform check of the solutions for link insertion after all possible solutions are found and sorted according to their priority.
2022-12-22 15:51:09 +03:00
3 changed files with 290 additions and 92 deletions

View File

@@ -76,8 +76,137 @@ namespace {
theBox.Add( thePnt2 );
theBox.Enlarge(Precision);
}
//=============================================================================
//function : IntSegSeg
//purpose : Checks intersection between the two segments.
//=============================================================================
BRepMesh_GeomTool::IntFlag IntSegSeg(
const Handle(BRepMesh_DataStructureOfDelaun)& theMeshData,
const BRepMesh_Edge& theEdg1,
const BRepMesh_Edge& theEdg2,
const Standard_Boolean isConsiderEndPointTouch,
const Standard_Boolean isConsiderPointOnEdge,
gp_Pnt2d& theIntPnt)
{
gp_XY p1, p2, p3, p4;
p1 = theMeshData->GetNode( theEdg1.FirstNode() ).Coord();
p2 = theMeshData->GetNode( theEdg1.LastNode () ).Coord();
p3 = theMeshData->GetNode( theEdg2.FirstNode() ).Coord();
p4 = theMeshData->GetNode( theEdg2.LastNode () ).Coord();
return BRepMesh_GeomTool::IntSegSeg( p1, p2, p3, p4,
isConsiderEndPointTouch, isConsiderPointOnEdge, theIntPnt );
}
} // anonymous namespace
//! Checks polygon links for intersection with current one of the same polygon.
class BRepMesh_Delaun::EBTreeOfB2d_Selector :
public NCollection_EBTree<Standard_Integer, Bnd_B2d>::Selector
{
public:
//! Constructor.
EBTreeOfB2d_Selector(
const Handle(BRepMesh_DataStructureOfDelaun)& theMeshData,
const DataMapOfPVoid& theSegmentsPolyMap,
const Standard_Boolean isConsiderEndPointTouch = Standard_False,
const Standard_Boolean isConsiderPointOnEdge = Standard_False)
: myMeshData ( theMeshData ),
mySegmentsPolyMap ( theSegmentsPolyMap ),
myConsiderEndPointTouch ( isConsiderEndPointTouch ),
myConsiderPointOnEdge ( isConsiderPointOnEdge ),
myPolygonPtr ( nullptr )
{
}
//! Implementation of rejection method
//! @return
//! True if the bounding box does not intersect with the current
virtual Standard_Boolean Reject (const Bnd_B2d& theBox) const
{
return (myBox.IsOut( theBox ));
}
//! Implementation of acceptance method
//! This method is called when the bounding box intersect with the current.
//! It stores the object - the index of box in the list of accepted objects.
//! @return
//! True, because the object is accepted
virtual Standard_Boolean Accept (const Standard_Integer& theObj)
{
if (mySkipLinks.Contains( theObj ))
{
return Standard_False;
}
auto aPtr = mySegmentsPolyMap.Seek( theObj );
if (aPtr != nullptr && *aPtr == myPolygonPtr)
{
const BRepMesh_Edge& aPolyLink = myMeshData->GetLink( Abs( theObj ) );
if (!myLink.IsEqual( aPolyLink ))
{
// intersection is possible...
gp_Pnt2d anIntPnt;
BRepMesh_GeomTool::IntFlag aIntFlag = IntSegSeg(
myMeshData, myLink, aPolyLink,
myConsiderEndPointTouch, myConsiderPointOnEdge, anIntPnt );
myStop = (aIntFlag != BRepMesh_GeomTool::NoIntersection);
return myStop;
}
}
return Standard_False;
}
//! Set current box to search for overlapping with him
void SetCurrent (const BRepMesh_Edge& theLink,
const Bnd_B2d& theBox,
const void* thePolygonPtr)
{
mySkipLinks.Clear();
myStop = Standard_False;
myLink = theLink;
myBox = theBox;
myPolygonPtr = thePolygonPtr;
}
void SetSkipLink(const int theLink)
{
mySkipLinks.Add( theLink );
}
template<typename... T>
void SetSkipLink( const int theLink, const T... theLinks )
{
SetSkipLink( theLink );
SetSkipLink( theLinks... );
}
//! Returns true if the current segment intersects another one of the same polygon.
Standard_Boolean IsIntersected()
{
return myStop;
}
protected:
const Handle(BRepMesh_DataStructureOfDelaun)& myMeshData;
const DataMapOfPVoid& mySegmentsPolyMap;
const Standard_Boolean myConsiderEndPointTouch;
const Standard_Boolean myConsiderPointOnEdge;
const void* myPolygonPtr;
BRepMesh_Edge myLink;
Bnd_B2d myBox;
NCollection_Map<Standard_Integer> mySkipLinks;
};
//=======================================================================
//function : BRepMesh_Delaun
//purpose :
@@ -1883,24 +2012,31 @@ void BRepMesh_Delaun::meshPolygon(IMeshData::SequenceOfInteger& thePolygon,
}
}
IMeshData::SequenceOfInteger* aPolygon1 = &thePolygon;
IMeshData::SequenceOfBndB2d* aPolyBoxes1 = &thePolyBoxes;
SegmentsBoxes aSegmentsBoxes;
EBTreeOfB2dFiller aTreeFiller( aSegmentsBoxes.Boxes );
Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger;
Handle(IMeshData::SequenceOfBndB2d) aPolyBoxes2 = new IMeshData::SequenceOfBndB2d;
Standard_Integer aLinkIt = thePolygon.Lower();
for (; aLinkIt <= thePolygon.Upper(); ++aLinkIt)
{
const Standard_Integer aLinkInfo = thePolygon( aLinkIt );
aTreeFiller .Add (aLinkInfo, thePolyBoxes( aLinkIt ));
aSegmentsBoxes.Rebind(aLinkInfo, &thePolygon);
}
aTreeFiller.Fill();
IMeshData::SequenceOfInteger* aPolygon1 = &thePolygon;
Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger;
NCollection_Sequence<Handle(IMeshData::SequenceOfInteger)> aPolyStack;
NCollection_Sequence<Handle(IMeshData::SequenceOfBndB2d)> aPolyBoxStack;
for (;;)
{
decomposeSimplePolygon(*aPolygon1, *aPolyBoxes1, *aPolygon2, *aPolyBoxes2);
decomposeSimplePolygon(*aPolygon1, *aPolygon2, aSegmentsBoxes);
if (!aPolygon2->IsEmpty())
{
aPolyStack.Append(aPolygon2);
aPolyBoxStack.Append(aPolyBoxes2);
aPolygon2 = new IMeshData::SequenceOfInteger;
aPolyBoxes2 = new IMeshData::SequenceOfBndB2d;
aPolygon2 = new IMeshData::SequenceOfInteger;
}
if (aPolygon1->IsEmpty())
@@ -1908,14 +2044,12 @@ void BRepMesh_Delaun::meshPolygon(IMeshData::SequenceOfInteger& thePolygon,
if (!aPolyStack.IsEmpty() && aPolygon1 == &(*aPolyStack.First()))
{
aPolyStack.Remove(1);
aPolyBoxStack.Remove(1);
}
if (aPolyStack.IsEmpty())
break;
aPolygon1 = &(*aPolyStack.ChangeFirst());
aPolyBoxes1 = &(*aPolyBoxStack.ChangeFirst());
aPolygon1 = &(*aPolyStack.ChangeFirst());
}
}
}
@@ -1964,17 +2098,54 @@ Standard_Boolean BRepMesh_Delaun::meshElementaryPolygon(
//function : meshSimplePolygon
//purpose :
//=======================================================================
namespace
{
struct Candidate
{
Standard_Integer PivotNode;
Standard_Integer LinkId;
Standard_Real Dist;
Standard_Real Angle;
Candidate()
: PivotNode (0),
LinkId (0),
Dist (RealLast()),
Angle (0.)
{
}
Candidate(const Standard_Integer thePivotNode,
const Standard_Integer theLinkId,
const Standard_Real theDist,
const Standard_Real theAngle)
: PivotNode (thePivotNode),
LinkId (theLinkId),
Dist (theDist),
Angle (theAngle)
{
}
bool operator<(const Candidate& theOther) const
{
const bool isWorse = ((Dist >= theOther.Dist) &&
(Angle <= theOther.Angle || Angle > AngDeviation90Deg));
return !isWorse;
}
};
}
void BRepMesh_Delaun::decomposeSimplePolygon(
IMeshData::SequenceOfInteger& thePolygon,
IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::SequenceOfInteger& thePolygonCut,
IMeshData::SequenceOfBndB2d& thePolyBoxesCut)
SegmentsBoxes& theSegmentsBoxes)
{
// Check is the given polygon elementary
if ( meshElementaryPolygon( thePolygon ) )
{
theSegmentsBoxes.Rebind( thePolygon, nullptr );
thePolygon.Clear();
thePolyBoxes.Clear();
return;
}
@@ -1994,8 +2165,8 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
Standard_Real aRefEdgeLen = aRefEdgeDir.Magnitude();
if ( aRefEdgeLen < Precision )
{
theSegmentsBoxes.Rebind( thePolygon, nullptr );
thePolygon.Clear();
thePolyBoxes.Clear();
return;
}
@@ -2003,19 +2174,16 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
// Find a point with minimum distance respect
// the end of reference link
Standard_Integer aUsedLinkId = 0;
Standard_Real aOptAngle = 0.0;
Standard_Real aMinDist = RealLast();
Standard_Integer aPivotNode = aNodes[1];
Standard_Integer aPolyLen = thePolygon.Length();
for ( Standard_Integer aLinkIt = 3; aLinkIt <= aPolyLen; ++aLinkIt )
{
Standard_Integer aLinkInfo = thePolygon( aLinkIt );
const BRepMesh_Edge& aNextEdge = GetEdge( Abs( aLinkInfo ) );
NCollection_Vector<Candidate> aCandidates( thePolygon.Length() );
aPivotNode = aLinkInfo > 0 ?
for ( Standard_Integer aLinkIt = 3; aLinkIt <= thePolygon.Length(); ++aLinkIt )
{
const Standard_Integer aLinkInfo = thePolygon( aLinkIt );
const BRepMesh_Edge& aNextEdge = GetEdge( Abs( aLinkInfo ) );
const Standard_Integer aPivotNode = aLinkInfo > 0 ?
aNextEdge.FirstNode() :
aNextEdge.LastNode();
aNextEdge.LastNode ();
// We have end points touch case in the polygon - ignore it
if (aPivotNode == aNodes[1])
@@ -2025,55 +2193,43 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
gp_Vec2d aDistanceDir( aRefVertices[1], aPivotVertex );
Standard_Real aDist = aRefEdgeDir ^ aDistanceDir;
Standard_Real aAngle = Abs( aRefEdgeDir.Angle(aDistanceDir) );
Standard_Real aAngle = Abs( aRefEdgeDir.Angle( aDistanceDir ) );
Standard_Real anAbsDist = Abs( aDist );
if (anAbsDist < Precision || aDist < 0.)
continue;
if ( ( anAbsDist >= aMinDist ) &&
( aAngle <= aOptAngle || aAngle > AngDeviation90Deg ) )
{
continue;
}
aCandidates.Append( Candidate{ aPivotNode, aLinkIt, anAbsDist, aAngle });
}
std::sort( aCandidates.begin(), aCandidates.end() );
Standard_Integer aUsedLinkId = 0;
EBTreeOfB2d_Selector aSelector( myMeshData, theSegmentsBoxes.PolyMap );
Standard_Integer aCandIt = aCandidates.Lower();
for (; aCandIt <= aCandidates.Upper(); ++aCandIt)
{
const Candidate& aCand = aCandidates.Value( aCandIt );
const gp_Pnt2d& aPivotVertex = GetVertex( aCand.PivotNode ).Coord();
// Check is the test link crosses the polygon boundaries
Standard_Boolean isIntersect = Standard_False;
for ( Standard_Integer aRefLinkNodeIt = 0; aRefLinkNodeIt < 2; ++aRefLinkNodeIt )
{
const Standard_Integer& aLinkFirstNode = aNodes[aRefLinkNodeIt];
const Standard_Integer& aLinkFirstNode = aNodes [aRefLinkNodeIt];
const gp_Pnt2d& aLinkFirstVertex = aRefVertices[aRefLinkNodeIt];
Bnd_B2d aBox;
UpdateBndBox(aLinkFirstVertex.Coord(), aPivotVertex.Coord(), aBox);
UpdateBndBox( aLinkFirstVertex.Coord(), aPivotVertex.Coord(), aBox );
BRepMesh_Edge aCheckLink( aLinkFirstNode, aPivotNode, BRepMesh_Free );
BRepMesh_Edge aCheckLink( aLinkFirstNode, aCand.PivotNode, BRepMesh_Free );
Standard_Integer aCheckLinkIt = 2;
for ( ; aCheckLinkIt <= aPolyLen; ++aCheckLinkIt )
{
if( aCheckLinkIt == aLinkIt )
continue;
if ( !aBox.IsOut( thePolyBoxes.Value( aCheckLinkIt ) ) )
{
const BRepMesh_Edge& aPolyLink =
GetEdge( Abs( thePolygon( aCheckLinkIt ) ) );
aSelector.SetCurrent ( aCheckLink, aBox, &thePolygon );
aSelector.SetSkipLink( thePolygon.First(), thePolygon( aCand.LinkId ) );
if ( aCheckLink.IsEqual( aPolyLink ) )
continue;
// intersection is possible...
gp_Pnt2d anIntPnt;
BRepMesh_GeomTool::IntFlag aIntFlag = intSegSeg( aCheckLink, aPolyLink,
Standard_False, Standard_False, anIntPnt );
if( aIntFlag != BRepMesh_GeomTool::NoIntersection )
{
isIntersect = Standard_True;
break;
}
}
}
theSegmentsBoxes.Boxes.Select( aSelector );
isIntersect = aSelector.IsIntersected();
if ( isIntersect )
break;
@@ -2083,17 +2239,16 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
continue;
aOptAngle = aAngle;
aMinDist = anAbsDist;
aNodes[2] = aPivotNode;
aNodes [2] = aCand.PivotNode;
aRefVertices[2] = aPivotVertex;
aUsedLinkId = aLinkIt;
aUsedLinkId = aCand.LinkId;
break;
}
if ( aUsedLinkId == 0 )
{
theSegmentsBoxes.Rebind( thePolygon, nullptr );
thePolygon.Clear();
thePolyBoxes.Clear();
return;
}
@@ -2112,48 +2267,49 @@ void BRepMesh_Delaun::decomposeSimplePolygon(
for ( Standard_Integer aTriEdgeIt = 0; aTriEdgeIt < 3; ++aTriEdgeIt )
{
const Standard_Integer& anEdgeInfo = aNewEdgesInfo[aTriEdgeIt];
anEdges[aTriEdgeIt] = Abs( anEdgeInfo );
anEdges [aTriEdgeIt] = Abs( anEdgeInfo );
anEdgesOri[aTriEdgeIt] = anEdgeInfo > 0;
}
addTriangle( anEdges, anEdgesOri, aNodes );
if (aUsedLinkId == 3)
{
thePolygon.Remove ( 1 );
thePolyBoxes.Remove( 1 );
theSegmentsBoxes.Rebind( thePolygon.First(), nullptr );
thePolygon .Remove( 1 );
thePolygon.SetValue( 1, -aNewEdgesInfo[2] );
Bnd_B2d aBox;
UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox);
thePolyBoxes.SetValue( 1, aBox );
UpdateBndBox( aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox );
theSegmentsBoxes.Add( thePolygon.First(), aBox, &thePolygon );
}
else
{
// Create triangle and split the source polygon on two
// parts (if possible) and mesh each part as independent
// polygon.
if ( aUsedLinkId < aPolyLen )
if ( aUsedLinkId < thePolygon.Length() )
{
thePolygon.Split(aUsedLinkId, thePolygonCut);
thePolygonCut.Prepend( -aNewEdgesInfo[2] );
thePolyBoxes.Split(aUsedLinkId, thePolyBoxesCut);
thePolygon.Split( aUsedLinkId, thePolygonCut );
theSegmentsBoxes.Rebind ( thePolygonCut, &thePolygonCut );
thePolygonCut .Prepend( -aNewEdgesInfo[2] );
Bnd_B2d aBox;
UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox);
thePolyBoxesCut.Prepend( aBox );
UpdateBndBox( aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox );
theSegmentsBoxes.Add( thePolygonCut.First(), aBox, &thePolygonCut );
}
else
{
thePolygon.Remove ( aPolyLen );
thePolyBoxes.Remove( aPolyLen );
theSegmentsBoxes.Rebind( thePolygon.Last (), nullptr );
thePolygon .Remove( thePolygon.Length() );
}
thePolygon.SetValue( 1, -aNewEdgesInfo[1] );
Bnd_B2d aBox;
UpdateBndBox(aRefVertices[1].Coord(), aRefVertices[2].Coord(), aBox);
thePolyBoxes.SetValue( 1, aBox );
UpdateBndBox( aRefVertices[1].Coord(), aRefVertices[2].Coord(), aBox );
theSegmentsBoxes.Add( thePolygon.First(), aBox, &thePolygon );
}
}
@@ -2477,13 +2633,7 @@ BRepMesh_GeomTool::IntFlag BRepMesh_Delaun::intSegSeg(
const Standard_Boolean isConsiderPointOnEdge,
gp_Pnt2d& theIntPnt) const
{
gp_XY p1, p2, p3, p4;
p1 = GetVertex( theEdg1.FirstNode() ).Coord();
p2 = GetVertex( theEdg1.LastNode() ).Coord();
p3 = GetVertex( theEdg2.FirstNode() ).Coord();
p4 = GetVertex( theEdg2.LastNode() ).Coord();
return BRepMesh_GeomTool::IntSegSeg(p1, p2, p3, p4,
return IntSegSeg (myMeshData, theEdg1, theEdg2,
isConsiderEndPointTouch, isConsiderPointOnEdge, theIntPnt);
}

View File

@@ -165,6 +165,42 @@ private:
};
typedef NCollection_DataMap<Standard_Integer, IMeshData::MapOfInteger> DataMapOfMap;
typedef NCollection_DataMap<Standard_Integer, void*> DataMapOfPVoid;
typedef NCollection_EBTree <Standard_Integer, Bnd_B2d> EBTreeOfB2d;
typedef NCollection_UBTreeFiller <Standard_Integer, Bnd_B2d> EBTreeOfB2dFiller;
class EBTreeOfB2d_Selector;
struct SegmentsBoxes
{
EBTreeOfB2d Boxes;
DataMapOfPVoid PolyMap;
void Rebind (const Standard_Integer theLinkInfo,
void* const& thePolygonPtr)
{
PolyMap.Bind (theLinkInfo, thePolygonPtr);
}
void Rebind (IMeshData::SequenceOfInteger& thePolygon,
void* const& thePolygonPtr)
{
Standard_Integer aLinkIt = thePolygon.Lower();
for (; aLinkIt <= thePolygon.Upper(); ++aLinkIt)
{
const Standard_Integer aLinkInfo = thePolygon (aLinkIt);
Rebind (aLinkInfo, thePolygonPtr);
}
}
void Add (const Standard_Integer theLinkInfo,
const Bnd_B2d& theBox,
void* const& thePolygonPtr)
{
PolyMap.Bind (theLinkInfo, thePolygonPtr);
Boxes .Add (theLinkInfo, theBox);
}
};
//! Performs initialization of circles cell filter tool.
void initCirclesTool (const Bnd_Box2d& theBox,
@@ -245,14 +281,12 @@ private:
//! In case if source polygon consists of three links, creates new triangle
//! and clears source container.
//! @param thePolygon source polygon to be decomposed (first part of decomposition).
//! @param thePolyBoxes bounding boxes corresponded to source polygon's links.
//! @param thePolygonCut product of decomposition of source polygon (second part of decomposition).
//! @param thePolyBoxesCut bounding boxes corresponded to resulting polygon's links.
//! @param theSegmentsBoxes map of relations between semgents and their polygons.
void decomposeSimplePolygon (
IMeshData::SequenceOfInteger& thePolygon,
IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::SequenceOfInteger& thePolygonCut,
IMeshData::SequenceOfBndB2d& thePolyBoxesCut);
SegmentsBoxes& theSegmentsBoxes);
//! Triangulation of closed polygon containing only three edges.
Standard_Boolean meshElementaryPolygon (const IMeshData::SequenceOfInteger& thePolygon);

14
tests/bugs/mesh/bug31586 Normal file
View File

@@ -0,0 +1,14 @@
puts "========"
puts "0031586: BRepMesh hangs up"
puts "========"
puts ""
puts "TODO OCC31586 All: Not connected mesh inside face"
restore [locate_data_file bug31586.brep] result
incmesh result 0.022627417117969499
checkview -display result -3d -path ${imagedir}/${test_image}.png
tricheck result