23179: EDF 11603 - Problem with extrusion when path is not well oriented

HYDRO module: Feature #523: river, channel, embankment meshing
This commit is contained in:
eap 2015-10-09 17:47:17 +03:00
parent 0c1e70a38f
commit 512d3547bc
12 changed files with 132 additions and 97 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -229,6 +229,9 @@ have been defined will be discretized.
</hypotheses-set-group>
</meshers>
~~~~~~
If the file contents are incorrect, there can be an error at
activation of Mesh module: <em>"fatal parsing error: error
triggered by consumer in line ..."</em>
<br>
<center>
\image html hypo_sets.png

View File

@ -5,13 +5,18 @@
Medial Axis Projection algorithm can be used for meshing faces with
sinuous borders and having channel-like shape, for which is it
difficult to define 1D hypotheses so that generated quadrangles to be
of good shape.
of good shape. The algorithm can be also applied to faces with ring
topology, which can be viewed as a closed 'channel'. In the latter
case radial discretization of a ring can be specified by
using <em>Number of Layers</em> or <em>Distribution of Layers</em>
hypothesis.
\image html quad_from_ma_mesh.png "A mesh of a river model"
\image html quad_from_ma_mesh.png "A mesh of a river model to the left and of a ring-face to the right"
The algorithm assures good shape of quadrangles by constructing Medial
Axis between sinuous borders of the face and using it to
discretize the borders.
discretize the borders. (Shape of quadrangles can be not perfect at
locations where opposite sides of a 'channel' are far from being parallel.)
\image html quad_from_ma_medial_axis.png "Medial Axis between two blue sinuous borders"

View File

@ -441,7 +441,8 @@ void SMESH_Gen::setCurrentSubMesh(SMESH_subMesh* sm)
{
if ( sm )
_sm_current.push_back( sm );
else
else if ( !_sm_current.empty() )
_sm_current.pop_back();
}

View File

