// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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 // 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 aPolyStack; NCollection_Sequence 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 contains geometricaly // . If is != 0 then theVertex is on Edge // of index //======================================================================= 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 #include #include #include #include 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