mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-06-10 11:34:06 +03:00
Apply new regex replacement with method's guards in .cxx Update GH workflow with style checking
2568 lines
89 KiB
C++
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
|