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 :
}
}
- IMeshData::SequenceOfInteger* aPolygon1 = &thePolygon;
- IMeshData::SequenceOfBndB2d* aPolyBoxes1 = &thePolyBoxes;
+ SegmentsBoxes aSegmentsBoxes;
+ EBTreeOfB2dFiller aTreeFiller( aSegmentsBoxes.Boxes );
+
+ 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();
- Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger;
- Handle(IMeshData::SequenceOfBndB2d) aPolyBoxes2 = new IMeshData::SequenceOfBndB2d;
+ 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())
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());
}
}
}
//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;
}
Standard_Real aRefEdgeLen = aRefEdgeDir.Magnitude();
if ( aRefEdgeLen < Precision )
{
+ theSegmentsBoxes.Rebind( thePolygon, nullptr );
thePolygon.Clear();
- thePolyBoxes.Clear();
return;
}
// 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 )
+ NCollection_Vector<Candidate> aCandidates( thePolygon.Length() );
+
+ for ( Standard_Integer aLinkIt = 3; aLinkIt <= thePolygon.Length(); ++aLinkIt )
{
- Standard_Integer aLinkInfo = thePolygon( aLinkIt );
- const BRepMesh_Edge& aNextEdge = GetEdge( Abs( aLinkInfo ) );
+ const Standard_Integer aLinkInfo = thePolygon( aLinkIt );
+ const BRepMesh_Edge& aNextEdge = GetEdge( Abs( aLinkInfo ) );
- aPivotNode = aLinkInfo > 0 ?
+ 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])
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;
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;
}
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 );
}
}
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);
}