@ -5986,6 +5986,10 @@ SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet theElements[2],
ASSERT( theTrack );
SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
if ( !pSubMeshDS )
return ExtrusionAlongTrack( theElements, theTrack->GetFather(), theN1,
theHasAngles, theAngles, theLinearVariation,
theHasRefPoint, theRefPoint, theMakeGroups );
aItE = pSubMeshDS->GetElements();
while ( aItE->more() ) {

View File

@ -344,6 +344,9 @@ namespace
if ( !_edge || !seg2._edge )
return true;
if ( _edge->twin() == seg2._edge )
return true;
const TVDCell* cell1 = this->_edge->twin()->cell();
const TVDCell* cell2 = seg2. _edge->twin()->cell();
if ( cell1 == cell2 )
@ -367,8 +370,8 @@ namespace
else if ( edgeMedium1->is_primary() && edgeMedium2->is_primary() )
{
if ( edgeMedium1->twin() == edgeMedium2 &&
SMESH_MAT2d::Branch::getBndSegment( edgeMedium1 ) ==
SMESH_MAT2d::Branch::getBndSegment( edgeMedium2 ))
SMESH_MAT2d::Branch::getGeomEdge( edgeMedium1 ) ==
SMESH_MAT2d::Branch::getGeomEdge( edgeMedium2 ))
// this is an ignored MA edge between inSegment's on one EDGE forming a convex corner
return true;
}
@ -413,7 +416,7 @@ namespace
*/
//================================================================================
void bndSegsToMesh( const vector< BndSeg >& bndSegs )
void bndSegsToMesh( const vector< vector< BndSeg > >& bndSegsPerEdge )
{
#ifdef _MYDEBUG_
if ( !getenv("bndSegsToMesh")) return;
@ -431,31 +434,35 @@ namespace
text << "from salome.smesh import smeshBuilder\n";
text << "smesh = smeshBuilder.New(salome.myStudy)\n";
text << "m=smesh.Mesh()\n";
for ( size_t i = 0; i < bndSegs.size(); ++i )
for ( size_t iE = 0; iE < bndSegsPerEdge.size(); ++iE )
{
if ( !bndSegs[i]._edge )
text << "# " << i << " NULL edge\n";
else if ( !bndSegs[i]._edge->vertex0() ||
!bndSegs[i]._edge->vertex1() )
text << "# " << i << " INFINITE edge\n";
else if ( addedEdges.insert( bndSegs[i]._edge ).second &&
addedEdges.insert( bndSegs[i]._edge->twin() ).second )
const vector< BndSeg >& bndSegs = bndSegsPerEdge[ iE ];
for ( size_t i = 0; i < bndSegs.size(); ++i )
{
v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex0(), v2Node.size() + 1 )).first;
int n0 = v2n->second;
if ( n0 == v2Node.size() )
text << "n" << n0 << " = m.AddNode( "
<< bndSegs[i]._edge->vertex0()->x() / theScale[0] << ", "
<< bndSegs[i]._edge->vertex0()->y() / theScale[1] << ", 0 )\n";
if ( !bndSegs[i]._edge )
text << "# E=" << iE << " i=" << i << " NULL edge\n";
else if ( !bndSegs[i]._edge->vertex0() ||
!bndSegs[i]._edge->vertex1() )
text << "# E=" << iE << " i=" << i << " INFINITE edge\n";
else if ( addedEdges.insert( bndSegs[i]._edge ).second &&
addedEdges.insert( bndSegs[i]._edge->twin() ).second )
{
v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex0(), v2Node.size() + 1 )).first;
int n0 = v2n->second;
if ( n0 == v2Node.size() )
text << "n" << n0 << " = m.AddNode( "
<< bndSegs[i]._edge->vertex0()->x() / theScale[0] << ", "
<< bndSegs[i]._edge->vertex0()->y() / theScale[1] << ", 0 )\n";
v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex1(), v2Node.size() + 1 )).first;
int n1 = v2n->second;
if ( n1 == v2Node.size() )
text << "n" << n1 << " = m.AddNode( "
<< bndSegs[i]._edge->vertex1()->x() / theScale[0] << ", "
<< bndSegs[i]._edge->vertex1()->y() / theScale[1] << ", 0 )\n";
v2n = v2Node.insert( make_pair( bndSegs[i]._edge->vertex1(), v2Node.size() + 1 )).first;
int n1 = v2n->second;
if ( n1 == v2Node.size() )
text << "n" << n1 << " = m.AddNode( "
<< bndSegs[i]._edge->vertex1()->x() / theScale[0] << ", "
<< bndSegs[i]._edge->vertex1()->y() / theScale[1] << ", 0 )\n";
text << "e" << i << " = m.AddEdge([ n" << n0 << ", n" << n1 << " ])\n";
text << "e" << i << " = m.AddEdge([ n" << n0 << ", n" << n1 << " ])\n";
}
}
}
text << "\n";
@ -985,7 +992,7 @@ namespace
bndSegs[0].setIndexToEdge( 0 );
}
//bndSegsToMesh( bndSegsPerEdge ); // debug: visually check found MA edges
bndSegsToMesh( bndSegsPerEdge ); // debug: visually check found MA edges
// Find TVDEdge's of Branches and associate them with bndSegs
@ -1374,6 +1381,15 @@ bool SMESH_MAT2d::Boundary::getBranchPoint( const std::size_t iEdge,
while ( points._params[i+1] < u ) ++i;
}
if ( points._params[i] == points._params[i+1] ) // coincident points at some end
{
int di = ( points._params[0] == points._params[i] ) ? +1 : -1;
while ( points._params[i] == points._params[i+1] )
i += di;
if ( i < 0 || i+1 >= points._params.size() )
i = 0;
}
double edgeParam = ( u - points._params[i] ) / ( points._params[i+1] - points._params[i] );
if ( !points._maEdges[ i ].second ) // no branch at the EDGE end, look for a closest branch

View File

