Loading files
// Created on: 2007-12-08
// Created by: Alexander GRIGORIEV
// Copyright (c) 2007-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 <Poly_CoherentTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <Poly_Triangle.hxx>
#include <NCollection_Array1.hxx>
#include <NCollection_List.hxx>
#include <Precision.hxx>
#include <Standard_ProgramError.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Poly_CoherentTriangulation, Standard_Transient)
//=================================================================================================
Poly_CoherentTriangulation::Poly_CoherentTriangulation(
const occ::handle<NCollection_BaseAllocator>& theAlloc)
: myAlloc(theAlloc.IsNull() ? NCollection_BaseAllocator::CommonBaseAllocator() : theAlloc),
myDeflection(0.)
{
}
//=================================================================================================
Poly_CoherentTriangulation::Poly_CoherentTriangulation(
const occ::handle<Poly_Triangulation>& theTriangulation,
const occ::handle<NCollection_BaseAllocator>& theAlloc)
: myAlloc(theAlloc.IsNull() ? NCollection_BaseAllocator::CommonBaseAllocator() : theAlloc)
{
if (!theTriangulation.IsNull())
{
const int nNodes = theTriangulation->NbNodes();
int i;
// Copy the nodes
for (i = 0; i < nNodes; i++)
{
const int anOldInd = i + 1;
const int aNewInd = SetNode(theTriangulation->Node(anOldInd).XYZ(), i);
Poly_CoherentNode& aCopiedNode = myNodes(aNewInd);
aCopiedNode.SetIndex(anOldInd);
}
// Copy the triangles
for (i = 1; i <= theTriangulation->NbTriangles(); i++)
{
int iNode[3];
theTriangulation->Triangle(i).Get(iNode[0], iNode[1], iNode[2]);
if (iNode[0] != iNode[1] && iNode[1] != iNode[2] && iNode[2] != iNode[0])
{
AddTriangle(iNode[0] - 1, iNode[1] - 1, iNode[2] - 1);
}
}
// Copy UV coordinates of nodes
if (theTriangulation->HasUVNodes())
{
for (i = 0; i < nNodes; i++)
{
const gp_Pnt2d anUV = theTriangulation->UVNode(i + 1);
myNodes(i).SetUV(anUV.X(), anUV.Y());
}
}
// Copy the normals at nodes
if (theTriangulation->HasNormals())
{
NCollection_Vec3<float> aNormal;
for (i = 0; i < nNodes; i++)
{
theTriangulation->Normal(i + 1, aNormal);
myNodes(i).SetNormal(gp_XYZ(aNormal.x(), aNormal.y(), aNormal.z()));
}
}
myDeflection = theTriangulation->Deflection();
}
}
//=================================================================================================
Poly_CoherentTriangulation::~Poly_CoherentTriangulation()
{
NCollection_DynamicArray<Poly_CoherentNode>::Iterator anIter(myNodes);
for (; anIter.More(); anIter.Next())
{
anIter.ChangeValue().Clear(myAlloc);
}
}
//=================================================================================================
occ::handle<Poly_Triangulation> Poly_CoherentTriangulation::GetTriangulation() const
{
const int nNodes = NNodes();
const int nTriangles = NTriangles();
if (nNodes == 0 || nTriangles == 0)
{
return occ::handle<Poly_Triangulation>();
}
occ::handle<Poly_Triangulation> aResult = new Poly_Triangulation(nNodes, nTriangles, false);
NCollection_DynamicArray<int> vecNodeId;
int aCount = 0;
// Copy the nodes (3D and 2D coordinates)
for (int i = 0; i < myNodes.Length(); i++)
{
const Poly_CoherentNode& aNode = myNodes(i);
if (aNode.IsFreeNode())
{
vecNodeId.SetValue(i, 0);
continue;
}
vecNodeId.SetValue(i, ++aCount);
const gp_XYZ aNormal = aNode.GetNormal();
if (aNormal.SquareModulus() > Precision::Confusion())
{
aResult->AddNormals();
aResult->SetNormal(aCount, gp_Dir(aNormal));
}
aResult->SetNode(aCount, aNode);
if (aNode.GetU() * aNode.GetU() + aNode.GetV() * aNode.GetV() > Precision::Confusion())
{
aResult->AddUVNodes();
aResult->SetUVNode(aCount, gp_Pnt2d(aNode.GetU(), aNode.GetV()));
}
}
// Copy the triangles
aCount = 0;
for (NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator anIterT(myTriangles);
anIterT.More();
anIterT.Next())
{
const Poly_CoherentTriangle& aTri = anIterT.Value();
if (!aTri.IsEmpty())
{
aResult->SetTriangle(
++aCount,
Poly_Triangle(vecNodeId(aTri.Node(0)), vecNodeId(aTri.Node(1)), vecNodeId(aTri.Node(2))));
}
}
aResult->Deflection(myDeflection);
return aResult;
}
//=================================================================================================
bool Poly_CoherentTriangulation::GetFreeNodes(NCollection_List<int>& lstNodes) const
{
lstNodes.Clear();
int i;
for (i = 0; i < myNodes.Length(); i++)
{
const Poly_CoherentNode& aNode = myNodes(i);
if (aNode.IsFreeNode())
{
lstNodes.Append(i);
}
}
return !lstNodes.IsEmpty();
}
//=======================================================================
// function : RemoveDegenerated
// purpose : Find and remove degenerated triangles in Triangulation.
//=======================================================================
bool Poly_CoherentTriangulation::RemoveDegenerated(
const double theTol,
NCollection_List<Poly_CoherentTriangulation::TwoIntegers>* pLstRemovedNode)
{
bool aResult(false);
const double aTol2 = theTol * theTol;
const int ind0[] = {2, 0, 1, 2, 0};
const int* ind = &ind0[1];
if (pLstRemovedNode)
{
pLstRemovedNode->Clear();
}
// NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator anIterT(myTriangles);
Poly_CoherentTriangulation::IteratorOfTriangle anIterT(this);
for (; anIterT.More(); anIterT.Next())
{
Poly_CoherentTriangle& aTri = anIterT.ChangeValue();
Poly_CoherentNode* pNode[3] = {&ChangeNode(aTri.Node(0)),
&ChangeNode(aTri.Node(1)),
&ChangeNode(aTri.Node(2))};
const double aLen2[3] = {pNode[2]->Subtracted(*pNode[1]).SquareModulus(),
pNode[0]->Subtracted(*pNode[2]).SquareModulus(),
pNode[1]->Subtracted(*pNode[0]).SquareModulus()};
for (int i = 0; i < 3; i++)
{
if (aLen2[i] < aTol2)
{
const int im1(aTri.Node(ind[i - 1]));
const int ip1(aTri.Node(ind[i + 1]));
// Disconnect from both neighbours
RemoveTriangle(aTri);
// Reconnect all triangles from Node(ind[i+1]) to Node(ind[i-1])
for (;;)
{
Poly_CoherentTriPtr::Iterator anIterConn = pNode[ind[i + 1]]->TriangleIterator();
if (!anIterConn.More())
{
break;
}
Poly_CoherentTriangle& aTriConn = anIterConn.ChangeValue();
int aNewTriConn[] = {aTriConn.Node(0), aTriConn.Node(1), aTriConn.Node(2)};
if (&aTriConn != &aTri)
{
if (aNewTriConn[0] == ip1)
{
aNewTriConn[0] = im1;
}
else if (aNewTriConn[1] == ip1)
{
aNewTriConn[1] = im1;
}
else if (aNewTriConn[2] == ip1)
{
aNewTriConn[2] = im1;
}
RemoveTriangle(aTriConn);
AddTriangle(aNewTriConn[0], aNewTriConn[1], aNewTriConn[2]);
}
else
{
anIterConn.Next();
if (!anIterConn.More())
{
break;
}
}
}
if (pLstRemovedNode)
{
pLstRemovedNode->Append(TwoIntegers(ip1, im1));
}
aResult = true;
break;
}
}
}
return aResult;
}
//=================================================================================================
Poly_CoherentTriangulation::IteratorOfTriangle::IteratorOfTriangle(
const occ::handle<Poly_CoherentTriangulation>& theTri)
{
if (!theTri.IsNull())
{
Init(theTri->myTriangles);
while (More())
{
const Poly_CoherentTriangle& aTri = Value();
if (!aTri.IsEmpty())
{
break;
}
NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator::Next();
}
}
}
//=================================================================================================
void Poly_CoherentTriangulation::IteratorOfTriangle::Next() noexcept
{
NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator::Next();
while (More())
{
const Poly_CoherentTriangle& aTri = Value();
if (!aTri.IsEmpty())
{
break;
}
NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator::Next();
}
}
//=================================================================================================
Poly_CoherentTriangulation::IteratorOfNode::IteratorOfNode(
const occ::handle<Poly_CoherentTriangulation>& theTri)
{
if (!theTri.IsNull())
{
Init(theTri->myNodes);
while (More())
{
if (!Value().IsFreeNode())
{
break;
}
NCollection_DynamicArray<Poly_CoherentNode>::Iterator::Next();
}
}
}
//=================================================================================================
void Poly_CoherentTriangulation::IteratorOfNode::Next() noexcept
{
NCollection_DynamicArray<Poly_CoherentNode>::Iterator::Next();
while (More())
{
if (!Value().IsFreeNode())
{
break;
}
NCollection_DynamicArray<Poly_CoherentNode>::Iterator::Next();
}
}
//=================================================================================================
Poly_CoherentTriangulation::IteratorOfLink::IteratorOfLink(
const occ::handle<Poly_CoherentTriangulation>& theTri)
{
if (!theTri.IsNull())
{
Init(theTri->myLinks);
while (More())
{
if (!Value().IsEmpty())
{
break;
}
NCollection_DynamicArray<Poly_CoherentLink>::Iterator::Next();
}
}
}
//=================================================================================================
void Poly_CoherentTriangulation::IteratorOfLink::Next() noexcept
{
NCollection_DynamicArray<Poly_CoherentLink>::Iterator::Next();
while (More())
{
if (!Value().IsEmpty())
{
break;
}
NCollection_DynamicArray<Poly_CoherentLink>::Iterator::Next();
}
}
//=================================================================================================
int Poly_CoherentTriangulation::NNodes() const
{
int aCount(0);
NCollection_DynamicArray<Poly_CoherentNode>::Iterator anIter(myNodes);
for (; anIter.More(); anIter.Next())
{
if (!anIter.Value().IsFreeNode())
{
aCount++;
}
}
return aCount;
}
//=================================================================================================
int Poly_CoherentTriangulation::NTriangles() const
{
int aCount(0);
NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator anIter(myTriangles);
for (; anIter.More(); anIter.Next())
{
const Poly_CoherentTriangle& aTri = anIter.Value();
if (!aTri.IsEmpty())
{
aCount++;
}
}
return aCount;
}
//=================================================================================================
int Poly_CoherentTriangulation::NLinks() const
{
int aCount(0);
NCollection_DynamicArray<Poly_CoherentLink>::Iterator anIter(myLinks);
for (; anIter.More(); anIter.Next())
{
if (!anIter.Value().IsEmpty())
{
aCount++;
}
}
return aCount;
}
//=================================================================================================
int Poly_CoherentTriangulation::SetNode(const gp_XYZ& thePnt, const int iNode)
{
int aResult = myNodes.Length();
if (iNode < 0)
{
myNodes.Append(Poly_CoherentNode(thePnt));
}
else
{
myNodes.SetValue(iNode, Poly_CoherentNode(thePnt));
aResult = iNode;
}
return aResult;
}
//=================================================================================================
bool Poly_CoherentTriangulation::RemoveTriangle(Poly_CoherentTriangle& theTriangle)
{
bool aResult(false);
for (int i = 0; i < 3; i++)
{
if (theTriangle.Node(i) >= 0)
{
Poly_CoherentNode& aNode = myNodes(theTriangle.Node(i));
// If Links exist in this Triangulation, remove or update a Link
Poly_CoherentLink* aLink = const_cast<Poly_CoherentLink*>(theTriangle.mypLink[i]);
if (aLink)
{
const Poly_CoherentTriangle* pTriOpp = theTriangle.GetConnectedTri(i);
bool toRemoveLink(true);
if (pTriOpp != nullptr)
{
// A neighbour is detected. If a Link exists on it, update it,
// otherwise remove this link
for (int j = 0; j < 3; j++)
{
if (aLink == pTriOpp->GetLink(j))
{
if (aLink->OppositeNode(0) == theTriangle.Node(i))
{
aLink->myOppositeNode[0] = -1;
toRemoveLink = false;
}
else if (aLink->OppositeNode(1) == theTriangle.Node(i))
{
aLink->myOppositeNode[1] = -1;
toRemoveLink = false;
}
break;
}
}
}
if (toRemoveLink)
{
RemoveLink(*aLink);
}
}
if (aNode.RemoveTriangle(theTriangle, myAlloc))
{
theTriangle.myNodes[i] = -1;
aResult = true;
}
}
theTriangle.RemoveConnection(i);
}
return aResult;
}
//=================================================================================================
Poly_CoherentTriangle* Poly_CoherentTriangulation::AddTriangle(const int iNode0,
const int iNode1,
const int iNode2)
{
Poly_CoherentTriangle* pTriangle = nullptr;
if (iNode0 >= 0 && iNode1 >= 0 && iNode2 >= 0)
{
pTriangle = &myTriangles.Append(Poly_CoherentTriangle());
ReplaceNodes(*pTriangle, iNode0, iNode1, iNode2);
}
return pTriangle;
}
//=================================================================================================
bool Poly_CoherentTriangulation::ReplaceNodes(Poly_CoherentTriangle& theTriangle,
const int iNode0,
const int iNode1,
const int iNode2)
{
if (!theTriangle.IsEmpty())
{
RemoveTriangle(theTriangle);
}
if (iNode0 >= 0 && iNode1 >= 0 && iNode2 >= 0)
{
theTriangle = Poly_CoherentTriangle(iNode0, iNode1, iNode2);
for (int i = 0; i < 3; i++)
{
Poly_CoherentNode& aNode = myNodes(theTriangle.Node(i));
Poly_CoherentTriPtr::Iterator anIterT = aNode.TriangleIterator();
for (; anIterT.More(); anIterT.Next())
{
anIterT.ChangeValue().SetConnection(theTriangle);
}
aNode.AddTriangle(theTriangle, myAlloc);
}
// If Links exist in this Triangulation, create or update a Link
if (myLinks.Length() > 0)
{
for (int i = 0; i < 3; i++)
{
const Poly_CoherentTriangle* pTriOpp = theTriangle.GetConnectedTri(i);
bool toAddLink(true);
if (pTriOpp != nullptr)
{
// A neighbour is detected. If a Link exists on it, update it,
// otherwise create a new link.
for (int j = 0; j < 3; j++)
{
if (theTriangle.Node(i) == pTriOpp->GetConnectedNode(j))
{
Poly_CoherentLink* aLink = const_cast<Poly_CoherentLink*>(pTriOpp->GetLink(j));
if (aLink != nullptr)
{
if (aLink->OppositeNode(0) == pTriOpp->Node(j))
{
aLink->myOppositeNode[1] = theTriangle.Node(i);
toAddLink = false;
}
else if (aLink->OppositeNode(1) == pTriOpp->Node(j))
{
aLink->myOppositeNode[0] = theTriangle.Node(i);
toAddLink = false;
}
}
}
}
}
if (toAddLink)
{
// No neighbor on this side, the new Link is created.
AddLink(theTriangle, i);
}
}
}
return true;
}
return false;
}
//=================================================================================================
void Poly_CoherentTriangulation::RemoveLink(Poly_CoherentLink& theLink)
{
const Poly_CoherentTriangle* pTri[2] = {nullptr, nullptr};
if (FindTriangle(theLink, pTri))
{
for (int i = 0; i < 2; i++)
{
const int iNode = theLink.OppositeNode(i);
if (iNode >= 0 && pTri[i] != nullptr)
{
if (iNode == pTri[i]->Node(0))
{
const_cast<Poly_CoherentTriangle*>(pTri[i])->mypLink[0] = nullptr;
}
else if (iNode == pTri[i]->Node(1))
{
const_cast<Poly_CoherentTriangle*>(pTri[i])->mypLink[1] = nullptr;
}
else if (iNode == pTri[i]->Node(2))
{
const_cast<Poly_CoherentTriangle*>(pTri[i])->mypLink[2] = nullptr;
}
else
{
throw Standard_ProgramError("Poly_CoherentTriangulation::RemoveLink: "
" wrong connectivity between triangles");
}
}
}
}
theLink = Poly_CoherentLink();
}
//=================================================================================================
Poly_CoherentLink* Poly_CoherentTriangulation::AddLink(const Poly_CoherentTriangle& theTri,
const int theConn)
{
Poly_CoherentLink* pLink = nullptr;
if (!theTri.IsEmpty())
{
pLink = &myLinks.Append(Poly_CoherentLink(theTri, theConn));
const_cast<Poly_CoherentTriangle&>(theTri).mypLink[theConn] = pLink;
const Poly_CoherentTriangle* pTriOpp = theTri.GetConnectedTri(theConn);
if (!pTriOpp)
{
return pLink;
}
if (pTriOpp->IsEmpty())
{
return pLink;
}
if (pTriOpp)
{
if (pTriOpp->Node(0) == theTri.GetConnectedNode(theConn))
{
const_cast<Poly_CoherentTriangle*>(pTriOpp)->mypLink[0] = pLink;
}
else if (pTriOpp->Node(1) == theTri.GetConnectedNode(theConn))
{
const_cast<Poly_CoherentTriangle*>(pTriOpp)->mypLink[1] = pLink;
}
else if (pTriOpp->Node(2) == theTri.GetConnectedNode(theConn))
{
const_cast<Poly_CoherentTriangle*>(pTriOpp)->mypLink[2] = pLink;
}
else
{
throw Standard_ProgramError("Poly_CoherentTriangulation::AddLink: "
"Bad connectivity of triangles");
}
}
}
return pLink;
}
//=================================================================================================
bool Poly_CoherentTriangulation::FindTriangle(const Poly_CoherentLink& theLink,
const Poly_CoherentTriangle* pTri[2]) const
{
pTri[0] = nullptr;
pTri[1] = nullptr;
const int iNode0 = theLink.Node(0);
if (!theLink.IsEmpty() && iNode0 < myNodes.Length() && theLink.Node(1) < myNodes.Length())
{
Poly_CoherentTriPtr::Iterator anIter0 = myNodes(iNode0).TriangleIterator();
for (; anIter0.More(); anIter0.Next())
{
const Poly_CoherentTriangle& aTri = anIter0.Value();
if (aTri.Node(0) == iNode0)
{
if (aTri.Node(1) == theLink.Node(1))
{
pTri[0] = &aTri;
}
else if (aTri.Node(2) == theLink.Node(1))
{
pTri[1] = &aTri;
}
}
else if (aTri.Node(1) == iNode0)
{
if (aTri.Node(2) == theLink.Node(1))
{
pTri[0] = &aTri;
}
else if (aTri.Node(0) == theLink.Node(1))
{
pTri[1] = &aTri;
}
}
else if (aTri.Node(2) == iNode0)
{
if (aTri.Node(0) == theLink.Node(1))
{
pTri[0] = &aTri;
}
else if (aTri.Node(1) == theLink.Node(1))
{
pTri[1] = &aTri;
}
}
else
{
throw Standard_ProgramError("Poly_CoherentTriangulation::FindTriangle : "
" Data incoherence detected");
}
if (pTri[0] && pTri[1])
{
break;
}
}
}
return (pTri[0] != nullptr || pTri[1] != nullptr);
}
//=================================================================================================
int Poly_CoherentTriangulation::ComputeLinks()
{
myLinks.Clear();
NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator anIter(myTriangles);
for (; anIter.More(); anIter.Next())
{
const Poly_CoherentTriangle& aTriangle = anIter.Value();
if (aTriangle.IsEmpty())
{
continue;
}
if (aTriangle.Node(0) < aTriangle.Node(1))
{
AddLink(aTriangle, 2);
}
if (aTriangle.Node(1) < aTriangle.Node(2))
{
AddLink(aTriangle, 0);
}
if (aTriangle.Node(2) < aTriangle.Node(0))
{
AddLink(aTriangle, 1);
}
}
// Above algorithm does not create all boundary links, so
// it is necessary to check triangles and add absentee links
anIter.Init(myTriangles);
int i;
for (; anIter.More(); anIter.Next())
{
Poly_CoherentTriangle& aTriangle = anIter.ChangeValue();
if (aTriangle.IsEmpty())
{
continue;
}
for (i = 0; i < 3; ++i)
{
if (aTriangle.mypLink[i] == nullptr)
{
AddLink(aTriangle, i);
}
}
}
return myLinks.Length();
}
//=================================================================================================
void Poly_CoherentTriangulation::ClearLinks()
{
myLinks.Clear();
NCollection_DynamicArray<Poly_CoherentTriangle>::Iterator anIter(myTriangles);
for (; anIter.More(); anIter.Next())
{
Poly_CoherentTriangle& aTriangle = anIter.ChangeValue();
aTriangle.mypLink[0] = nullptr;
aTriangle.mypLink[1] = nullptr;
aTriangle.mypLink[2] = nullptr;
}
}
//=================================================================================================
occ::handle<Poly_CoherentTriangulation> Poly_CoherentTriangulation::Clone(
const occ::handle<NCollection_BaseAllocator>& theAlloc) const
{
occ::handle<Poly_CoherentTriangulation> newTri;
if (NTriangles() != 0 && NNodes() != 0)
{
occ::handle<Poly_Triangulation> theTriangulation = GetTriangulation();
newTri = new Poly_CoherentTriangulation(theTriangulation, theAlloc);
newTri->SetDeflection(theTriangulation->Deflection());
}
return newTri;
}
//=================================================================================================
void Poly_CoherentTriangulation::Dump(Standard_OStream& theStream) const
{
for (int iNode = 0; iNode < myNodes.Length(); iNode++)
{
const Poly_CoherentNode& aNode = myNodes(iNode);
if (aNode.IsFreeNode())
{
continue;
}
theStream << "Node " << iNode;
aNode.Dump(theStream);
}
}
3d097a032This file is pinned to the selected release. Download the original to open it in your design tool.