mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2024-11-13 17:18:35 +05:00
519 lines
20 KiB
C++
519 lines
20 KiB
C++
// Copyright (C) 2007-2019 CEA/DEN, EDF R&D, OPEN CASCADE
|
|
//
|
|
// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
|
|
// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 of the License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
|
|
//
|
|
// File : SMESH_FillHole.cxx
|
|
// Created : Tue Sep 26 15:11:17 2017
|
|
// Author : Edward AGAPOV (eap)
|
|
//
|
|
|
|
#include "SMESH_MeshAlgos.hxx"
|
|
|
|
#include "SMESH_Comment.hxx"
|
|
|
|
#include "ObjectPool.hxx"
|
|
#include "SMDS_Mesh.hxx"
|
|
#include "SMESH_TypeDefs.hxx"
|
|
|
|
#include <Utils_SALOME_Exception.hxx>
|
|
|
|
#include <boost/intrusive/circular_list_algorithms.hpp>
|
|
#include <boost/container/flat_map.hpp>
|
|
|
|
#include <Bnd_B3d.hxx>
|
|
|
|
namespace
|
|
{
|
|
bool isSmallAngle( double cos2 )
|
|
{
|
|
// cosine of min angle at which adjacent faces are considered overlapping
|
|
const double theMinCos2 = 0.996 * 0.996; // ~5 degrees
|
|
return ( cos2 > theMinCos2 );
|
|
}
|
|
|
|
struct BEdge;
|
|
typedef std::multimap< double, BEdge* > TAngleMap;
|
|
typedef std::map< const SMDS_MeshElement*, int > TFaceIndMap;
|
|
|
|
//--------------------------------------------------------------------------------
|
|
/*!
|
|
* \brief Edge of a free border
|
|
*/
|
|
struct BEdge
|
|
{
|
|
const SMDS_MeshNode* myNode1;
|
|
const SMDS_MeshNode* myNode2;
|
|
const SMDS_MeshElement* myFace; // face adjacent to the border
|
|
|
|
gp_XYZ myFaceNorm;
|
|
gp_XYZ myDir; // myNode1 -> myNode2
|
|
double myDirCoef; // 1. or -1, to make myDir oriented as myNodes in myFace
|
|
double myLength; // between nodes
|
|
double myAngleWithPrev; // between myDir and -myPrev->myDir
|
|
double myMinMaxRatio; // of a possible triangle sides
|
|
TAngleMap::iterator myAngleMapPos;
|
|
double myOverlapAngle; // angle delta due to overlapping
|
|
const SMDS_MeshNode* myNode1Shift; // nodes created to avoid overlapping of faces
|
|
const SMDS_MeshNode* myNode2Shift;
|
|
|
|
BEdge* myPrev; // neighbors in the border
|
|
BEdge* myNext;
|
|
|
|
BEdge(): myNode1Shift(0), myNode2Shift(0) {}
|
|
void Init( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2,
|
|
const SMDS_MeshElement* f=0,
|
|
const SMDS_MeshNode* nf1=0, const SMDS_MeshNode* nf2=0 );
|
|
void ComputeAngle( bool reverseAngle = false );
|
|
void ShiftOverlapped( const SMDS_MeshNode* oppNode,
|
|
const TFaceIndMap& capFaceWithBordInd,
|
|
SMDS_Mesh& mesh,
|
|
std::vector<const SMDS_MeshElement*>& newFaces);
|
|
void MakeShiftfFaces( SMDS_Mesh& mesh,
|
|
std::vector<const SMDS_MeshElement*>& newFaces,
|
|
const bool isReverse );
|
|
gp_XYZ GetInFaceDir() const { return myFaceNorm ^ myDir * myDirCoef; }
|
|
double ShapeFactor() const { return 0.5 * ( 1. - myMinMaxRatio ); }
|
|
void InsertSelf(TAngleMap& edgesByAngle, bool isReverseFaces, bool reBind, bool useOverlap )
|
|
{
|
|
if ( reBind ) edgesByAngle.erase( myAngleMapPos );
|
|
double key = (( isReverseFaces ? 2 * M_PI - myAngleWithPrev : myAngleWithPrev )
|
|
+ myOverlapAngle * useOverlap
|
|
+ ShapeFactor() );
|
|
myAngleMapPos = edgesByAngle.insert( std::make_pair( key, this ));
|
|
}
|
|
|
|
// traits used by boost::intrusive::circular_list_algorithms
|
|
typedef BEdge node;
|
|
typedef BEdge * node_ptr;
|
|
typedef const BEdge * const_node_ptr;
|
|
static node_ptr get_next(const_node_ptr n) { return n->myNext; }
|
|
static void set_next(node_ptr n, node_ptr next) { n->myNext = next; }
|
|
static node_ptr get_previous(const_node_ptr n) { return n->myPrev; }
|
|
static void set_previous(node_ptr n, node_ptr prev){ n->myPrev = prev; }
|
|
};
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Initialize a border edge data
|
|
*/
|
|
//================================================================================
|
|
|
|
void BEdge::Init( const SMDS_MeshNode* n1,
|
|
const SMDS_MeshNode* n2,
|
|
const SMDS_MeshElement* newFace, // new cap face
|
|
const SMDS_MeshNode* nf1,
|
|
const SMDS_MeshNode* nf2 )
|
|
{
|
|
myNode1 = n1;
|
|
myNode2 = n2;
|
|
myDir = SMESH_NodeXYZ( n2 ) - SMESH_NodeXYZ( n1 );
|
|
myLength = myDir.Modulus();
|
|
if ( myLength > std::numeric_limits<double>::min() )
|
|
myDir /= myLength;
|
|
|
|
myFace = newFace;
|
|
if ( !myFace )
|
|
{
|
|
TIDSortedElemSet elemSet, avoidSet;
|
|
int ind1, ind2;
|
|
myFace = SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet, &ind1, &ind2 );
|
|
if ( !myFace )
|
|
throw SALOME_Exception( SMESH_Comment("No face sharing nodes #")
|
|
<< myNode1->GetID() << " and #" << myNode2->GetID());
|
|
avoidSet.insert( myFace );
|
|
if ( SMESH_MeshAlgos::FindFaceInSet( n1, n2, elemSet, avoidSet ))
|
|
throw SALOME_Exception( SMESH_Comment("No free border between nodes #")
|
|
<< myNode1->GetID() << " and #" << myNode2->GetID());
|
|
|
|
myDirCoef = SMESH_MeshAlgos::IsRightOrder( myFace, myNode1, myNode2 ) ? 1. : -1.;
|
|
}
|
|
|
|
if (! SMESH_MeshAlgos::FaceNormal( myFace, myFaceNorm, /*normalized=*/false ))
|
|
{
|
|
SMDS_ElemIteratorPtr fIt = myNode1->GetInverseElementIterator( SMDSAbs_Face );
|
|
while ( fIt->more() )
|
|
if ( SMESH_MeshAlgos::FaceNormal( fIt->next(), myFaceNorm, /*normalized=*/false ))
|
|
break;
|
|
}
|
|
|
|
if ( newFace )
|
|
{
|
|
myFace = 0;
|
|
myDirCoef = SMESH_MeshAlgos::IsRightOrder( newFace, nf1, nf2 ) ? 1. : -1.;
|
|
if ( myPrev->myNode2 == n1 )
|
|
myNode1Shift = myPrev->myNode2Shift;
|
|
if ( myNext->myNode1 == n2 )
|
|
myNode2Shift = myNext->myNode1Shift;
|
|
}
|
|
else if ( myDirCoef * myPrev->myDirCoef < 0 ) // different orientation of faces
|
|
{
|
|
myFaceNorm *= -1;
|
|
myDirCoef *= -1;
|
|
}
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Compute myAngleWithPrev
|
|
*/
|
|
//================================================================================
|
|
|
|
void BEdge::ComputeAngle( bool theReverseAngle )
|
|
{
|
|
double dot = myDir.Dot( myPrev->myDir.Reversed() );
|
|
if ( dot >= 1 ) myAngleWithPrev = 0;
|
|
else if ( dot <= -1 ) myAngleWithPrev = M_PI;
|
|
else myAngleWithPrev = acos( dot );
|
|
|
|
bool isObtuse;
|
|
gp_XYZ inFaceDirNew = myDir - myPrev->myDir;
|
|
gp_XYZ inFaceDir1 = myPrev->GetInFaceDir();
|
|
gp_XYZ inFaceDir2 = this->GetInFaceDir();
|
|
double dot1 = inFaceDirNew * inFaceDir1;
|
|
double dot2 = inFaceDirNew * inFaceDir2;
|
|
bool isOverlap1 = ( dot1 > 0 );
|
|
bool isOverlap2 = ( dot2 > 0 );
|
|
if ( !myPrev->myFace )
|
|
isObtuse = isOverlap1;
|
|
else if ( !myFace )
|
|
isObtuse = isOverlap2;
|
|
else
|
|
{
|
|
double dt1 = myDir.Dot( myPrev->myFaceNorm );
|
|
double dt2 = myPrev->myDir.Dot( myFaceNorm );
|
|
isObtuse = ( dt1 > 0 || dt2 < 0 ); // suppose face normals point outside the border
|
|
if ( theReverseAngle )
|
|
isObtuse = !isObtuse;
|
|
}
|
|
if ( isObtuse )
|
|
{
|
|
myAngleWithPrev = 2 * M_PI - myAngleWithPrev;
|
|
}
|
|
|
|
// if ( ! isObtuse )
|
|
// isObtuse =
|
|
// isSmallAngle( 1 - myDir.CrossSquareMagnitude( myPrev->myDir )); // edges co-directed
|
|
|
|
myOverlapAngle = 0;
|
|
//if ( !isObtuse )
|
|
{
|
|
// check if myFace and a triangle built on this and prev edges overlap
|
|
if ( isOverlap1 )
|
|
{
|
|
double cos2 = dot1 * dot1 / inFaceDirNew.SquareModulus() / inFaceDir1.SquareModulus();
|
|
myOverlapAngle += 1. * M_PI * cos2;
|
|
}
|
|
if ( isOverlap2 )
|
|
{
|
|
double cos2 = dot2 * dot2 / inFaceDirNew.SquareModulus() / inFaceDir2.SquareModulus();
|
|
myOverlapAngle += 1. * M_PI * cos2;
|
|
}
|
|
}
|
|
|
|
{
|
|
double len3 = SMESH_NodeXYZ( myPrev->myNode1 ).Distance( myNode2 );
|
|
double minLen = Min( myLength, Min( myPrev->myLength, len3 ));
|
|
double maxLen = Max( myLength, Max( myPrev->myLength, len3 ));
|
|
myMinMaxRatio = minLen / maxLen;
|
|
}
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Check if myFace is overlapped by a triangle formed by myNode's and a
|
|
* given node. If so, create shifted nodes to avoid overlapping
|
|
*/
|
|
//================================================================================
|
|
|
|
void BEdge::ShiftOverlapped( const SMDS_MeshNode* theOppNode,
|
|
const TFaceIndMap& theCapFaceWithBordInd,
|
|
SMDS_Mesh& theMesh,
|
|
std::vector<const SMDS_MeshElement*>& theNewFaces )
|
|
{
|
|
if ( myNode1Shift && myNode2Shift )
|
|
return;
|
|
|
|
gp_XYZ inNewFaceDir = SMESH_NodeXYZ( theOppNode ) - SMESH_NodeXYZ( myNode1 );
|
|
double dot = inNewFaceDir.Dot( myFaceNorm );
|
|
double cos2 = dot * dot / myFaceNorm.SquareModulus() / inNewFaceDir.SquareModulus();
|
|
bool isOverlap = ( isSmallAngle( 1 - cos2 ) && GetInFaceDir() * inNewFaceDir > 0 );
|
|
|
|
if ( isOverlap )
|
|
{
|
|
gp_XYZ shift = myFaceNorm / myLength / 4;
|
|
if ( myFace )
|
|
shift.Reverse();
|
|
if ( !myNode1Shift )
|
|
{
|
|
gp_XYZ p = SMESH_NodeXYZ( myNode1 ) + shift;
|
|
myNode1Shift = theMesh.AddNode( p.X(), p.Y(), p.Z() );
|
|
myPrev->myNode2Shift = myNode1Shift;
|
|
}
|
|
if ( !myNode2Shift )
|
|
{
|
|
gp_XYZ p = SMESH_NodeXYZ( myNode2 ) + shift;
|
|
myNode2Shift = theMesh.AddNode( p.X(), p.Y(), p.Z() );
|
|
myNext->myNode1Shift = myNode2Shift;
|
|
}
|
|
|
|
// MakeShiftfFaces() for already created cap faces
|
|
for ( int is2nd = 0; is2nd < 2; ++is2nd )
|
|
{
|
|
const SMDS_MeshNode* ns = is2nd ? myNode2Shift : myNode1Shift;
|
|
const SMDS_MeshNode* n = is2nd ? myNode2 : myNode1;
|
|
if ( !ns ) continue;
|
|
|
|
SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator( SMDSAbs_Face );
|
|
while ( fIt->more() )
|
|
{
|
|
const SMDS_MeshElement* f = fIt->next();
|
|
if ( !f->isMarked() ) continue;
|
|
|
|
TFaceIndMap::const_iterator f2i = theCapFaceWithBordInd.find( f );
|
|
if ( f2i == theCapFaceWithBordInd.end() )
|
|
continue;
|
|
const SMDS_MeshNode* nf1 = f->GetNode( f2i->second );
|
|
const SMDS_MeshNode* nf2 = f->GetNode(( f2i->second+1 ) % f->NbNodes() );
|
|
if ( nf1 == n || nf2 == n )
|
|
{
|
|
BEdge tmpE;
|
|
tmpE.myPrev = tmpE.myNext = this;
|
|
tmpE.Init( nf1, nf2, f, nf1, nf2 );
|
|
if ( !tmpE.myNode1Shift && !tmpE.myNode2Shift )
|
|
tmpE.Init( nf2, nf1, f, nf2, nf1 );
|
|
tmpE.myFace = f;
|
|
tmpE.MakeShiftfFaces( theMesh, theNewFaces, tmpE.myDirCoef < 0 );
|
|
}
|
|
std::vector< const SMDS_MeshNode* > nodes( f->begin_nodes(), f->end_nodes() );
|
|
nodes[ f->GetNodeIndex( n ) ] = ns;
|
|
theMesh.ChangeElementNodes( f, &nodes[0], nodes.size() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Create a triangle
|
|
*/
|
|
//================================================================================
|
|
|
|
const SMDS_MeshElement* MakeTria( SMDS_Mesh& mesh,
|
|
const SMDS_MeshNode* n1,
|
|
const SMDS_MeshNode* n2,
|
|
const SMDS_MeshNode* n3,
|
|
const bool isReverse )
|
|
{
|
|
if ( isReverse )
|
|
return mesh.AddFace( n1, n3, n2 );
|
|
return mesh.AddFace( n1, n2, n3 );
|
|
}
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Create a quadrangle
|
|
*/
|
|
//================================================================================
|
|
|
|
// const SMDS_MeshElement* MakeQuad( SMDS_Mesh& mesh,
|
|
// const SMDS_MeshNode* n1,
|
|
// const SMDS_MeshNode* n2,
|
|
// const SMDS_MeshNode* n3,
|
|
// const SMDS_MeshNode* n4,
|
|
// const bool isReverse )
|
|
// {
|
|
// if ( isReverse )
|
|
// return mesh.AddFace( n4, n3, n2, n1 );
|
|
// return mesh.AddFace( n1, n2, n3, n4 );
|
|
// }
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Create faces on myNode* and myNode*Shift
|
|
*/
|
|
//================================================================================
|
|
|
|
void BEdge::MakeShiftfFaces(SMDS_Mesh& mesh,
|
|
std::vector<const SMDS_MeshElement*>& newFaces,
|
|
const bool isReverse )
|
|
{
|
|
if ( !myFace )
|
|
return;
|
|
if ( myNode1Shift && myNode2Shift )
|
|
{
|
|
newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode2Shift, isReverse ));
|
|
newFaces.push_back( MakeTria( mesh, myNode1, myNode2Shift, myNode1Shift, isReverse ));
|
|
}
|
|
else if ( myNode1Shift )
|
|
{
|
|
newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode1Shift, isReverse ));
|
|
}
|
|
else if ( myNode2Shift )
|
|
{
|
|
newFaces.push_back( MakeTria( mesh, myNode1, myNode2, myNode2Shift, isReverse ));
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
|
|
//================================================================================
|
|
/*!
|
|
* \brief Fill with 2D elements a hole defined by a TFreeBorder
|
|
*/
|
|
//================================================================================
|
|
|
|
void SMESH_MeshAlgos::FillHole(const SMESH_MeshAlgos::TFreeBorder & theFreeBorder,
|
|
SMDS_Mesh& theMesh,
|
|
std::vector<const SMDS_MeshElement*>& theNewFaces)
|
|
{
|
|
if ( theFreeBorder.size() < 4 || // at least 3 nodes
|
|
theFreeBorder[0] != theFreeBorder.back() ) // the hole must be closed
|
|
return;
|
|
|
|
// prepare data of the border
|
|
|
|
ObjectPool< BEdge > edgeAllocator;
|
|
boost::intrusive::circular_list_algorithms< BEdge > circularList;
|
|
BEdge* edge;
|
|
BEdge* edge0 = edgeAllocator.getNew();
|
|
BEdge* edgePrev = edge0;
|
|
circularList.init_header( edge0 );
|
|
edge0->Init( theFreeBorder[0], theFreeBorder[1], 0 );
|
|
Bnd_B3d box;
|
|
box.Add( SMESH_NodeXYZ( edge0->myNode1 ));
|
|
for ( size_t i = 2; i < theFreeBorder.size(); ++i )
|
|
{
|
|
edge = edgeAllocator.getNew();
|
|
circularList.link_after( edgePrev, edge );
|
|
edge->Init( theFreeBorder[i-1], theFreeBorder[i] );
|
|
edge->ComputeAngle();
|
|
edgePrev = edge;
|
|
box.Add( SMESH_NodeXYZ( edge->myNode1 ));
|
|
}
|
|
edge0->ComputeAngle();
|
|
|
|
// check if face normals point outside the border
|
|
|
|
gp_XYZ hSize = 0.5 * ( box.CornerMax() - box.CornerMin() );
|
|
const double hDelta = 1e-6 * hSize.Modulus();
|
|
hSize -= gp_XYZ( hDelta, hDelta, hDelta );
|
|
if ( hSize.X() < 0 ) hSize.SetX(hDelta);
|
|
if ( hSize.Y() < 0 ) hSize.SetY(hDelta);
|
|
if ( hSize.Z() < 0 ) hSize.SetZ(hDelta);
|
|
box.SetHSize( hSize ); // decrease the box by hDelta
|
|
|
|
size_t nbEdges = theFreeBorder.size() - 1;
|
|
edge = edge0;
|
|
int nbRev = 0, nbFrw = 0;
|
|
double angTol = M_PI - ( nbEdges - 2 ) * M_PI / nbEdges, sumDirCoeff = 0;
|
|
for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
|
|
{
|
|
if ( box.IsOut( SMESH_NodeXYZ( edge->myNode1 )) &&
|
|
edge->myOverlapAngle < 0.1 * M_PI )
|
|
{
|
|
nbRev += edge->myAngleWithPrev > M_PI + angTol;
|
|
nbFrw += edge->myAngleWithPrev < M_PI - angTol;
|
|
}
|
|
sumDirCoeff += edge->myDirCoef;
|
|
|
|
// unmark all adjacent faces, new faces will be marked
|
|
SMDS_ElemIteratorPtr fIt = edge->myNode1->GetInverseElementIterator( SMDSAbs_Face );
|
|
while ( fIt->more() )
|
|
fIt->next()->setIsMarked( false );
|
|
}
|
|
bool isReverseAngle = ( nbRev > nbFrw ); // true == face normals point inside the border
|
|
//std::cout << "nbRev="<< nbRev << ", nbFrw="<< nbFrw<<std::endl;
|
|
|
|
// sort border edges by myAngleWithPrev
|
|
|
|
TAngleMap edgesByAngle;
|
|
bool useOverlap = true; // to add BEdge.myOverlapAngle when filling edgesByAngle
|
|
edge = edge0;
|
|
for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
|
|
edge->InsertSelf( edgesByAngle, isReverseAngle, /*reBind=*/false, useOverlap );
|
|
|
|
// create triangles to fill the hole
|
|
|
|
//compare order of nodes in the edges with their order in faces
|
|
bool isReverse = sumDirCoeff > 0.5 * nbEdges;
|
|
|
|
// faces filling the hole (cap faces) and indices of border edges in them
|
|
TFaceIndMap capFaceWithBordInd;
|
|
|
|
theNewFaces.reserve( nbEdges - 2 );
|
|
std::vector< const SMDS_MeshNode* > nodes(3);
|
|
while ( edgesByAngle.size() > 2 )
|
|
{
|
|
TAngleMap::iterator a2e = edgesByAngle.begin();
|
|
edge = a2e->second;
|
|
if ( useOverlap &&
|
|
a2e->first - edge->ShapeFactor() > M_PI - angTol ) // all new triangles need shift
|
|
{
|
|
// re-sort the edges w/o overlap consideration
|
|
useOverlap = false;
|
|
nbEdges = edgesByAngle.size();
|
|
edgesByAngle.clear();
|
|
for ( size_t i = 0; i < nbEdges; ++i, edge = edge->myNext )
|
|
edge->InsertSelf( edgesByAngle, isReverseAngle, /*reBind=*/false, useOverlap );
|
|
a2e = edgesByAngle.begin();
|
|
}
|
|
edge = a2e->second;
|
|
edgePrev = edge->myPrev;
|
|
|
|
// create shift nodes and faces
|
|
edgePrev->ShiftOverlapped( edge->myNode2, capFaceWithBordInd, theMesh, theNewFaces );
|
|
edge->ShiftOverlapped( edgePrev->myNode1, capFaceWithBordInd, theMesh, theNewFaces );
|
|
edge ->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
|
|
edgePrev->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
|
|
|
|
// make a cap face
|
|
//nodes.resize( 3 );
|
|
nodes[0] = edgePrev->myNode1Shift ? edgePrev->myNode1Shift : edgePrev->myNode1;
|
|
nodes[1] = edgePrev->myNode2Shift ? edgePrev->myNode2Shift : edgePrev->myNode2;
|
|
nodes[2] = edge->myNode2Shift ? edge->myNode2Shift : edge->myNode2;
|
|
theNewFaces.push_back( MakeTria( theMesh, nodes[0], nodes[1], nodes[2], isReverse ));
|
|
// std::cout << nodes[1]->GetID() << " " << nodes[0]->GetID() << " " << nodes[2]->GetID()
|
|
// << " " << edge->myAngleWithPrev << std::endl;
|
|
|
|
// remember a border edge within the new cap face
|
|
theNewFaces.back()->setIsMarked( true );
|
|
if ( edgePrev->myFace )
|
|
capFaceWithBordInd.insert( std::make_pair( theNewFaces.back(), isReverse ? 2 : 0 ));
|
|
if ( edge->myFace )
|
|
capFaceWithBordInd.insert( std::make_pair( theNewFaces.back(), 1 ));
|
|
|
|
// remove edgePrev from the list and update <edge>
|
|
edgesByAngle.erase( edgePrev->myAngleMapPos );
|
|
circularList.unlink( edgePrev ); // remove edgePrev from the border
|
|
|
|
edge->Init( edgePrev->myNode1, edge->myNode2, theNewFaces.back(), nodes[0], nodes[2] );
|
|
edge->ComputeAngle( isReverseAngle );
|
|
edge->InsertSelf( edgesByAngle, /*isReverse=*/false, /*reBind=*/true, useOverlap );
|
|
edge->myNext->ComputeAngle( isReverseAngle );
|
|
edge->myNext->InsertSelf( edgesByAngle, /*isReverse=*/false, /*reBind=*/true, useOverlap );
|
|
// std::cout << "A " << edge->myNode1->GetID() << " " << edge->myAngleWithPrev
|
|
// << " " << edge->myNext->myNode1->GetID() << " " << edge->myNext->myAngleWithPrev
|
|
// << std::endl;
|
|
}
|
|
edge = edgesByAngle.begin()->second;
|
|
edge-> MakeShiftfFaces( theMesh, theNewFaces, isReverse );
|
|
edge->myNext->MakeShiftfFaces( theMesh, theNewFaces, isReverse );
|
|
}
|