@ -947,7 +947,8 @@ std::string SMESH_GroupOnFilter_i::FilterToString() const
{
SMESH::Filter::Criterion& crit = criteria[ i ];
if ( SMESH::FunctorType( crit.Type ) == SMESH::FT_BelongToMeshGroup )
if ( SMESH::FunctorType( crit.Type ) == SMESH::FT_BelongToMeshGroup &&
crit.ThresholdID.in() && crit.ThresholdID.in()[0] )
{
CORBA::Object_var obj = SMESH_Gen_i::GetORB()->string_to_object( crit.ThresholdID );
if ( SMESH_GroupBase_i * g = SMESH::DownCast< SMESH_GroupBase_i*>( obj ))

View File

@ -2844,7 +2844,7 @@ SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & the
if ( !aMeshImp ) return aGroups._retn();
TopoDS_Shape aShape = SMESH_Gen_i::GetSMESHGen()->GeomObjectToShape( thePathShape );
aSubMesh = aMeshImp->GetImpl().GetSubMesh( aShape );
if ( !aSubMesh || !aSubMesh->GetSubMeshDS() )
if ( !aSubMesh /*|| !aSubMesh->GetSubMeshDS()*/ )
return aGroups._retn();
}

View File

@ -1100,8 +1100,7 @@ class StdMeshersBuilder_Prism3D(Mesh_Algorithm):
pass # end of StdMeshersBuilder_Prism3D class
## Defines a Prism 3D algorithm, which is either "Extrusion 3D" or "Radial Prism"
# depending on geometry
## Defines a Prism 3D algorithm
#
# It is created by calling smeshBuilder.Mesh.Prism(geom=0)
#
@ -1133,30 +1132,12 @@ class StdMeshersBuilder_RadialPrism3D(StdMeshersBuilder_Prism3D):
self.nbLayers = None
return
## Defines a Radial Quadrangle 1D-2D algorithm
## Base class for algorithms supporting radial distribution hypotheses
#
# It is created by calling smeshBuilder.Mesh.Quadrangle(smeshBuilder.RADIAL_QUAD,geom=0)
#
# @ingroup l2_algos_radialq
class StdMeshersBuilder_RadialQuadrangle1D2D(Mesh_Algorithm):
class StdMeshersBuilder_RadialAlgorithm(Mesh_Algorithm):
## name of the dynamic method in smeshBuilder.Mesh class
# @internal
meshMethod = "Quadrangle"
## type of algorithm used with helper function in smeshBuilder.Mesh class
# @internal
algoType = RADIAL_QUAD
## doc string of the method
# @internal
docHelper = "Creates quadrangle 1D-2D algorithm for faces having a shape of disk or a disk segment"
## Private constructor.
# @param mesh parent mesh object algorithm is assigned to
# @param geom geometry (shape/sub-shape) algorithm is assigned to;
# if it is @c 0 (default), the algorithm is assigned to the main shape
def __init__(self, mesh, geom=0):
def __init__(self):
Mesh_Algorithm.__init__(self)
self.Create(mesh, geom, self.algoType)
self.distribHyp = None #self.Hypothesis("LayerDistribution2D", UseExisting=0)
self.nbLayers = None
@ -1259,12 +1240,42 @@ class StdMeshersBuilder_RadialQuadrangle1D2D(Mesh_Algorithm):
pass # end of StdMeshersBuilder_RadialQuadrangle1D2D class
## Defines a Radial Quadrangle 1D-2D algorithm
#
# It is created by calling smeshBuilder.Mesh.Quadrangle(smeshBuilder.RADIAL_QUAD,geom=0)
#
# @ingroup l2_algos_radialq
class StdMeshersBuilder_RadialQuadrangle1D2D(StdMeshersBuilder_RadialAlgorithm):
## name of the dynamic method in smeshBuilder.Mesh class
# @internal
meshMethod = "Quadrangle"
## type of algorithm used with helper function in smeshBuilder.Mesh class
# @internal
algoType = RADIAL_QUAD
## doc string of the method
# @internal
docHelper = "Creates quadrangle 1D-2D algorithm for faces having a shape of disk or a disk segment"
## Private constructor.
# @param mesh parent mesh object algorithm is assigned to
# @param geom geometry (shape/sub-shape) algorithm is assigned to;
# if it is @c 0 (default), the algorithm is assigned to the main shape
def __init__(self, mesh, geom=0):
StdMeshersBuilder_RadialAlgorithm.__init__(self)
self.Create(mesh, geom, self.algoType)
self.distribHyp = None #self.Hypothesis("LayerDistribution2D", UseExisting=0)
self.nbLayers = None
pass
## Defines a Quadrangle (Medial Axis Projection) 1D-2D algorithm
#
# It is created by calling smeshBuilder.Mesh.Quadrangle(smeshBuilder.QUAD_MA_PROJ,geom=0)
#
# @ingroup l2_algos_quad_ma
class StdMeshersBuilder_QuadMA_1D2D(Mesh_Algorithm):
class StdMeshersBuilder_QuadMA_1D2D(StdMeshersBuilder_RadialAlgorithm):
## name of the dynamic method in smeshBuilder.Mesh class
# @internal
@ -1281,7 +1292,7 @@ class StdMeshersBuilder_QuadMA_1D2D(Mesh_Algorithm):
# @param geom geometry (shape/sub-shape) algorithm is assigned to;
# if it is @c 0 (default), the algorithm is assigned to the main shape
def __init__(self, mesh, geom=0):
Mesh_Algorithm.__init__(self)
StdMeshersBuilder_RadialAlgorithm.__init__(self)
self.Create(mesh, geom, self.algoType)
pass

View File

@ -3987,6 +3987,7 @@ class Mesh:
if isinstance( RefPoint, geomBuilder.GEOM._objref_GEOM_Object):
RefPoint = self.smeshpyD.GetPointStruct(RefPoint)
if isinstance( RefPoint, list ):
if not RefPoint: RefPoint = [0,0,0]
RefPoint = SMESH.PointStruct( *RefPoint )
if isinstance( PathMesh, Mesh ):
PathMesh = PathMesh.GetMesh()
@ -4019,8 +4020,9 @@ class Mesh:
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathX(self, Base, Path, NodeStart,
HasAngles, Angles, LinearVariation,
HasRefPoint, RefPoint, MakeGroups, ElemType):
HasAngles=False, Angles=[], LinearVariation=False,
HasRefPoint=False, RefPoint=[0,0,0], MakeGroups=False,
ElemType=SMESH.FACE):
n,e,f = [],[],[]
if ElemType == SMESH.NODE: n = Base
if ElemType == SMESH.EDGE: e = Base
@ -4050,7 +4052,7 @@ class Mesh:
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPath(self, IDsOfElements, PathMesh, PathShape, NodeStart,
HasAngles, Angles, HasRefPoint, RefPoint,
HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],IDsOfElements,IDsOfElements
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape,
@ -4080,7 +4082,7 @@ class Mesh:
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathObject(self, theObject, PathMesh, PathShape, NodeStart,
HasAngles, Angles, HasRefPoint, RefPoint,
HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],theObject,theObject
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart,
@ -4109,7 +4111,7 @@ class Mesh:
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathObject1D(self, theObject, PathMesh, PathShape, NodeStart,
HasAngles, Angles, HasRefPoint, RefPoint,
HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],theObject,[]
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart,
@ -4138,7 +4140,7 @@ class Mesh:
# only SMESH::Extrusion_Error otherwise
# @ingroup l2_modif_extrurev
def ExtrusionAlongPathObject2D(self, theObject, PathMesh, PathShape, NodeStart,
HasAngles, Angles, HasRefPoint, RefPoint,
HasAngles=False, Angles=[], HasRefPoint=False, RefPoint=[],
MakeGroups=False, LinearVariation=False):
n,e,f = [],[],theObject
gr,er = self.ExtrusionAlongPathObjects(n,e,f, PathMesh, PathShape, NodeStart,

View File

@ -85,6 +85,7 @@ class Mesh_Algorithm:
attr = hypo_so_i.FindAttribute("AttributeIOR")[1]
if attr is not None:
anIOR = attr.Value()
if not anIOR: continue # prevent exception in orb.string_to_object()
hypo_o_i = salome.orb.string_to_object(anIOR)
if hypo_o_i is not None:
# Check if this is a hypothesis
@ -128,6 +129,7 @@ class Mesh_Algorithm:
attr = algo_so_i.FindAttribute("AttributeIOR")[1]
if attr is not None:
anIOR = attr.Value()
if not anIOR: continue # prevent exception in orb.string_to_object()
algo_o_i = salome.orb.string_to_object(anIOR)
if algo_o_i is not None:
# Check if this is an algorithm

View File

@ -1039,7 +1039,7 @@ namespace
const vector< Handle(Geom_Curve) >& theCurves = theSinuFace._sinuCurves;
double uMA;
SMESH_MAT2d::BoundaryPoint bp[2];
SMESH_MAT2d::BoundaryPoint bp[2]; // 2 sinuous sides
const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0);
{
// add to thePointsOnE NodePoint's of ends of theSinuEdges
@ -1138,7 +1138,7 @@ namespace
// projection is set to the BoundaryPoint of this projection
// evaluate distance to neighbor projections
const double rShort = 0.2;
const double rShort = 0.33;
bool isShortPrev[2], isShortNext[2], isPrevCloser[2];
TMAPar2NPoints::iterator u2NPPrev = u2NP, u2NPNext = u2NP;
--u2NPPrev; ++u2NPNext;
@ -1306,8 +1306,8 @@ namespace
TIterator u2NPprev = sameU2NP.front();
TIterator u2NPnext = sameU2NP.back() ;
if ( u2NPprev->first > 0. ) --u2NPprev;
if ( u2NPnext->first < 1. ) ++u2NPprev;
if ( u2NPprev->first < 0. ) ++u2NPprev;
if ( u2NPnext->first > 1. ) --u2NPnext;
set< int >::iterator edgeID = edgeInds.begin();
for ( ; edgeID != edgeInds.end(); ++edgeID )
@ -1322,8 +1322,8 @@ namespace
if ( u0 == u1 )
{
if ( np->_node ) --u2NPprev;
else ++u2NPnext;
if ( u2NPprev != thePointsOnE.begin() ) --u2NPprev;
if ( u2NPnext != --thePointsOnE.end() ) ++u2NPnext;
np = &get( u2NPprev->second, iSide );
u0 = getUOnEdgeByPoint( *edgeID, np, theSinuFace );
np = &get( u2NPnext->second, iSide );
@ -1331,7 +1331,7 @@ namespace
}
// distribute points and create nodes
double du = ( u1 - u0 ) / ( sameU2NP.size() + !existingNode );
double du = ( u1 - u0 ) / ( sameU2NP.size() + 1 /*!existingNode*/ );
double u = u0 + du;
for ( size_t i = 0; i < sameU2NP.size(); ++i )
{
@ -1503,8 +1503,8 @@ namespace
theFace._quad->side[ 1 ] = StdMeshers_FaceSide::New( uvsNew );
}
if ( theFace._quad->side[ 1 ].NbPoints() !=
theFace._quad->side[ 3 ].NbPoints())
if ( theFace._quad->side[ 1 ].GetUVPtStruct().empty() ||
theFace._quad->side[ 3 ].GetUVPtStruct().empty() )
return false;
} // if ( theFace.IsRing() )
@ -1553,6 +1553,7 @@ namespace
vector< int > edgeIDs ( theSinuEdges.size() ); // IDs in the main shape
vector< bool > isComputed( theSinuEdges.size() );
curves.resize( theSinuEdges.size(), 0 );
bool allComputed = true;
for ( size_t i = 0; i < theSinuEdges.size(); ++i )
{
curves[i] = BRep_Tool::Curve( theSinuEdges[i], f,l );
@ -1561,6 +1562,8 @@ namespace
SMESH_subMesh* sm = mesh->GetSubMesh( theSinuEdges[i] );
edgeIDs [i] = sm->GetId();
isComputed[i] = ( !sm->IsEmpty() );
if ( !isComputed[i] )
allComputed = false;
}
const SMESH_MAT2d::Branch& branch = *theMA.getBranch(0);
@ -1568,7 +1571,9 @@ namespace
vector< std::size_t > edgeIDs1, edgeIDs2; // indices in theSinuEdges
vector< SMESH_MAT2d::BranchPoint > divPoints;
branch.getOppositeGeomEdges( edgeIDs1, edgeIDs2, divPoints );
if ( !allComputed )
branch.getOppositeGeomEdges( edgeIDs1, edgeIDs2, divPoints );
for ( size_t i = 0; i < edgeIDs1.size(); ++i )
if ( isComputed[ edgeIDs1[i]] &&
isComputed[ edgeIDs2[i]] )
@ -1587,15 +1592,20 @@ namespace
return false;
}
// map param on MA to parameters of nodes on a pair of theSinuEdges
// map (param on MA) to (parameters of nodes on a pair of theSinuEdges)
TMAPar2NPoints pointsOnE;
vector<double> maParams;
set<int> projectedEdges; // treated EDGEs which 'isComputed'
// compute params of nodes on EDGEs by projecting division points from MA
for ( size_t iEdgePair = 0; iEdgePair < edgeIDs1.size(); ++iEdgePair )
// loop on pairs of opposite EDGEs
{
if ( projectedEdges.count( edgeIDs1[ iEdgePair ]) ||
projectedEdges.count( edgeIDs2[ iEdgePair ]) )
continue;
// --------------------------------------------------------------------------------
if ( isComputed[ edgeIDs1[ iEdgePair ]] != // one EDGE is meshed
isComputed[ edgeIDs2[ iEdgePair ]])
@ -1610,6 +1620,8 @@ namespace
if ( !SMESH_Algo::GetSortedNodesOnEdge( meshDS, theSinuEdges[ iEdgeComputed ], /*skipMedium=*/true, nodeParams ))
return false;
projectedEdges.insert( iEdgeComputed );
SMESH_MAT2d::BoundaryPoint& bndPnt = bp[ 1-iSideComputed ];
SMESH_MAT2d::BranchPoint brp;
NodePoint npN, npB; // NodePoint's initialized by node and BoundaryPoint
@ -1618,10 +1630,10 @@ namespace
double maParam1st, maParamLast, maParam;
if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, nodeParams.begin()->first, brp ))
return false;
return false;
branch.getParameter( brp, maParam1st );
if ( !theMA.getBoundary().getBranchPoint( iEdgeComputed, nodeParams.rbegin()->first, brp ))
return false;
return false;
branch.getParameter( brp, maParamLast );
map< double, const SMDS_MeshNode* >::iterator u2n = nodeParams.begin(), u2nEnd = nodeParams.end();
@ -1641,28 +1653,6 @@ namespace
npB = NodePoint( bndPnt );
pos = pointsOnE.insert( hint, make_pair( maParam, make_pair( np0, np1 )));
}
// move iEdgePair forward;
// find divPoints most close to max MA param
if ( edgeIDs1.size() > 1 )
{
maParamLast = pointsOnE.rbegin()->first;
int iClosest;
double minDist = 1.;
for ( ; iEdgePair < edgeIDs1.size()-1; ++iEdgePair )
{
branch.getParameter( divPoints[iEdgePair], maParam );
double d = Abs( maParamLast - maParam );
if ( d < minDist )
minDist = d, iClosest = iEdgePair;
else
break;
}
if ( Abs( maParamLast - 1. ) < minDist )
break; // the last pair treated
else
iEdgePair = iClosest;
}
}
// --------------------------------------------------------------------------------
else if ( !isComputed[ edgeIDs1[ iEdgePair ]] && // none of EDGEs is meshed