1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-06-10 11:34:06 +03:00
occt/src/BRepMesh/BRepMesh_Delaun.cxx
Pasukhin Dmitry 1f386af59f
Coding - Update method guards for consistency #333
Apply new regex replacement with method's guards in .cxx
Update GH workflow with style checking
2025-02-03 11:16:00 +00:00

2568 lines
89 KiB
C++

// Created on: 1993-05-12
// Created by: Didier PIFFAULT
// Copyright (c) 1993-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_Delaun.hxx>
#include <gp_XY.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec2d.hxx>
#include <Precision.hxx>
#include <Bnd_Box2d.hxx>
#include <Bnd_B2d.hxx>
#include <BRepMesh_SelectorOfDataStructureOfDelaun.hxx>
#include <BRepMesh_Edge.hxx>
#include <BRepMesh_Vertex.hxx>
#include <BRepMesh_Triangle.hxx>
#include <NCollection_Vector.hxx>
#include <algorithm>
#include <stack>
const Standard_Real AngDeviation1Deg = M_PI / 180.;
const Standard_Real AngDeviation90Deg = 90 * AngDeviation1Deg;
const Standard_Real Angle2PI = 2 * M_PI;
const Standard_Real Precision = Precision::PConfusion();
const Standard_Real Precision2 = Precision * Precision;
namespace
{
//! Sort two points in projection on vector (1,1)
struct ComparatorOfVertexOfDelaun
{
bool operator()(const BRepMesh_Vertex& theLeft, const BRepMesh_Vertex& theRight)
{
return theLeft.Coord().X() + theLeft.Coord().Y() < theRight.Coord().X() + theRight.Coord().Y();
}
};
//! Sort two points in projection on vector (1,1)
struct ComparatorOfIndexedVertexOfDelaun
{
public:
ComparatorOfIndexedVertexOfDelaun(const Handle(BRepMesh_DataStructureOfDelaun)& theDS)
: myStructure(theDS)
{
}
bool operator()(Standard_Integer theLeft, Standard_Integer theRight)
{
const BRepMesh_Vertex& aLeft = myStructure->GetNode(theLeft);
const BRepMesh_Vertex& aRight = myStructure->GetNode(theRight);
return ComparatorOfVertexOfDelaun()(aLeft, aRight);
}
private:
Handle(BRepMesh_DataStructureOfDelaun) myStructure;
};
void UpdateBndBox(const gp_XY& thePnt1, const gp_XY& thePnt2, Bnd_B2d& theBox)
{
theBox.Add(thePnt1);
theBox.Add(thePnt2);
theBox.Enlarge(Precision);
}
} // anonymous namespace
//=================================================================================================
BRepMesh_Delaun::BRepMesh_Delaun(const Handle(BRepMesh_DataStructureOfDelaun)& theOldMesh,
const Standard_Integer theCellsCountU,
const Standard_Integer theCellsCountV,
const Standard_Boolean isFillCircles)
: myMeshData(theOldMesh),
myCircles(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)),
mySupVert(3),
myInitCircles(Standard_False)
{
if (isFillCircles)
{
InitCirclesTool(theCellsCountU, theCellsCountV);
}
}
//=======================================================================
// function : BRepMesh_Delaun
// purpose : Creates the triangulation with an empty Mesh data structure
//=======================================================================
BRepMesh_Delaun::BRepMesh_Delaun(IMeshData::Array1OfVertexOfDelaun& theVertices)
: myCircles(theVertices.Length(),
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)),
mySupVert(3),
myInitCircles(Standard_False)
{
if (theVertices.Length() > 2)
{
myMeshData = new BRepMesh_DataStructureOfDelaun(
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE),
theVertices.Length());
Init(theVertices);
}
}
//=======================================================================
// function : BRepMesh_Delaun
// purpose : Creates the triangulation with and existent Mesh data structure
//=======================================================================
BRepMesh_Delaun::BRepMesh_Delaun(const Handle(BRepMesh_DataStructureOfDelaun)& theOldMesh,
IMeshData::Array1OfVertexOfDelaun& theVertices)
: myMeshData(theOldMesh),
myCircles(theVertices.Length(),
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)),
mySupVert(3),
myInitCircles(Standard_False)
{
if (theVertices.Length() > 2)
{
Init(theVertices);
}
}
//=======================================================================
// function : BRepMesh_Delaun
// purpose : Creates the triangulation with and existent Mesh data structure
//=======================================================================
BRepMesh_Delaun::BRepMesh_Delaun(const Handle(BRepMesh_DataStructureOfDelaun)& theOldMesh,
IMeshData::VectorOfInteger& theVertexIndices)
: myMeshData(theOldMesh),
myCircles(theVertexIndices.Length(),
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)),
mySupVert(3),
myInitCircles(Standard_False)
{
perform(theVertexIndices);
}
//=======================================================================
// function : BRepMesh_Delaun
// purpose : Creates the triangulation with and existent Mesh data structure
//=======================================================================
BRepMesh_Delaun::BRepMesh_Delaun(const Handle(BRepMesh_DataStructureOfDelaun)& theOldMesh,
IMeshData::VectorOfInteger& theVertexIndices,
const Standard_Integer theCellsCountU,
const Standard_Integer theCellsCountV)
: myMeshData(theOldMesh),
myCircles(theVertexIndices.Length(),
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)),
mySupVert(3),
myInitCircles(Standard_False)
{
perform(theVertexIndices, theCellsCountU, theCellsCountV);
}
//=======================================================================
// function : Init
// purpose : Initializes the triangulation with an Array of Vertex
//=======================================================================
void BRepMesh_Delaun::Init(IMeshData::Array1OfVertexOfDelaun& theVertices)
{
Standard_Integer aLowerIdx = theVertices.Lower();
Standard_Integer anUpperIdx = theVertices.Upper();
IMeshData::VectorOfInteger aVertexIndexes(theVertices.Size());
Standard_Integer anIndex = aLowerIdx;
for (; anIndex <= anUpperIdx; ++anIndex)
{
aVertexIndexes.Append(myMeshData->AddNode(theVertices(anIndex)));
}
perform(aVertexIndexes);
}
//=================================================================================================
void BRepMesh_Delaun::InitCirclesTool(const Standard_Integer theCellsCountU,
const Standard_Integer theCellsCountV)
{
Bnd_Box2d aBox;
for (Standard_Integer aNodeIt = 1; aNodeIt <= myMeshData->NbNodes(); ++aNodeIt)
{
aBox.Add(gp_Pnt2d(GetVertex(aNodeIt).Coord()));
}
aBox.Enlarge(Precision);
initCirclesTool(aBox, theCellsCountU, theCellsCountV);
IMeshData::IteratorOfMapOfInteger aTriangleIt(myMeshData->ElementsOfDomain());
for (; aTriangleIt.More(); aTriangleIt.Next())
{
Standard_Integer aNodesIndices[3];
const BRepMesh_Triangle& aTriangle = myMeshData->GetElement(aTriangleIt.Key());
myMeshData->ElementNodes(aTriangle, aNodesIndices);
myCircles.Bind(aTriangleIt.Key(),
GetVertex(aNodesIndices[0]).Coord(),
GetVertex(aNodesIndices[1]).Coord(),
GetVertex(aNodesIndices[2]).Coord());
}
}
//=================================================================================================
void BRepMesh_Delaun::initCirclesTool(const Bnd_Box2d& theBox,
const Standard_Integer theCellsCountU,
const Standard_Integer theCellsCountV)
{
Standard_Real aMinX, aMinY, aMaxX, aMaxY;
theBox.Get(aMinX, aMinY, aMaxX, aMaxY);
const Standard_Real aDeltaX = aMaxX - aMinX;
const Standard_Real aDeltaY = aMaxY - aMinY;
Standard_Integer aScaler = 2;
if (myMeshData->NbNodes() > 100)
{
aScaler = 5;
}
else if (myMeshData->NbNodes() > 1000)
{
aScaler = 7;
}
myCircles.SetMinMaxSize(gp_XY(aMinX, aMinY), gp_XY(aMaxX, aMaxY));
myCircles.SetCellSize(aDeltaX / Max(theCellsCountU, aScaler),
aDeltaY / Max(theCellsCountV, aScaler));
myInitCircles = Standard_True;
}
//=======================================================================
// function : perform
// purpose : Create super mesh and run triangulation procedure
//=======================================================================
void BRepMesh_Delaun::perform(IMeshData::VectorOfInteger& theVertexIndices,
const Standard_Integer theCellsCountU /* = -1 */,
const Standard_Integer theCellsCountV /* = -1 */)
{
if (theVertexIndices.Length() <= 2)
{
return;
}
Bnd_Box2d aBox;
Standard_Integer anIndex = theVertexIndices.Lower();
Standard_Integer anUpper = theVertexIndices.Upper();
for (; anIndex <= anUpper; ++anIndex)
{
aBox.Add(gp_Pnt2d(GetVertex(theVertexIndices(anIndex)).Coord()));
}
aBox.Enlarge(Precision);
initCirclesTool(aBox, theCellsCountU, theCellsCountV);
superMesh(aBox);
ComparatorOfIndexedVertexOfDelaun aCmp(myMeshData);
std::make_heap(theVertexIndices.begin(), theVertexIndices.end(), aCmp);
std::sort_heap(theVertexIndices.begin(), theVertexIndices.end(), aCmp);
compute(theVertexIndices);
}
//=======================================================================
// function : superMesh
// purpose : Build the super mesh
//=======================================================================
void BRepMesh_Delaun::superMesh(const Bnd_Box2d& theBox)
{
Standard_Real aMinX, aMinY, aMaxX, aMaxY;
theBox.Get(aMinX, aMinY, aMaxX, aMaxY);
Standard_Real aDeltaX = aMaxX - aMinX;
Standard_Real aDeltaY = aMaxY - aMinY;
Standard_Real aDeltaMin = Min(aDeltaX, aDeltaY);
Standard_Real aDeltaMax = Max(aDeltaX, aDeltaY);
Standard_Real aDelta = aDeltaX + aDeltaY;
mySupVert.Append(
myMeshData->AddNode(BRepMesh_Vertex((aMinX + aMaxX) / 2, aMaxY + aDeltaMax, BRepMesh_Free)));
mySupVert.Append(
myMeshData->AddNode(BRepMesh_Vertex(aMinX - aDelta, aMinY - aDeltaMin, BRepMesh_Free)));
mySupVert.Append(
myMeshData->AddNode(BRepMesh_Vertex(aMaxX + aDelta, aMinY - aDeltaMin, BRepMesh_Free)));
Standard_Integer e[3];
Standard_Boolean o[3];
for (Standard_Integer aNodeId = 0; aNodeId < 3; ++aNodeId)
{
Standard_Integer aFirstNode = aNodeId;
Standard_Integer aLastNode = (aNodeId + 1) % 3;
Standard_Integer aLinkIndex = myMeshData->AddLink(
BRepMesh_Edge(mySupVert[aFirstNode], mySupVert[aLastNode], BRepMesh_Free));
e[aNodeId] = Abs(aLinkIndex);
o[aNodeId] = (aLinkIndex > 0);
}
mySupTrian = BRepMesh_Triangle(e, o, BRepMesh_Free);
}
//=======================================================================
// function : deleteTriangle
// purpose : Deletes the triangle with the given index and adds the free
// edges into the map.
// When an edge is suppressed more than one time it is destroyed.
//=======================================================================
void BRepMesh_Delaun::deleteTriangle(const Standard_Integer theIndex,
IMeshData::MapOfIntegerInteger& theLoopEdges)
{
if (myInitCircles)
{
myCircles.Delete(theIndex);
}
const BRepMesh_Triangle& aElement = GetTriangle(theIndex);
const Standard_Integer(&e)[3] = aElement.myEdges;
const Standard_Boolean(&o)[3] = aElement.myOrientations;
myMeshData->RemoveElement(theIndex);
for (Standard_Integer i = 0; i < 3; ++i)
{
if (!theLoopEdges.Bind(e[i], o[i]))
{
theLoopEdges.UnBind(e[i]);
myMeshData->RemoveLink(e[i]);
}
}
}
//=======================================================================
// function : compute
// purpose : Computes the triangulation and add the vertices edges and
// triangles to the Mesh data structure
//=======================================================================
void BRepMesh_Delaun::compute(IMeshData::VectorOfInteger& theVertexIndexes)
{
// Insertion of edges of super triangles in the list of free edges:
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
IMeshData::MapOfIntegerInteger aLoopEdges(10, aAllocator);
const Standard_Integer(&e)[3] = mySupTrian.myEdges;
aLoopEdges.Bind(e[0], Standard_True);
aLoopEdges.Bind(e[1], Standard_True);
aLoopEdges.Bind(e[2], Standard_True);
if (theVertexIndexes.Length() > 0)
{
// Creation of 3 trianglers with the first node and the edges of the super triangle:
Standard_Integer anVertexIdx = theVertexIndexes.Lower();
createTriangles(theVertexIndexes(anVertexIdx), aLoopEdges);
// Add other nodes to the mesh
createTrianglesOnNewVertices(theVertexIndexes, Message_ProgressRange());
}
RemoveAuxElements();
}
//=================================================================================================
void BRepMesh_Delaun::RemoveAuxElements()
{
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
IMeshData::MapOfIntegerInteger aLoopEdges(10, aAllocator);
// Destruction of triangles containing a top of the super triangle
BRepMesh_SelectorOfDataStructureOfDelaun aSelector(myMeshData);
for (Standard_Integer aSupVertId = 0; aSupVertId < mySupVert.Size(); ++aSupVertId)
aSelector.NeighboursOfNode(mySupVert[aSupVertId]);
IMeshData::IteratorOfMapOfInteger aFreeTriangles(aSelector.Elements());
for (; aFreeTriangles.More(); aFreeTriangles.Next())
deleteTriangle(aFreeTriangles.Key(), aLoopEdges);
// All edges that remain free are removed from aLoopEdges;
// only the boundary edges of the triangulation remain there
IMeshData::MapOfIntegerInteger::Iterator aFreeEdges(aLoopEdges);
for (; aFreeEdges.More(); aFreeEdges.Next())
{
if (myMeshData->ElementsConnectedTo(aFreeEdges.Key()).IsEmpty())
myMeshData->RemoveLink(aFreeEdges.Key());
}
// The tops of the super triangle are destroyed
for (Standard_Integer aSupVertId = 0; aSupVertId < mySupVert.Size(); ++aSupVertId)
myMeshData->RemoveNode(mySupVert[aSupVertId]);
}
//=======================================================================
// function : createTriangles
// purpose : Creates the triangles between the node and the polyline.
//=======================================================================
void BRepMesh_Delaun::createTriangles(const Standard_Integer theVertexIndex,
IMeshData::MapOfIntegerInteger& thePoly)
{
IMeshData::ListOfInteger aLoopEdges, anExternalEdges;
const gp_XY& aVertexCoord = myMeshData->GetNode(theVertexIndex).Coord();
IMeshData::MapOfIntegerInteger::Iterator anEdges(thePoly);
for (; anEdges.More(); anEdges.Next())
{
Standard_Integer anEdgeId = anEdges.Key();
const BRepMesh_Edge& anEdge = GetEdge(anEdgeId);
Standard_Boolean isPositive = thePoly(anEdgeId) != 0;
Standard_Integer aNodes[3];
if (isPositive)
{
aNodes[0] = anEdge.FirstNode();
aNodes[2] = anEdge.LastNode();
}
else
{
aNodes[0] = anEdge.LastNode();
aNodes[2] = anEdge.FirstNode();
}
aNodes[1] = theVertexIndex;
const BRepMesh_Vertex& aFirstVertex = GetVertex(aNodes[0]);
const BRepMesh_Vertex& aLastVertex = GetVertex(aNodes[2]);
gp_XY anEdgeDir(aLastVertex.Coord() - aFirstVertex.Coord());
Standard_Real anEdgeLen = anEdgeDir.Modulus();
if (anEdgeLen < Precision)
continue;
anEdgeDir.SetCoord(anEdgeDir.X() / anEdgeLen, anEdgeDir.Y() / anEdgeLen);
gp_XY aFirstLinkDir(aFirstVertex.Coord() - aVertexCoord);
gp_XY aLastLinkDir(aVertexCoord - aLastVertex.Coord());
Standard_Real aDist12 = aFirstLinkDir ^ anEdgeDir;
Standard_Real aDist23 = anEdgeDir ^ aLastLinkDir;
if (Abs(aDist12) < Precision || Abs(aDist23) < Precision)
{
continue;
}
BRepMesh_Edge aFirstLink(aNodes[1], aNodes[0], BRepMesh_Free);
BRepMesh_Edge aLastLink(aNodes[2], aNodes[1], BRepMesh_Free);
Standard_Integer anEdgesInfo[3] = {myMeshData->AddLink(aFirstLink),
isPositive ? anEdgeId : -anEdgeId,
myMeshData->AddLink(aLastLink)};
Standard_Boolean isSensOK = (aDist12 > 0. && aDist23 > 0.);
if (isSensOK)
{
Standard_Integer anEdgeIds[3];
Standard_Boolean anEdgesOri[3];
for (Standard_Integer aTriLinkIt = 0; aTriLinkIt < 3; ++aTriLinkIt)
{
const Standard_Integer& anEdgeInfo = anEdgesInfo[aTriLinkIt];
anEdgeIds[aTriLinkIt] = Abs(anEdgeInfo);
anEdgesOri[aTriLinkIt] = anEdgeInfo > 0;
}
addTriangle(anEdgeIds, anEdgesOri, aNodes);
}
else
{
if (isPositive)
aLoopEdges.Append(anEdges.Key());
else
aLoopEdges.Append(-anEdges.Key());
if (aFirstLinkDir.SquareModulus() > aLastLinkDir.SquareModulus())
anExternalEdges.Append(Abs(anEdgesInfo[0]));
else
anExternalEdges.Append(Abs(anEdgesInfo[2]));
}
}
thePoly.Clear();
while (!anExternalEdges.IsEmpty())
{
const BRepMesh_PairOfIndex& aPair =
myMeshData->ElementsConnectedTo(Abs(anExternalEdges.First()));
if (!aPair.IsEmpty())
deleteTriangle(aPair.FirstIndex(), thePoly);
anExternalEdges.RemoveFirst();
}
for (anEdges.Initialize(thePoly); anEdges.More(); anEdges.Next())
{
if (myMeshData->ElementsConnectedTo(anEdges.Key()).IsEmpty())
myMeshData->RemoveLink(anEdges.Key());
}
while (!aLoopEdges.IsEmpty())
{
const BRepMesh_Edge& anEdge = GetEdge(Abs(aLoopEdges.First()));
if (anEdge.Movability() != BRepMesh_Deleted)
{
Standard_Integer anEdgeIdx = aLoopEdges.First();
meshLeftPolygonOf(Abs(anEdgeIdx), (anEdgeIdx > 0));
}
aLoopEdges.RemoveFirst();
}
}
//=======================================================================
// function : createTrianglesOnNewVertices
// purpose : Creation of triangles from the new nodes
//=======================================================================
void BRepMesh_Delaun::createTrianglesOnNewVertices(IMeshData::VectorOfInteger& theVertexIndexes,
const Message_ProgressRange& theRange)
{
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
Standard_Real aTolU, aTolV;
myMeshData->Data()->GetTolerance(aTolU, aTolV);
const Standard_Real aSqTol = aTolU * aTolU + aTolV * aTolV;
// Insertion of nodes :
Standard_Boolean isModify = Standard_True;
Standard_Integer anIndex = theVertexIndexes.Lower();
Standard_Integer anUpper = theVertexIndexes.Upper();
Message_ProgressScope aPS(theRange, "Create triangles on new vertices", anUpper);
for (; anIndex <= anUpper; ++anIndex, aPS.Next())
{
if (!aPS.More())
{
return;
}
aAllocator->Reset(Standard_False);
IMeshData::MapOfIntegerInteger aLoopEdges(10, aAllocator);
Standard_Integer aVertexIdx = theVertexIndexes(anIndex);
const BRepMesh_Vertex& aVertex = GetVertex(aVertexIdx);
// Iterator in the list of indexes of circles containing the node
IMeshData::ListOfInteger& aCirclesList = myCircles.Select(aVertex.Coord());
Standard_Integer onEgdeId = 0, aTriangleId = 0;
IMeshData::ListOfInteger::Iterator aCircleIt(aCirclesList);
for (; aCircleIt.More(); aCircleIt.Next())
{
// To add a node in the mesh it is necessary to check conditions:
// - the node should be within the boundaries of the mesh and so in an existing triangle
// - all adjacent triangles should belong to a component connected with this triangle
if (Contains(aCircleIt.Value(), aVertex, aSqTol, onEgdeId))
{
if (onEgdeId != 0 && GetEdge(onEgdeId).Movability() != BRepMesh_Free)
{
// We can skip free vertex too close to the frontier edge.
if (aVertex.Movability() == BRepMesh_Free)
continue;
// However, we should add vertex that have neighboring frontier edges.
}
// Remove triangle even if it contains frontier edge in order
// to prevent appearance of incorrect configurations like free
// edge glued with frontier #26407
aTriangleId = aCircleIt.Value();
aCirclesList.Remove(aCircleIt);
break;
}
}
if (aTriangleId > 0)
{
deleteTriangle(aTriangleId, aLoopEdges);
isModify = Standard_True;
while (isModify && !aCirclesList.IsEmpty())
{
isModify = Standard_False;
IMeshData::ListOfInteger::Iterator aCircleIt1(aCirclesList);
for (; aCircleIt1.More(); aCircleIt1.Next())
{
const BRepMesh_Triangle& aElement = GetTriangle(aCircleIt1.Value());
const Standard_Integer(&e)[3] = aElement.myEdges;
if (aLoopEdges.IsBound(e[0]) || aLoopEdges.IsBound(e[1]) || aLoopEdges.IsBound(e[2]))
{
isModify = Standard_True;
deleteTriangle(aCircleIt1.Value(), aLoopEdges);
aCirclesList.Remove(aCircleIt1);
break;
}
}
}
// Creation of triangles with the current node and free edges
// and removal of these edges from the list of free edges
createTriangles(aVertexIdx, aLoopEdges);
}
}
ProcessConstraints();
}
//=================================================================================================
void BRepMesh_Delaun::insertInternalEdges()
{
Handle(IMeshData::MapOfInteger) anInternalEdges = InternalEdges();
// Destruction of triangles intersecting internal edges
// and their replacement by makeshift triangles
IMeshData::IteratorOfMapOfInteger anInernalEdgesIt(*anInternalEdges);
for (; anInernalEdgesIt.More(); anInernalEdgesIt.Next())
{
const Standard_Integer aLinkIndex = anInernalEdgesIt.Key();
const BRepMesh_PairOfIndex& aPair = myMeshData->ElementsConnectedTo(aLinkIndex);
// Check both sides of link for adjusted triangle.
Standard_Boolean isGo[2] = {Standard_True, Standard_True};
for (Standard_Integer aTriangleIt = 1; aTriangleIt <= aPair.Extent(); ++aTriangleIt)
{
const BRepMesh_Triangle& aElement = GetTriangle(aPair.Index(aTriangleIt));
const Standard_Integer(&e)[3] = aElement.myEdges;
const Standard_Boolean(&o)[3] = aElement.myOrientations;
for (Standard_Integer i = 0; i < 3; ++i)
{
if (e[i] == aLinkIndex)
{
isGo[o[i] ? 0 : 1] = Standard_False;
break;
}
}
}
if (isGo[0])
{
meshLeftPolygonOf(aLinkIndex, Standard_True);
}
if (isGo[1])
{
meshLeftPolygonOf(aLinkIndex, Standard_False);
}
}
}
//=================================================================================================
Standard_Boolean BRepMesh_Delaun::isBoundToFrontier(const Standard_Integer theRefNodeId,
const Standard_Integer theRefLinkId)
{
std::stack<Standard_Integer> aLinkStack;
TColStd_PackedMapOfInteger aVisitedLinks;
aLinkStack.push(theRefLinkId);
while (!aLinkStack.empty())
{
const Standard_Integer aCurrentLinkId = aLinkStack.top();
aLinkStack.pop();
const BRepMesh_PairOfIndex& aPair = myMeshData->ElementsConnectedTo(aCurrentLinkId);
if (aPair.IsEmpty())
return Standard_False;
const Standard_Integer aNbElements = aPair.Extent();
for (Standard_Integer anElemIt = 1; anElemIt <= aNbElements; ++anElemIt)
{
const Standard_Integer aTriId = aPair.Index(anElemIt);
if (aTriId < 0)
continue;
const BRepMesh_Triangle& aElement = GetTriangle(aTriId);
const Standard_Integer(&anEdges)[3] = aElement.myEdges;
for (Standard_Integer anEdgeIt = 0; anEdgeIt < 3; ++anEdgeIt)
{
const Standard_Integer anEdgeId = anEdges[anEdgeIt];
if (anEdgeId == aCurrentLinkId)
continue;
const BRepMesh_Edge& anEdge = GetEdge(anEdgeId);
if (anEdge.FirstNode() != theRefNodeId && anEdge.LastNode() != theRefNodeId)
{
continue;
}
if (anEdge.Movability() != BRepMesh_Free)
return Standard_True;
if (aVisitedLinks.Add(anEdgeId))
{
aLinkStack.push(anEdgeId);
}
}
}
}
return Standard_False;
}
//=======================================================================
// function : cleanupMesh
// purpose : Cleanup mesh from the free triangles
//=======================================================================
void BRepMesh_Delaun::cleanupMesh()
{
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
for (;;)
{
aAllocator->Reset(Standard_False);
IMeshData::MapOfIntegerInteger aLoopEdges(10, aAllocator);
IMeshData::MapOfInteger aDelTriangles;
Handle(IMeshData::MapOfInteger) aFreeEdges = FreeEdges();
IMeshData::IteratorOfMapOfInteger aFreeEdgesIt(*aFreeEdges);
for (; aFreeEdgesIt.More(); aFreeEdgesIt.Next())
{
const Standard_Integer& aFreeEdgeId = aFreeEdgesIt.Key();
const BRepMesh_Edge& anEdge = GetEdge(aFreeEdgeId);
if (anEdge.Movability() == BRepMesh_Frontier)
continue;
const BRepMesh_PairOfIndex& aPair = myMeshData->ElementsConnectedTo(aFreeEdgeId);
if (aPair.IsEmpty())
{
aLoopEdges.Bind(aFreeEdgeId, Standard_True);
continue;
}
Standard_Integer aTriId = aPair.FirstIndex();
// Check that the connected triangle is not surrounded by another triangles
const BRepMesh_Triangle& aElement = GetTriangle(aTriId);
const Standard_Integer(&anEdges)[3] = aElement.myEdges;
Standard_Boolean isCanNotBeRemoved = Standard_True;
for (Standard_Integer aCurEdgeIdx = 0; aCurEdgeIdx < 3; ++aCurEdgeIdx)
{
if (anEdges[aCurEdgeIdx] != aFreeEdgeId)
continue;
for (Standard_Integer anOtherEdgeIt = 1; anOtherEdgeIt <= 2 && isCanNotBeRemoved;
++anOtherEdgeIt)
{
Standard_Integer anOtherEdgeId = (aCurEdgeIdx + anOtherEdgeIt) % 3;
const BRepMesh_PairOfIndex& anOtherEdgePair =
myMeshData->ElementsConnectedTo(anEdges[anOtherEdgeId]);
if (anOtherEdgePair.Extent() < 2)
{
isCanNotBeRemoved = Standard_False;
}
else
{
for (int aTriIdx = 1; aTriIdx <= anOtherEdgePair.Extent() && isCanNotBeRemoved;
++aTriIdx)
{
if (anOtherEdgePair.Index(aTriIdx) == aTriId)
continue;
Standard_Integer v[3];
const BRepMesh_Triangle& aCurTriangle = GetTriangle(anOtherEdgePair.Index(aTriIdx));
myMeshData->ElementNodes(aCurTriangle, v);
for (int aNodeIdx = 0; aNodeIdx < 3 && isCanNotBeRemoved; ++aNodeIdx)
{
if (isSupVertex(v[aNodeIdx]))
{
isCanNotBeRemoved = Standard_False;
}
}
}
}
}
break;
}
if (isCanNotBeRemoved)
continue;
Standard_Boolean isConnected[2] = {Standard_False, Standard_False};
for (Standard_Integer aLinkNodeIt = 0; aLinkNodeIt < 2; ++aLinkNodeIt)
{
isConnected[aLinkNodeIt] =
isBoundToFrontier((aLinkNodeIt == 0) ? anEdge.FirstNode() : anEdge.LastNode(),
aFreeEdgeId);
}
if (!isConnected[0] || !isConnected[1])
aDelTriangles.Add(aTriId);
}
// Destruction of triangles :
Standard_Integer aDeletedTrianglesNb = 0;
IMeshData::IteratorOfMapOfInteger aDelTrianglesIt(aDelTriangles);
for (; aDelTrianglesIt.More(); aDelTrianglesIt.Next())
{
deleteTriangle(aDelTrianglesIt.Key(), aLoopEdges);
aDeletedTrianglesNb++;
}
// Destruction of remaining hanging edges
IMeshData::MapOfIntegerInteger::Iterator aLoopEdgesIt(aLoopEdges);
for (; aLoopEdgesIt.More(); aLoopEdgesIt.Next())
{
if (myMeshData->ElementsConnectedTo(aLoopEdgesIt.Key()).IsEmpty())
myMeshData->RemoveLink(aLoopEdgesIt.Key());
}
if (aDeletedTrianglesNb == 0)
break;
}
}
//=======================================================================
// function : frontierAdjust
// purpose : Adjust the mesh on the frontier
//=======================================================================
void BRepMesh_Delaun::frontierAdjust()
{
Handle(IMeshData::MapOfInteger) aFrontier = Frontier();
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
IMeshData::VectorOfInteger aFailedFrontiers(256, aAllocator);
IMeshData::MapOfIntegerInteger aLoopEdges(10, aAllocator);
Handle(IMeshData::MapOfInteger) aIntFrontierEdges = new IMeshData::MapOfInteger;
for (Standard_Integer aPass = 1; aPass <= 2; ++aPass)
{
// 1 pass): find external triangles on boundary edges;
// 2 pass): find external triangles on boundary edges appeared
// during triangles replacement.
IMeshData::IteratorOfMapOfInteger aFrontierIt(*aFrontier);
for (; aFrontierIt.More(); aFrontierIt.Next())
{
Standard_Integer aFrontierId = aFrontierIt.Key();
const BRepMesh_PairOfIndex& aPair = myMeshData->ElementsConnectedTo(aFrontierId);
Standard_Integer aNbElem = aPair.Extent();
for (Standard_Integer aElemIt = 1; aElemIt <= aNbElem; ++aElemIt)
{
const Standard_Integer aPriorElemId = aPair.Index(aElemIt);
if (aPriorElemId < 0)
continue;
const BRepMesh_Triangle& aElement = GetTriangle(aPriorElemId);
const Standard_Integer(&e)[3] = aElement.myEdges;
const Standard_Boolean(&o)[3] = aElement.myOrientations;
Standard_Boolean isTriangleFound = Standard_False;
for (Standard_Integer n = 0; n < 3; ++n)
{
if (aFrontierId == e[n] && !o[n])
{
// Destruction of external triangles on boundary edges
isTriangleFound = Standard_True;
deleteTriangle(aPriorElemId, aLoopEdges);
break;
}
}
if (isTriangleFound)
break;
}
}
// destrucrion of remaining hanging edges :
IMeshData::MapOfIntegerInteger::Iterator aLoopEdgesIt(aLoopEdges);
for (; aLoopEdgesIt.More(); aLoopEdgesIt.Next())
{
Standard_Integer aLoopEdgeId = aLoopEdgesIt.Key();
if (myMeshData->ElementsConnectedTo(aLoopEdgeId).IsEmpty())
myMeshData->RemoveLink(aLoopEdgeId);
}
// destruction of triangles crossing the boundary edges and
// their replacement by makeshift triangles
for (aFrontierIt.Reset(); aFrontierIt.More(); aFrontierIt.Next())
{
Standard_Integer aFrontierId = aFrontierIt.Key();
if (!myMeshData->ElementsConnectedTo(aFrontierId).IsEmpty())
continue;
Standard_Boolean isSuccess = meshLeftPolygonOf(aFrontierId, Standard_True, aIntFrontierEdges);
if (aPass == 2 && !isSuccess)
aFailedFrontiers.Append(aFrontierId);
}
}
cleanupMesh();
// When the mesh has been cleaned up, try to process frontier edges
// once again to fill the possible gaps that might be occurred in case of "saw" -
// situation when frontier edge has a triangle at a right side, but its free
// links cross another frontieres and meshLeftPolygonOf itself can't collect
// a closed polygon.
IMeshData::VectorOfInteger::Iterator aFailedFrontiersIt(aFailedFrontiers);
for (; aFailedFrontiersIt.More(); aFailedFrontiersIt.Next())
{
Standard_Integer aFrontierId = aFailedFrontiersIt.Value();
if (!myMeshData->ElementsConnectedTo(aFrontierId).IsEmpty())
continue;
meshLeftPolygonOf(aFrontierId, Standard_True, aIntFrontierEdges);
}
}
//=======================================================================
// function : fillBndBox
// purpose : Add bounding box for edge defined by start & end point to
// the given vector of bounding boxes for triangulation edges
//=======================================================================
void BRepMesh_Delaun::fillBndBox(IMeshData::SequenceOfBndB2d& theBoxes,
const BRepMesh_Vertex& theV1,
const BRepMesh_Vertex& theV2)
{
Bnd_B2d aBox;
UpdateBndBox(theV1.Coord(), theV2.Coord(), aBox);
theBoxes.Append(aBox);
}
//=======================================================================
// function : meshLeftPolygonOf
// purpose : Collect the polygon at the left of the given edge (material side)
//=======================================================================
Standard_Boolean BRepMesh_Delaun::meshLeftPolygonOf(const Standard_Integer theStartEdgeId,
const Standard_Boolean isForward,
Handle(IMeshData::MapOfInteger) theSkipped)
{
if (!theSkipped.IsNull() && theSkipped->Contains(theStartEdgeId))
return Standard_True;
const BRepMesh_Edge& aRefEdge = GetEdge(theStartEdgeId);
IMeshData::SequenceOfInteger aPolygon;
Standard_Integer aStartNode, aPivotNode;
if (isForward)
{
aPolygon.Append(theStartEdgeId);
aStartNode = aRefEdge.FirstNode();
aPivotNode = aRefEdge.LastNode();
}
else
{
aPolygon.Append(-theStartEdgeId);
aStartNode = aRefEdge.LastNode();
aPivotNode = aRefEdge.FirstNode();
}
const BRepMesh_Vertex& aStartEdgeVertexS = GetVertex(aStartNode);
BRepMesh_Vertex aPivotVertex = GetVertex(aPivotNode);
gp_Vec2d aRefLinkDir(aPivotVertex.Coord() - aStartEdgeVertexS.Coord());
if (aRefLinkDir.SquareMagnitude() < Precision2)
return Standard_True;
// Auxiliary structures.
// Bounding boxes of polygon links to be used for preliminary
// analysis of intersections
IMeshData::SequenceOfBndB2d aBoxes;
fillBndBox(aBoxes, aStartEdgeVertexS, aPivotVertex);
// Hanging ends
IMeshData::MapOfInteger aDeadLinks;
// Links are temporarily excluded from consideration
IMeshData::MapOfInteger aLeprousLinks;
aLeprousLinks.Add(theStartEdgeId);
Standard_Boolean isSkipLeprous = Standard_True;
Standard_Integer aFirstNode = aStartNode;
while (aPivotNode != aFirstNode)
{
Bnd_B2d aNextLinkBndBox;
gp_Vec2d aNextLinkDir;
Standard_Integer aNextPivotNode = 0;
Standard_Integer aNextLinkId = findNextPolygonLink(aFirstNode,
aPivotNode,
aPivotVertex,
aRefLinkDir,
aBoxes,
aPolygon,
theSkipped,
isSkipLeprous,
aLeprousLinks,
aDeadLinks,
aNextPivotNode,
aNextLinkDir,
aNextLinkBndBox);
if (aNextLinkId != 0)
{
aStartNode = aPivotNode;
aRefLinkDir = aNextLinkDir;
aPivotNode = aNextPivotNode;
aPivotVertex = GetVertex(aNextPivotNode);
aBoxes.Append(aNextLinkBndBox);
aPolygon.Append(aNextLinkId);
isSkipLeprous = Standard_True;
}
else
{
// Nothing to do
if (aPolygon.Length() == 1)
return Standard_False;
// Return to the previous point
Standard_Integer aDeadLinkId = Abs(aPolygon.Last());
aDeadLinks.Add(aDeadLinkId);
aLeprousLinks.Remove(aDeadLinkId);
aPolygon.Remove(aPolygon.Length());
aBoxes.Remove(aBoxes.Length());
Standard_Integer aPrevLinkInfo = aPolygon.Last();
const BRepMesh_Edge& aPrevLink = GetEdge(Abs(aPrevLinkInfo));
if (aPrevLinkInfo > 0)
{
aStartNode = aPrevLink.FirstNode();
aPivotNode = aPrevLink.LastNode();
}
else
{
aStartNode = aPrevLink.LastNode();
aPivotNode = aPrevLink.FirstNode();
}
aPivotVertex = GetVertex(aPivotNode);
aRefLinkDir = aPivotVertex.Coord() - GetVertex(aStartNode).Coord();
isSkipLeprous = Standard_False;
}
}
if (aPolygon.Length() < 3)
return Standard_False;
cleanupPolygon(aPolygon, aBoxes);
meshPolygon(aPolygon, aBoxes, theSkipped);
return Standard_True;
}
//=======================================================================
// function : findNextPolygonLink
// purpose : Find next link starting from the given node and has maximum
// angle respect the given reference link.
// Each time the next link is found other neighbor links at the
// pivot node are marked as leprous and will be excluded from
// consideration next time until a hanging end is occurred.
//=======================================================================
Standard_Integer BRepMesh_Delaun::findNextPolygonLink(
const Standard_Integer& theFirstNode,
const Standard_Integer& thePivotNode,
const BRepMesh_Vertex& thePivotVertex,
const gp_Vec2d& theRefLinkDir,
const IMeshData::SequenceOfBndB2d& theBoxes,
const IMeshData::SequenceOfInteger& thePolygon,
const Handle(IMeshData::MapOfInteger)& theSkipped,
const Standard_Boolean& isSkipLeprous,
IMeshData::MapOfInteger& theLeprousLinks,
IMeshData::MapOfInteger& theDeadLinks,
Standard_Integer& theNextPivotNode,
gp_Vec2d& theNextLinkDir,
Bnd_B2d& theNextLinkBndBox)
{
// Find the next link having the greatest angle
// respect to a direction of a reference one
Standard_Real aMaxAngle = RealFirst();
Standard_Integer aNextLinkId = 0;
IMeshData::ListOfInteger::Iterator aLinkIt(myMeshData->LinksConnectedTo(thePivotNode));
for (; aLinkIt.More(); aLinkIt.Next())
{
const Standard_Integer& aNeighbourLinkInfo = aLinkIt.Value();
Standard_Integer aNeighbourLinkId = Abs(aNeighbourLinkInfo);
if (theDeadLinks.Contains(aNeighbourLinkId)
|| (!theSkipped.IsNull() && theSkipped->Contains(aNeighbourLinkId)))
{
continue;
}
Standard_Boolean isLeprous = theLeprousLinks.Contains(aNeighbourLinkId);
if (isSkipLeprous && isLeprous)
continue;
const BRepMesh_Edge& aNeighbourLink = GetEdge(aNeighbourLinkId);
// Determine whether the link belongs to the mesh
if (aNeighbourLink.Movability() == BRepMesh_Free
&& myMeshData->ElementsConnectedTo(aNeighbourLinkInfo).IsEmpty())
{
theDeadLinks.Add(aNeighbourLinkId);
continue;
}
Standard_Integer anOtherNode = aNeighbourLink.FirstNode();
if (anOtherNode == thePivotNode)
anOtherNode = aNeighbourLink.LastNode();
gp_Vec2d aCurLinkDir(GetVertex(anOtherNode).Coord() - thePivotVertex.Coord());
if (aCurLinkDir.SquareMagnitude() < Precision2)
{
theDeadLinks.Add(aNeighbourLinkId);
continue;
}
if (!isLeprous)
theLeprousLinks.Add(aNeighbourLinkId);
Standard_Real anAngle = theRefLinkDir.Angle(aCurLinkDir);
Standard_Boolean isFrontier = (aNeighbourLink.Movability() == BRepMesh_Frontier);
Standard_Boolean isCheckPointOnEdge = Standard_True;
if (isFrontier)
{
if (Abs(Abs(anAngle) - M_PI) < Precision::Angular())
{
// Glued constrains - don't check intersection
isCheckPointOnEdge = Standard_False;
anAngle = Abs(anAngle);
}
}
if (anAngle <= aMaxAngle)
continue;
Standard_Boolean isCheckEndPoints = (anOtherNode != theFirstNode);
Bnd_B2d aBox;
Standard_Boolean isNotIntersect = checkIntersection(aNeighbourLink,
thePolygon,
theBoxes,
isCheckEndPoints,
isCheckPointOnEdge,
Standard_True,
aBox);
if (isNotIntersect)
{
aMaxAngle = anAngle;
theNextLinkDir = aCurLinkDir;
theNextPivotNode = anOtherNode;
theNextLinkBndBox = aBox;
aNextLinkId =
(aNeighbourLink.FirstNode() == thePivotNode) ? aNeighbourLinkId : -aNeighbourLinkId;
}
}
return aNextLinkId;
}
//=======================================================================
// function : checkIntersection
// purpose : Check is the given link intersects the polygon boundaries.
// Returns bounding box for the given link through the
// <theLinkBndBox> parameter.
//=======================================================================
Standard_Boolean BRepMesh_Delaun::checkIntersection(const BRepMesh_Edge& theLink,
const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes,
const Standard_Boolean isConsiderEndPointTouch,
const Standard_Boolean isConsiderPointOnEdge,
const Standard_Boolean isSkipLastEdge,
Bnd_B2d& theLinkBndBox) const
{
UpdateBndBox(GetVertex(theLink.FirstNode()).Coord(),
GetVertex(theLink.LastNode()).Coord(),
theLinkBndBox);
Standard_Integer aPolyLen = thePolygon.Length();
// Don't check intersection with the last link
if (isSkipLastEdge)
--aPolyLen;
Standard_Boolean isFrontier = (theLink.Movability() == BRepMesh_Frontier);
for (Standard_Integer aPolyIt = 1; aPolyIt <= aPolyLen; ++aPolyIt)
{
if (!theLinkBndBox.IsOut(thePolyBoxes.Value(aPolyIt)))
{
// intersection is possible...
Standard_Integer aPolyLinkId = Abs(thePolygon(aPolyIt));
const BRepMesh_Edge& aPolyLink = GetEdge(aPolyLinkId);
// skip intersections between frontier edges
if (aPolyLink.Movability() == BRepMesh_Frontier && isFrontier)
continue;
gp_Pnt2d anIntPnt;
BRepMesh_GeomTool::IntFlag aIntFlag =
intSegSeg(theLink, aPolyLink, isConsiderEndPointTouch, isConsiderPointOnEdge, anIntPnt);
if (aIntFlag != BRepMesh_GeomTool::NoIntersection)
return Standard_False;
}
}
// Ok, no intersection
return Standard_True;
}
//=======================================================================
// function : addTriangle
// purpose : Add a triangle based on the given oriented edges into mesh
//=======================================================================
void BRepMesh_Delaun::addTriangle(const Standard_Integer (&theEdgesId)[3],
const Standard_Boolean (&theEdgesOri)[3],
const Standard_Integer (&theNodesId)[3])
{
Standard_Integer aNewTriangleId =
myMeshData->AddElement(BRepMesh_Triangle(theEdgesId, theEdgesOri, BRepMesh_Free));
Standard_Boolean isAdded = Standard_True;
if (myInitCircles)
{
isAdded = myCircles.Bind(aNewTriangleId,
GetVertex(theNodesId[0]).Coord(),
GetVertex(theNodesId[1]).Coord(),
GetVertex(theNodesId[2]).Coord());
}
if (!isAdded)
myMeshData->RemoveElement(aNewTriangleId);
}
//=======================================================================
// function : cleanupPolygon
// purpose : Remove internal triangles from the given polygon
//=======================================================================
void BRepMesh_Delaun::cleanupPolygon(const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes)
{
Standard_Integer aPolyLen = thePolygon.Length();
if (aPolyLen < 3)
return;
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
IMeshData::MapOfIntegerInteger aLoopEdges(10, aAllocator);
IMeshData::MapOfInteger anIgnoredEdges;
IMeshData::MapOfInteger aPolyVerticesFindMap;
IMeshData::VectorOfInteger aPolyVertices(256, aAllocator);
// Collect boundary vertices of the polygon
for (Standard_Integer aPolyIt = 1; aPolyIt <= aPolyLen; ++aPolyIt)
{
Standard_Integer aPolyEdgeInfo = thePolygon(aPolyIt);
Standard_Integer aPolyEdgeId = Abs(aPolyEdgeInfo);
anIgnoredEdges.Add(aPolyEdgeId);
Standard_Boolean isForward = (aPolyEdgeInfo > 0);
const BRepMesh_PairOfIndex& aPair = myMeshData->ElementsConnectedTo(aPolyEdgeId);
Standard_Integer anElemIt = 1;
for (; anElemIt <= aPair.Extent(); ++anElemIt)
{
Standard_Integer anElemId = aPair.Index(anElemIt);
if (anElemId < 0)
continue;
const BRepMesh_Triangle& aElement = GetTriangle(anElemId);
const Standard_Integer(&anEdges)[3] = aElement.myEdges;
const Standard_Boolean(&anEdgesOri)[3] = aElement.myOrientations;
Standard_Integer isTriangleFound = Standard_False;
for (Standard_Integer anEdgeIt = 0; anEdgeIt < 3; ++anEdgeIt)
{
if (anEdges[anEdgeIt] == aPolyEdgeId && anEdgesOri[anEdgeIt] == isForward)
{
isTriangleFound = Standard_True;
deleteTriangle(anElemId, aLoopEdges);
break;
}
}
if (isTriangleFound)
break;
}
// Skip a neighbor link to extract unique vertices each time
if (aPolyIt % 2)
{
const BRepMesh_Edge& aPolyEdge = GetEdge(aPolyEdgeId);
Standard_Integer aFirstVertex = aPolyEdge.FirstNode();
Standard_Integer aLastVertex = aPolyEdge.LastNode();
aPolyVerticesFindMap.Add(aFirstVertex);
aPolyVerticesFindMap.Add(aLastVertex);
if (aPolyEdgeInfo > 0)
{
aPolyVertices.Append(aFirstVertex);
aPolyVertices.Append(aLastVertex);
}
else
{
aPolyVertices.Append(aLastVertex);
aPolyVertices.Append(aFirstVertex);
}
}
}
// Make closed sequence
if (aPolyVertices.First() != aPolyVertices.Last())
aPolyVertices.Append(aPolyVertices.First());
IMeshData::MapOfInteger aSurvivedLinks(anIgnoredEdges);
Standard_Integer aPolyVertIt = 0;
Standard_Integer anUniqueVerticesNum = aPolyVertices.Length() - 1;
for (; aPolyVertIt < anUniqueVerticesNum; ++aPolyVertIt)
{
killTrianglesAroundVertex(aPolyVertices(aPolyVertIt),
aPolyVertices,
aPolyVerticesFindMap,
thePolygon,
thePolyBoxes,
aSurvivedLinks,
aLoopEdges);
}
IMeshData::MapOfIntegerInteger::Iterator aLoopEdgesIt(aLoopEdges);
for (; aLoopEdgesIt.More(); aLoopEdgesIt.Next())
{
const Standard_Integer& aLoopEdgeId = aLoopEdgesIt.Key();
if (anIgnoredEdges.Contains(aLoopEdgeId))
continue;
if (myMeshData->ElementsConnectedTo(aLoopEdgeId).IsEmpty())
myMeshData->RemoveLink(aLoopEdgesIt.Key());
}
}
//=======================================================================
// function : killTrianglesAroundVertex
// purpose : Remove all triangles and edges that are placed
// inside the polygon or crossed it.
//=======================================================================
void BRepMesh_Delaun::killTrianglesAroundVertex(
const Standard_Integer theZombieNodeId,
const IMeshData::VectorOfInteger& thePolyVertices,
const IMeshData::MapOfInteger& thePolyVerticesFindMap,
const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::MapOfInteger& theSurvivedLinks,
IMeshData::MapOfIntegerInteger& theLoopEdges)
{
IMeshData::ListOfInteger::Iterator aNeighborsIt = myMeshData->LinksConnectedTo(theZombieNodeId);
// Try to infect neighbor nodes
IMeshData::VectorOfInteger aVictimNodes;
for (; aNeighborsIt.More(); aNeighborsIt.Next())
{
const Standard_Integer& aNeighborLinkId = aNeighborsIt.Value();
if (theSurvivedLinks.Contains(aNeighborLinkId))
continue;
const BRepMesh_Edge& aNeighborLink = GetEdge(aNeighborLinkId);
if (aNeighborLink.Movability() == BRepMesh_Frontier)
{
// Though, if it lies onto the polygon boundary -
// take its triangles
Bnd_B2d aBox;
Standard_Boolean isNotIntersect = checkIntersection(aNeighborLink,
thePolygon,
thePolyBoxes,
Standard_False,
Standard_True,
Standard_False,
aBox);
if (isNotIntersect)
{
// Don't touch it
theSurvivedLinks.Add(aNeighborLinkId);
continue;
}
}
else
{
Standard_Integer anOtherNode = aNeighborLink.FirstNode();
if (anOtherNode == theZombieNodeId)
anOtherNode = aNeighborLink.LastNode();
// Possible sacrifice
if (!thePolyVerticesFindMap.Contains(anOtherNode))
{
if (isVertexInsidePolygon(anOtherNode, thePolyVertices))
{
// Got you!
aVictimNodes.Append(anOtherNode);
}
else
{
// Lucky. But it may intersect the polygon boundary.
// Let's check it!
killTrianglesOnIntersectingLinks(aNeighborLinkId,
aNeighborLink,
anOtherNode,
thePolygon,
thePolyBoxes,
theSurvivedLinks,
theLoopEdges);
continue;
}
}
}
// Add link to the survivors to avoid cycling
theSurvivedLinks.Add(aNeighborLinkId);
killLinkTriangles(aNeighborLinkId, theLoopEdges);
}
// Go and do your job!
IMeshData::VectorOfInteger::Iterator aVictimIt(aVictimNodes);
for (; aVictimIt.More(); aVictimIt.Next())
{
killTrianglesAroundVertex(aVictimIt.Value(),
thePolyVertices,
thePolyVerticesFindMap,
thePolygon,
thePolyBoxes,
theSurvivedLinks,
theLoopEdges);
}
}
//=======================================================================
// function : isVertexInsidePolygon
// purpose : Checks is the given vertex lies inside the polygon
//=======================================================================
Standard_Boolean BRepMesh_Delaun::isVertexInsidePolygon(
const Standard_Integer& theVertexId,
const IMeshData::VectorOfInteger& thePolygonVertices) const
{
Standard_Integer aPolyLen = thePolygonVertices.Length();
if (aPolyLen < 3)
return Standard_False;
const gp_XY aCenterPointXY = GetVertex(theVertexId).Coord();
const BRepMesh_Vertex& aFirstVertex = GetVertex(thePolygonVertices(0));
gp_Vec2d aPrevVertexDir(aFirstVertex.Coord() - aCenterPointXY);
if (aPrevVertexDir.SquareMagnitude() < Precision2)
return Standard_True;
Standard_Real aTotalAng = 0.0;
for (Standard_Integer aPolyIt = 1; aPolyIt < aPolyLen; ++aPolyIt)
{
const BRepMesh_Vertex& aPolyVertex = GetVertex(thePolygonVertices(aPolyIt));
gp_Vec2d aCurVertexDir(aPolyVertex.Coord() - aCenterPointXY);
if (aCurVertexDir.SquareMagnitude() < Precision2)
return Standard_True;
aTotalAng += aCurVertexDir.Angle(aPrevVertexDir);
aPrevVertexDir = aCurVertexDir;
}
if (Abs(Angle2PI - aTotalAng) > Precision::Angular())
return Standard_False;
return Standard_True;
}
//=======================================================================
// function : killTrianglesOnIntersectingLinks
// purpose : Checks is the given link crosses the polygon boundary.
// If yes, kills its triangles and checks neighbor links on
// boundary intersection. Does nothing elsewhere.
//=======================================================================
void BRepMesh_Delaun::killTrianglesOnIntersectingLinks(
const Standard_Integer& theLinkToCheckId,
const BRepMesh_Edge& theLinkToCheck,
const Standard_Integer& theEndPoint,
const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::MapOfInteger& theSurvivedLinks,
IMeshData::MapOfIntegerInteger& theLoopEdges)
{
if (theSurvivedLinks.Contains(theLinkToCheckId))
return;
Bnd_B2d aBox;
Standard_Boolean isNotIntersect = checkIntersection(theLinkToCheck,
thePolygon,
thePolyBoxes,
Standard_False,
Standard_False,
Standard_False,
aBox);
theSurvivedLinks.Add(theLinkToCheckId);
if (isNotIntersect)
return;
killLinkTriangles(theLinkToCheckId, theLoopEdges);
IMeshData::ListOfInteger::Iterator aNeighborsIt(myMeshData->LinksConnectedTo(theEndPoint));
for (; aNeighborsIt.More(); aNeighborsIt.Next())
{
const Standard_Integer& aNeighborLinkId = aNeighborsIt.Value();
const BRepMesh_Edge& aNeighborLink = GetEdge(aNeighborLinkId);
Standard_Integer anOtherNode = aNeighborLink.FirstNode();
if (anOtherNode == theEndPoint)
anOtherNode = aNeighborLink.LastNode();
killTrianglesOnIntersectingLinks(aNeighborLinkId,
aNeighborLink,
anOtherNode,
thePolygon,
thePolyBoxes,
theSurvivedLinks,
theLoopEdges);
}
}
//=======================================================================
// function : killLinkTriangles
// purpose : Kill triangles bound to the given link.
//=======================================================================
void BRepMesh_Delaun::killLinkTriangles(const Standard_Integer& theLinkId,
IMeshData::MapOfIntegerInteger& theLoopEdges)
{
const BRepMesh_PairOfIndex& aPair = myMeshData->ElementsConnectedTo(theLinkId);
Standard_Integer anElemNb = aPair.Extent();
for (Standard_Integer aPairIt = 1; aPairIt <= anElemNb; ++aPairIt)
{
Standard_Integer anElemId = aPair.FirstIndex();
if (anElemId < 0)
continue;
deleteTriangle(anElemId, theLoopEdges);
}
}
//=======================================================================
// function : getOrientedNodes
// purpose : Returns start and end nodes of the given edge in respect to
// its orientation.
//=======================================================================
void BRepMesh_Delaun::getOrientedNodes(const BRepMesh_Edge& theEdge,
const Standard_Boolean isForward,
Standard_Integer* theNodes) const
{
if (isForward)
{
theNodes[0] = theEdge.FirstNode();
theNodes[1] = theEdge.LastNode();
}
else
{
theNodes[0] = theEdge.LastNode();
theNodes[1] = theEdge.FirstNode();
}
}
//=======================================================================
// function : processLoop
// purpose : Processes loop within the given polygon formed by range of
// its links specified by start and end link indices.
//=======================================================================
void BRepMesh_Delaun::processLoop(const Standard_Integer theLinkFrom,
const Standard_Integer theLinkTo,
const IMeshData::SequenceOfInteger& thePolygon,
const IMeshData::SequenceOfBndB2d& thePolyBoxes)
{
Standard_Integer aNbOfLinksInLoop = theLinkTo - theLinkFrom - 1;
if (aNbOfLinksInLoop < 3)
return;
IMeshData::SequenceOfInteger aPolygon;
IMeshData::SequenceOfBndB2d aPolyBoxes;
for (; aNbOfLinksInLoop > 0; --aNbOfLinksInLoop)
{
Standard_Integer aLoopLinkIndex = theLinkFrom + aNbOfLinksInLoop;
aPolygon.Prepend(thePolygon(aLoopLinkIndex));
aPolyBoxes.Prepend(thePolyBoxes(aLoopLinkIndex));
}
meshPolygon(aPolygon, aPolyBoxes);
}
//=======================================================================
// function : createAndReplacePolygonLink
// purpose : Creates new link based on the given nodes and updates the
// given polygon.
//=======================================================================
Standard_Integer BRepMesh_Delaun::createAndReplacePolygonLink(
const Standard_Integer* theNodes,
const gp_Pnt2d* thePnts,
const Standard_Integer theRootIndex,
const ReplaceFlag theReplaceFlag,
IMeshData::SequenceOfInteger& thePolygon,
IMeshData::SequenceOfBndB2d& thePolyBoxes)
{
Standard_Integer aNewEdgeId =
myMeshData->AddLink(BRepMesh_Edge(theNodes[0], theNodes[1], BRepMesh_Free));
Bnd_B2d aNewBox;
UpdateBndBox(thePnts[0].Coord(), thePnts[1].Coord(), aNewBox);
switch (theReplaceFlag)
{
case BRepMesh_Delaun::Replace:
thePolygon.SetValue(theRootIndex, aNewEdgeId);
thePolyBoxes.SetValue(theRootIndex, aNewBox);
break;
case BRepMesh_Delaun::InsertAfter:
thePolygon.InsertAfter(theRootIndex, aNewEdgeId);
thePolyBoxes.InsertAfter(theRootIndex, aNewBox);
break;
case BRepMesh_Delaun::InsertBefore:
thePolygon.InsertBefore(theRootIndex, aNewEdgeId);
thePolyBoxes.InsertBefore(theRootIndex, aNewBox);
break;
}
return aNewEdgeId;
}
//=================================================================================================
void BRepMesh_Delaun::meshPolygon(IMeshData::SequenceOfInteger& thePolygon,
IMeshData::SequenceOfBndB2d& thePolyBoxes,
Handle(IMeshData::MapOfInteger) theSkipped)
{
// Check is the source polygon elementary
if (meshElementaryPolygon(thePolygon))
return;
// Check and correct boundary edges
Standard_Integer aPolyLen = thePolygon.Length();
const Standard_Real aPolyArea = Abs(polyArea(thePolygon, 1, aPolyLen));
const Standard_Real aSmallLoopArea = 0.001 * aPolyArea;
for (Standard_Integer aPolyIt = 1; aPolyIt < aPolyLen; ++aPolyIt)
{
Standard_Integer aCurEdgeInfo = thePolygon(aPolyIt);
Standard_Integer aCurEdgeId = Abs(aCurEdgeInfo);
const BRepMesh_Edge* aCurEdge = &GetEdge(aCurEdgeId);
if (aCurEdge->Movability() != BRepMesh_Frontier)
continue;
Standard_Integer aCurNodes[2];
getOrientedNodes(*aCurEdge, aCurEdgeInfo > 0, aCurNodes);
gp_Pnt2d aCurPnts[2] = {GetVertex(aCurNodes[0]).Coord(), GetVertex(aCurNodes[1]).Coord()};
gp_Vec2d aCurVec(aCurPnts[0], aCurPnts[1]);
// check further links
Standard_Integer aNextPolyIt = aPolyIt + 1;
for (; aNextPolyIt <= aPolyLen; ++aNextPolyIt)
{
Standard_Integer aNextEdgeInfo = thePolygon(aNextPolyIt);
Standard_Integer aNextEdgeId = Abs(aNextEdgeInfo);
const BRepMesh_Edge* aNextEdge = &GetEdge(aNextEdgeId);
if (aNextEdge->Movability() != BRepMesh_Frontier)
continue;
Standard_Integer aNextNodes[2];
getOrientedNodes(*aNextEdge, aNextEdgeInfo > 0, aNextNodes);
gp_Pnt2d aNextPnts[2] = {GetVertex(aNextNodes[0]).Coord(), GetVertex(aNextNodes[1]).Coord()};
gp_Pnt2d anIntPnt;
BRepMesh_GeomTool::IntFlag aIntFlag =
intSegSeg(*aCurEdge, *aNextEdge, Standard_False, Standard_True, anIntPnt);
if (aIntFlag == BRepMesh_GeomTool::NoIntersection)
continue;
Standard_Boolean isRemoveFromFirst = Standard_False;
Standard_Boolean isAddReplacingEdge = Standard_True;
Standard_Integer aIndexToRemoveTo = aNextPolyIt;
if (aIntFlag == BRepMesh_GeomTool::Cross)
{
Standard_Real aLoopArea = polyArea(thePolygon, aPolyIt + 1, aNextPolyIt);
gp_Vec2d aVec1(anIntPnt, aCurPnts[1]);
gp_Vec2d aVec2(anIntPnt, aNextPnts[0]);
aLoopArea += (aVec1 ^ aVec2) / 2.;
if (Abs(aLoopArea) > aSmallLoopArea)
{
aNextNodes[1] = aCurNodes[0];
aNextPnts[1] = aCurPnts[0];
aNextEdgeId = Abs(createAndReplacePolygonLink(aNextNodes,
aNextPnts,
aNextPolyIt,
BRepMesh_Delaun::Replace,
thePolygon,
thePolyBoxes));
processLoop(aPolyIt, aNextPolyIt, thePolygon, thePolyBoxes);
return;
}
Standard_Real aDist1 = anIntPnt.SquareDistance(aNextPnts[0]);
Standard_Real aDist2 = anIntPnt.SquareDistance(aNextPnts[1]);
// Choose node with lower distance
const Standard_Boolean isCloseToStart = (aDist1 < aDist2);
const Standard_Integer aEndPointIndex = isCloseToStart ? 0 : 1;
aCurNodes[1] = aNextNodes[aEndPointIndex];
aCurPnts[1] = aNextPnts[aEndPointIndex];
if (isCloseToStart)
--aIndexToRemoveTo;
// In this context only intersections between frontier edges
// are possible. If intersection between edges of different
// types occurred - treat this case as invalid (i.e. result
// might not reflect the expectations).
if (!theSkipped.IsNull())
{
Standard_Integer aSkippedLinkIt = aPolyIt;
for (; aSkippedLinkIt <= aIndexToRemoveTo; ++aSkippedLinkIt)
theSkipped->Add(Abs(thePolygon(aSkippedLinkIt)));
}
}
else if (aIntFlag == BRepMesh_GeomTool::PointOnSegment)
{
// Identify chopping link
Standard_Boolean isFirstChopping = Standard_False;
Standard_Integer aCheckPointIt = 0;
for (; aCheckPointIt < 2; ++aCheckPointIt)
{
gp_Pnt2d& aRefPoint = aCurPnts[aCheckPointIt];
// Check is second link touches the first one
gp_Vec2d aVec1(aRefPoint, aNextPnts[0]);
gp_Vec2d aVec2(aRefPoint, aNextPnts[1]);
if (Abs(aVec1 ^ aVec2) < Precision)
{
isFirstChopping = Standard_True;
break;
}
}
if (isFirstChopping)
{
// Split second link
isAddReplacingEdge = Standard_False;
isRemoveFromFirst = (aCheckPointIt == 0);
Standard_Integer aSplitLink[3] = {aNextNodes[0], aCurNodes[aCheckPointIt], aNextNodes[1]};
gp_Pnt2d aSplitPnts[3] = {aNextPnts[0], aCurPnts[aCheckPointIt], aNextPnts[1]};
Standard_Integer aSplitLinkIt = 0;
for (; aSplitLinkIt < 2; ++aSplitLinkIt)
{
createAndReplacePolygonLink(&aSplitLink[aSplitLinkIt],
&aSplitPnts[aSplitLinkIt],
aNextPolyIt,
(aSplitLinkIt == 0) ? BRepMesh_Delaun::Replace
: BRepMesh_Delaun::InsertAfter,
thePolygon,
thePolyBoxes);
}
processLoop(aPolyIt + aCheckPointIt, aIndexToRemoveTo, thePolygon, thePolyBoxes);
}
else
{
// Split first link
Standard_Integer aSplitLinkNodes[2] = {aNextNodes[1], aCurNodes[1]};
gp_Pnt2d aSplitLinkPnts[2] = {aNextPnts[1], aCurPnts[1]};
createAndReplacePolygonLink(aSplitLinkNodes,
aSplitLinkPnts,
aPolyIt,
BRepMesh_Delaun::InsertAfter,
thePolygon,
thePolyBoxes);
aCurNodes[1] = aNextNodes[1];
aCurPnts[1] = aNextPnts[1];
++aIndexToRemoveTo;
processLoop(aPolyIt + 1, aIndexToRemoveTo, thePolygon, thePolyBoxes);
}
}
else if (aIntFlag == BRepMesh_GeomTool::Glued)
{
if (aCurNodes[1] == aNextNodes[0])
{
aCurNodes[1] = aNextNodes[1];
aCurPnts[1] = aNextPnts[1];
}
// TODO: Non-adjacent glued links within the polygon
}
else if (aIntFlag == BRepMesh_GeomTool::Same)
{
processLoop(aPolyIt, aNextPolyIt, thePolygon, thePolyBoxes);
isRemoveFromFirst = Standard_True;
isAddReplacingEdge = Standard_False;
}
else
continue; // Not supported type
if (isAddReplacingEdge)
{
aCurEdgeId = Abs(createAndReplacePolygonLink(aCurNodes,
aCurPnts,
aPolyIt,
BRepMesh_Delaun::Replace,
thePolygon,
thePolyBoxes));
aCurEdge = &GetEdge(aCurEdgeId);
aCurVec = gp_Vec2d(aCurPnts[0], aCurPnts[1]);
}
Standard_Integer aIndexToRemoveFrom = isRemoveFromFirst ? aPolyIt : aPolyIt + 1;
thePolygon.Remove(aIndexToRemoveFrom, aIndexToRemoveTo);
thePolyBoxes.Remove(aIndexToRemoveFrom, aIndexToRemoveTo);
aPolyLen = thePolygon.Length();
if (isRemoveFromFirst)
{
--aPolyIt;
break;
}
aNextPolyIt = aPolyIt;
}
}
IMeshData::SequenceOfInteger* aPolygon1 = &thePolygon;
IMeshData::SequenceOfBndB2d* aPolyBoxes1 = &thePolyBoxes;
Handle(IMeshData::SequenceOfInteger) aPolygon2 = new IMeshData::SequenceOfInteger;
Handle(IMeshData::SequenceOfBndB2d) aPolyBoxes2 = new IMeshData::SequenceOfBndB2d;
NCollection_Sequence<Handle(IMeshData::SequenceOfInteger)> aPolyStack;
NCollection_Sequence<Handle(IMeshData::SequenceOfBndB2d)> aPolyBoxStack;
for (;;)
{
decomposeSimplePolygon(*aPolygon1, *aPolyBoxes1, *aPolygon2, *aPolyBoxes2);
if (!aPolygon2->IsEmpty())
{
aPolyStack.Append(aPolygon2);
aPolyBoxStack.Append(aPolyBoxes2);
aPolygon2 = new IMeshData::SequenceOfInteger;
aPolyBoxes2 = new IMeshData::SequenceOfBndB2d;
}
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());
}
}
}
//=======================================================================
// function : meshElementaryPolygon
// purpose : Triangulation of closed polygon containing only three edges.
//=======================================================================
Standard_Boolean BRepMesh_Delaun::meshElementaryPolygon(
const IMeshData::SequenceOfInteger& thePolygon)
{
Standard_Integer aPolyLen = thePolygon.Length();
if (aPolyLen < 3)
return Standard_True;
else if (aPolyLen > 3)
return Standard_False;
// Just create a triangle
Standard_Integer anEdges[3];
Standard_Boolean anEdgesOri[3];
for (Standard_Integer anEdgeIt = 0; anEdgeIt < 3; ++anEdgeIt)
{
Standard_Integer anEdgeInfo = thePolygon(anEdgeIt + 1);
anEdges[anEdgeIt] = Abs(anEdgeInfo);
anEdgesOri[anEdgeIt] = (anEdgeInfo > 0);
}
const BRepMesh_Edge& anEdge1 = GetEdge(anEdges[0]);
const BRepMesh_Edge& anEdge2 = GetEdge(anEdges[1]);
Standard_Integer aNodes[3] = {anEdge1.FirstNode(), anEdge1.LastNode(), anEdge2.FirstNode()};
if (aNodes[2] == aNodes[0] || aNodes[2] == aNodes[1])
{
aNodes[2] = anEdge2.LastNode();
}
addTriangle(anEdges, anEdgesOri, aNodes);
return Standard_True;
}
//=================================================================================================
void BRepMesh_Delaun::decomposeSimplePolygon(IMeshData::SequenceOfInteger& thePolygon,
IMeshData::SequenceOfBndB2d& thePolyBoxes,
IMeshData::SequenceOfInteger& thePolygonCut,
IMeshData::SequenceOfBndB2d& thePolyBoxesCut)
{
// Check is the given polygon elementary
if (meshElementaryPolygon(thePolygon))
{
thePolygon.Clear();
thePolyBoxes.Clear();
return;
}
// Polygon contains more than 3 links
Standard_Integer aFirstEdgeInfo = thePolygon(1);
const BRepMesh_Edge& aFirstEdge = GetEdge(Abs(aFirstEdgeInfo));
Standard_Integer aNodes[3];
getOrientedNodes(aFirstEdge, aFirstEdgeInfo > 0, aNodes);
gp_Pnt2d aRefVertices[3];
aRefVertices[0] = GetVertex(aNodes[0]).Coord();
aRefVertices[1] = GetVertex(aNodes[1]).Coord();
gp_Vec2d aRefEdgeDir(aRefVertices[0], aRefVertices[1]);
Standard_Real aRefEdgeLen = aRefEdgeDir.Magnitude();
if (aRefEdgeLen < Precision)
{
thePolygon.Clear();
thePolyBoxes.Clear();
return;
}
aRefEdgeDir /= aRefEdgeLen;
// 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));
aPivotNode = aLinkInfo > 0 ? aNextEdge.FirstNode() : aNextEdge.LastNode();
// We have end points touch case in the polygon - ignore it
if (aPivotNode == aNodes[1])
continue;
gp_Pnt2d aPivotVertex = GetVertex(aPivotNode).Coord();
gp_Vec2d aDistanceDir(aRefVertices[1], aPivotVertex);
Standard_Real aDist = aRefEdgeDir ^ 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;
}
// 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 gp_Pnt2d& aLinkFirstVertex = aRefVertices[aRefLinkNodeIt];
Bnd_B2d aBox;
UpdateBndBox(aLinkFirstVertex.Coord(), aPivotVertex.Coord(), aBox);
BRepMesh_Edge aCheckLink(aLinkFirstNode, aPivotNode, 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)));
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;
}
}
}
if (isIntersect)
break;
}
if (isIntersect)
continue;
aOptAngle = aAngle;
aMinDist = anAbsDist;
aNodes[2] = aPivotNode;
aRefVertices[2] = aPivotVertex;
aUsedLinkId = aLinkIt;
}
if (aUsedLinkId == 0)
{
thePolygon.Clear();
thePolyBoxes.Clear();
return;
}
BRepMesh_Edge aNewEdges[2] = {BRepMesh_Edge(aNodes[1], aNodes[2], BRepMesh_Free),
BRepMesh_Edge(aNodes[2], aNodes[0], BRepMesh_Free)};
Standard_Integer aNewEdgesInfo[3] = {aFirstEdgeInfo,
myMeshData->AddLink(aNewEdges[0]),
myMeshData->AddLink(aNewEdges[1])};
Standard_Integer anEdges[3];
Standard_Boolean anEdgesOri[3];
for (Standard_Integer aTriEdgeIt = 0; aTriEdgeIt < 3; ++aTriEdgeIt)
{
const Standard_Integer& anEdgeInfo = aNewEdgesInfo[aTriEdgeIt];
anEdges[aTriEdgeIt] = Abs(anEdgeInfo);
anEdgesOri[aTriEdgeIt] = anEdgeInfo > 0;
}
addTriangle(anEdges, anEdgesOri, aNodes);
if (aUsedLinkId == 3)
{
thePolygon.Remove(1);
thePolyBoxes.Remove(1);
thePolygon.SetValue(1, -aNewEdgesInfo[2]);
Bnd_B2d aBox;
UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox);
thePolyBoxes.SetValue(1, aBox);
}
else
{
// Create triangle and split the source polygon on two
// parts (if possible) and mesh each part as independent
// polygon.
if (aUsedLinkId < aPolyLen)
{
thePolygon.Split(aUsedLinkId, thePolygonCut);
thePolygonCut.Prepend(-aNewEdgesInfo[2]);
thePolyBoxes.Split(aUsedLinkId, thePolyBoxesCut);
Bnd_B2d aBox;
UpdateBndBox(aRefVertices[0].Coord(), aRefVertices[2].Coord(), aBox);
thePolyBoxesCut.Prepend(aBox);
}
else
{
thePolygon.Remove(aPolyLen);
thePolyBoxes.Remove(aPolyLen);
}
thePolygon.SetValue(1, -aNewEdgesInfo[1]);
Bnd_B2d aBox;
UpdateBndBox(aRefVertices[1].Coord(), aRefVertices[2].Coord(), aBox);
thePolyBoxes.SetValue(1, aBox);
}
}
//=======================================================================
// function : RemoveVertex
// purpose : Removes a vertex from the triangulation
//=======================================================================
void BRepMesh_Delaun::RemoveVertex(const BRepMesh_Vertex& theVertex)
{
BRepMesh_SelectorOfDataStructureOfDelaun aSelector(myMeshData);
aSelector.NeighboursOf(theVertex);
IMeshData::MapOfIntegerInteger aLoopEdges; //( 10, myMeshData->Allocator() );
// Loop on triangles to be destroyed :
IMeshData::IteratorOfMapOfInteger aTriangleIt(aSelector.Elements());
for (; aTriangleIt.More(); aTriangleIt.Next())
deleteTriangle(aTriangleIt.Key(), aLoopEdges);
IMeshData::SequenceOfBndB2d aBoxes;
IMeshData::SequenceOfInteger aPolygon;
Standard_Integer aLoopEdgesCount = aLoopEdges.Extent();
IMeshData::MapOfIntegerInteger::Iterator aLoopEdgesIt(aLoopEdges);
if (aLoopEdgesIt.More())
{
const BRepMesh_Edge& anEdge = GetEdge(aLoopEdgesIt.Key());
Standard_Integer aFirstNode = anEdge.FirstNode();
Standard_Integer aLastNode;
Standard_Integer aPivotNode = anEdge.LastNode();
Standard_Integer anEdgeId = aLoopEdgesIt.Key();
Standard_Boolean isPositive = aLoopEdges(anEdgeId) != 0;
if (!isPositive)
{
Standard_Integer aTmp;
aTmp = aFirstNode;
aFirstNode = aPivotNode;
aPivotNode = aTmp;
aPolygon.Append(-anEdgeId);
}
else
aPolygon.Append(anEdgeId);
fillBndBox(aBoxes, GetVertex(aFirstNode), GetVertex(aPivotNode));
aLoopEdges.UnBind(anEdgeId);
aLastNode = aFirstNode;
while (aPivotNode != aLastNode)
{
IMeshData::ListOfInteger::Iterator aLinkIt(myMeshData->LinksConnectedTo(aPivotNode));
for (; aLinkIt.More(); aLinkIt.Next())
{
if (aLinkIt.Value() != anEdgeId && aLoopEdges.IsBound(aLinkIt.Value()))
{
Standard_Integer aCurrentNode;
anEdgeId = aLinkIt.Value();
const BRepMesh_Edge& anEdge1 = GetEdge(anEdgeId);
aCurrentNode = anEdge1.LastNode();
if (aCurrentNode != aPivotNode)
{
aCurrentNode = anEdge1.FirstNode();
aPolygon.Append(-anEdgeId);
}
else
aPolygon.Append(anEdgeId);
fillBndBox(aBoxes, GetVertex(aCurrentNode), GetVertex(aPivotNode));
aPivotNode = aCurrentNode;
aLoopEdges.UnBind(anEdgeId);
break;
}
}
if (aLoopEdgesCount <= 0)
break;
--aLoopEdgesCount;
}
meshPolygon(aPolygon, aBoxes);
}
}
//=======================================================================
// function : AddVertices
// purpose : Adds some vertices in the triangulation.
//=======================================================================
void BRepMesh_Delaun::AddVertices(IMeshData::VectorOfInteger& theVertices,
const Message_ProgressRange& theRange)
{
ComparatorOfIndexedVertexOfDelaun aCmp(myMeshData);
std::make_heap(theVertices.begin(), theVertices.end(), aCmp);
std::sort_heap(theVertices.begin(), theVertices.end(), aCmp);
createTrianglesOnNewVertices(theVertices, theRange);
}
//=======================================================================
// function : UseEdge
// purpose : Modify mesh to use the edge. Return True if done
//=======================================================================
Standard_Boolean BRepMesh_Delaun::UseEdge(const Standard_Integer /*theIndex*/)
{
/*
const BRepMesh_PairOfIndex& aPair = myMeshData->ElemConnectedTo( theIndex );
if ( aPair.Extent() == 0 )
{
const BRepMesh_Edge& anEdge = GetEdge( theIndex );
Standard_Integer aStartNode, aPivotNode, anOtherNode;
aStartNode = anEdge.FirstNode();
aPivotNode = anEdge.LastNode();
const BRepMesh_ListOfInteger& aStartNodeNeighbors = myMeshData->LinkNeighboursOf( aStartNode );
const BRepMesh_ListOfInteger& aPivotNodeNeighbors = myMeshData->LinkNeighboursOf( aPivotNode );
if ( aStartNodeNeighbors.Extent() > 0 &&
aPivotNodeNeighbors.Extent() > 0 )
{
const BRepMesh_Vertex& aStartVertex = GetVertex( aStartNode );
const BRepMesh_Vertex& aPivotVertex = GetVertex( aPivotNode );
gp_XY aVEdge ( aPivotVertex.Coord() );
aVEdge.Subtract( aStartVertex.Coord() );
Standard_Real anAngle = 0.;
Standard_Real anAngleMin = RealLast();
Standard_Real anAngleMax = RealFirst();
Standard_Integer aLeftEdge = 0, aRightEdge = 0;
BRepMesh_ListOfInteger::Iterator aNeighborIt( aPivotNodeNeighbors );
for ( ; aNeighborIt.More(); aNeighborIt.Next() )
{
Standard_Integer anEdgeId = aNeighborIt.Value();
if ( anEdgeId != theIndex )
{
const BRepMesh_Edge& aNextEdge = GetEdge( anEdgeId );
Standard_Boolean isInMesh = Standard_True;
if ( aNextEdge.Movability() == BRepMesh_Free )
{
if ( myMeshData->ElemConnectedTo( anEdgeId ).IsEmpty() )
isInMesh = Standard_False;
}
if ( isInMesh )
{
anOtherNode = aNextEdge.FirstNode();
if ( anOtherNode == aPivotNode )
anOtherNode = aNextEdge.LastNode();
gp_XY aVEdgeCur = GetVertex( anOtherNode ).Coord();
aVEdgeCur.Subtract( aPivotVertex.Coord() );
anAngle = gp_Vec2d( aVEdge ).Angle( gp_Vec2d( aVEdgeCur ) );
}
if ( anAngle > anAngleMax )
{
anAngleMax = anAngle;
aLeftEdge = anEdgeId;
}
if ( anAngle < anAngleMin )
{
anAngleMin = anAngle;
aRightEdge = anEdgeId;
}
}
}
if ( aLeftEdge > 0 )
{
if (aLeftEdge==aRightEdge)
{
}
else
{
}
}
}
}
*/
return Standard_False;
}
//=======================================================================
// function : getEdgesByType
// purpose : Gives the list of edges with type defined by input parameter
//=======================================================================
Handle(IMeshData::MapOfInteger) BRepMesh_Delaun::getEdgesByType(
const BRepMesh_DegreeOfFreedom theEdgeType) const
{
Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
Handle(IMeshData::MapOfInteger) aResult = new IMeshData::MapOfInteger;
IMeshData::IteratorOfMapOfInteger anEdgeIt(myMeshData->LinksOfDomain());
for (; anEdgeIt.More(); anEdgeIt.Next())
{
Standard_Integer anEdge = anEdgeIt.Key();
Standard_Boolean isToAdd = (theEdgeType == BRepMesh_Free)
? (myMeshData->ElementsConnectedTo(anEdge).Extent() <= 1)
: (GetEdge(anEdge).Movability() == theEdgeType);
if (isToAdd)
aResult->Add(anEdge);
}
return aResult;
}
//=======================================================================
// function : calculateDist
// purpose : Calculates distances between the given point and edges of
// triangle
//=======================================================================
Standard_Real BRepMesh_Delaun::calculateDist(const gp_XY theVEdges[3],
const gp_XY thePoints[3],
const BRepMesh_Vertex& theVertex,
Standard_Real theDistance[3],
Standard_Real theSqModulus[3],
Standard_Integer& theEdgeOn) const
{
Standard_Real aMinDist = RealLast();
for (Standard_Integer i = 0; i < 3; ++i)
{
theSqModulus[i] = theVEdges[i].SquareModulus();
if (theSqModulus[i] <= Precision2)
return -1;
theDistance[i] = theVEdges[i] ^ (theVertex.Coord() - thePoints[i]);
Standard_Real aDist = theDistance[i] * theDistance[i];
aDist /= theSqModulus[i];
if (aDist < aMinDist)
{
theEdgeOn = i;
aMinDist = aDist;
}
}
return aMinDist;
}
//=======================================================================
// function : Contains
// purpose : Test if triangle of index <TrianIndex> contains geometricaly
// <theVertex>. If <theEdgeOn> is != 0 then theVertex is on Edge
// of index <theEdgeOn>
//=======================================================================
Standard_Boolean BRepMesh_Delaun::Contains(const Standard_Integer theTriangleId,
const BRepMesh_Vertex& theVertex,
const Standard_Real theSqTolerance,
Standard_Integer& theEdgeOn) const
{
theEdgeOn = 0;
Standard_Integer p[3];
const BRepMesh_Triangle& aElement = GetTriangle(theTriangleId);
const Standard_Integer(&e)[3] = aElement.myEdges;
const BRepMesh_Edge* anEdges[3] = {&GetEdge(e[0]), &GetEdge(e[1]), &GetEdge(e[2])};
myMeshData->ElementNodes(aElement, p);
gp_XY aPoints[3];
aPoints[0] = GetVertex(p[0]).Coord();
aPoints[1] = GetVertex(p[1]).Coord();
aPoints[2] = GetVertex(p[2]).Coord();
gp_XY aVEdges[3];
aVEdges[0] = aPoints[1];
aVEdges[0].Subtract(aPoints[0]);
aVEdges[1] = aPoints[2];
aVEdges[1].Subtract(aPoints[1]);
aVEdges[2] = aPoints[0];
aVEdges[2].Subtract(aPoints[2]);
Standard_Real aDistance[3];
Standard_Real aSqModulus[3];
Standard_Real aSqMinDist;
Standard_Integer aEdgeOnId;
aSqMinDist = calculateDist(aVEdges, aPoints, theVertex, aDistance, aSqModulus, aEdgeOnId);
if (aSqMinDist < 0)
return Standard_False;
const Standard_Boolean isNotFree = (anEdges[aEdgeOnId]->Movability() != BRepMesh_Free);
if (aSqMinDist > theSqTolerance)
{
if (isNotFree && aDistance[aEdgeOnId] < (aSqModulus[aEdgeOnId] / 5.))
theEdgeOn = e[aEdgeOnId];
}
else if (isNotFree)
return Standard_False;
else
theEdgeOn = e[aEdgeOnId];
return (aDistance[0] >= 0. && aDistance[1] >= 0. && aDistance[2] >= 0.);
}
//=============================================================================
// function : intSegSeg
// purpose : Checks intersection between the two segments.
//=============================================================================
BRepMesh_GeomTool::IntFlag BRepMesh_Delaun::intSegSeg(
const BRepMesh_Edge& theEdg1,
const BRepMesh_Edge& theEdg2,
const Standard_Boolean isConsiderEndPointTouch,
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,
isConsiderEndPointTouch,
isConsiderPointOnEdge,
theIntPnt);
}
//=============================================================================
// function : polyArea
// purpose : Returns area of the loop of the given polygon defined by indices
// of its start and end links.
//=============================================================================
Standard_Real BRepMesh_Delaun::polyArea(const IMeshData::SequenceOfInteger& thePolygon,
const Standard_Integer theStartIndex,
const Standard_Integer theEndIndex) const
{
Standard_Real aArea = 0.0;
Standard_Integer aPolyLen = thePolygon.Length();
if (theStartIndex >= theEndIndex || theStartIndex > aPolyLen)
{
return aArea;
}
Standard_Integer aCurEdgeInfo = thePolygon(theStartIndex);
Standard_Integer aCurEdgeId = Abs(aCurEdgeInfo);
const BRepMesh_Edge* aCurEdge = &GetEdge(aCurEdgeId);
Standard_Integer aNodes[2];
getOrientedNodes(*aCurEdge, aCurEdgeInfo > 0, aNodes);
gp_Pnt2d aRefPnt = GetVertex(aNodes[0]).Coord();
Standard_Integer aPolyIt = theStartIndex + 1;
for (; aPolyIt <= theEndIndex; ++aPolyIt)
{
aCurEdgeInfo = thePolygon(aPolyIt);
aCurEdgeId = Abs(aCurEdgeInfo);
aCurEdge = &GetEdge(aCurEdgeId);
getOrientedNodes(*aCurEdge, aCurEdgeInfo > 0, aNodes);
gp_Vec2d aVec1(aRefPnt, GetVertex(aNodes[0]).Coord());
gp_Vec2d aVec2(aRefPnt, GetVertex(aNodes[1]).Coord());
aArea += aVec1 ^ aVec2;
}
return aArea / 2.;
}
#ifdef OCCT_DEBUG
//=================================================================================================
#include <TopoDS_Compound.hxx>
#include <BRep_Builder.hxx>
#include <Standard_ErrorHandler.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepTools.hxx>
Standard_CString BRepMesh_DumpPoly(void* thePolygon,
void* theMeshHandlePtr,
Standard_CString theFileNameStr)
{
if (thePolygon == 0 || theFileNameStr == 0)
{
return "Error: file name or polygon data is null";
}
IMeshData::SequenceOfInteger& aPolygon = *(IMeshData::SequenceOfInteger*)thePolygon;
Handle(BRepMesh_DataStructureOfDelaun) aMeshData =
*(Handle(BRepMesh_DataStructureOfDelaun)*)theMeshHandlePtr;
if (aMeshData.IsNull())
return "Error: mesh data is empty";
TopoDS_Compound aMesh;
BRep_Builder aBuilder;
aBuilder.MakeCompound(aMesh);
try
{
OCC_CATCH_SIGNALS
IMeshData::SequenceOfInteger::Iterator aLinksIt(aPolygon);
for (; aLinksIt.More(); aLinksIt.Next())
{
const BRepMesh_Edge& aLink = aMeshData->GetLink(Abs(aLinksIt.Value()));
gp_Pnt aPnt[2];
for (Standard_Integer i = 0; i < 2; ++i)
{
const Standard_Integer aNodeId = (i == 0) ? aLink.FirstNode() : aLink.LastNode();
const gp_XY& aNode = aMeshData->GetNode(aNodeId).Coord();
aPnt[i] = gp_Pnt(aNode.X(), aNode.Y(), 0.);
}
if (aPnt[0].SquareDistance(aPnt[1]) < Precision::SquareConfusion())
continue;
aBuilder.Add(aMesh, BRepBuilderAPI_MakeEdge(aPnt[0], aPnt[1]));
}
if (!BRepTools::Write(aMesh, theFileNameStr))
return "Error: write failed";
}
catch (Standard_Failure const& anException)
{
return anException.GetMessageString();
}
return theFileNameStr;
}
#endif