52568: Quadrangle (Mapping) differently meshes equal L-shaped faces.

Take into account number of segments when selecting corners among multiple vertices
This commit is contained in:
eap 2014-11-06 20:11:51 +03:00
parent e9c9effdfa
commit 36f660ae42

View File

@ -4280,16 +4280,17 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace,
vMap.Add( (*a2v).second ); vMap.Add( (*a2v).second );
// check if there are possible variations in choosing corners // check if there are possible variations in choosing corners
bool isThereVariants = false; bool haveVariants = false;
if ( vertexByAngle.size() > nbCorners ) if ( vertexByAngle.size() > nbCorners )
{ {
double lostAngle = a2v->first; double lostAngle = a2v->first;
double lastAngle = ( --a2v, a2v->first ); double lastAngle = ( --a2v, a2v->first );
isThereVariants = ( lostAngle * 1.1 >= lastAngle ); haveVariants = ( lostAngle * 1.1 >= lastAngle );
} }
const double angleTol = 5.* M_PI/180;
myCheckOri = ( vertexByAngle.size() > nbCorners || myCheckOri = ( vertexByAngle.size() > nbCorners ||
vertexByAngle.begin()->first < 5.* M_PI/180 ); vertexByAngle.begin()->first < angleTol );
// make theWire begin from a corner vertex or triaVertex // make theWire begin from a corner vertex or triaVertex
if ( nbCorners == 3 ) if ( nbCorners == 3 )
@ -4306,9 +4307,10 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace,
vector< double > angles; vector< double > angles;
vector< TopoDS_Edge > edgeVec; vector< TopoDS_Edge > edgeVec;
vector< int > cornerInd, nbSeg; vector< int > cornerInd, nbSeg;
angles.reserve( vertexByAngle.size() ); int nbSegTot = 0;
angles .reserve( vertexByAngle.size() );
edgeVec.reserve( vertexByAngle.size() ); edgeVec.reserve( vertexByAngle.size() );
nbSeg.reserve( vertexByAngle.size() ); nbSeg .reserve( vertexByAngle.size() );
cornerInd.reserve( nbCorners ); cornerInd.reserve( nbCorners );
for ( edge = theWire.begin(); edge != theWire.end(); ++edge ) for ( edge = theWire.begin(); edge != theWire.end(); ++edge )
{ {
@ -4321,105 +4323,219 @@ int StdMeshers_Quadrangle_2D::getCorners(const TopoDS_Face& theFace,
theVertices.push_back( v ); theVertices.push_back( v );
cornerInd.push_back( angles.size() ); cornerInd.push_back( angles.size() );
} }
angles.push_back( angleByVertex.IsBound( v ) ? angleByVertex( v ) : -M_PI ); angles .push_back( angleByVertex.IsBound( v ) ? angleByVertex( v ) : -M_PI );
edgeVec.push_back( *edge ); edgeVec.push_back( *edge );
if ( theConsiderMesh && isThereVariants ) if ( theConsiderMesh && haveVariants )
{ {
if ( SMESHDS_SubMesh* sm = helper.GetMeshDS()->MeshElements( *edge )) if ( SMESHDS_SubMesh* sm = helper.GetMeshDS()->MeshElements( *edge ))
nbSeg.push_back( sm->NbNodes() + 1 ); nbSeg.push_back( sm->NbNodes() + 1 );
else else
nbSeg.push_back( 0 ); nbSeg.push_back( 0 );
nbSegTot += nbSeg.back();
} }
} }
// refine the result vector - make sides elual by length if // refine the result vector - make sides equal by length if
// there are several equal angles // there are several equal angles
if ( isThereVariants ) if ( haveVariants )
{ {
if ( nbCorners == 3 ) if ( nbCorners == 3 )
angles[0] = 2 * M_PI; // not to move the base triangle VERTEX angles[0] = 2 * M_PI; // not to move the base triangle VERTEX
set< int > refinedCorners; // here we refer to VERTEX'es and EDGEs by indices in angles and edgeVec vectors
typedef int TGeoIndex;
// for each vertex find a vertex till which there are nbSegHalf segments
const int nbSegHalf = ( nbSegTot % 2 || nbCorners == 3 ) ? 0 : nbSegTot / 2;
vector< TGeoIndex > halfDivider( angles.size(), -1 );
int nbHalfDividers = 0;
if ( nbSegHalf )
{
// get min angle of corners
double minAngle = 10.;
for ( size_t iC = 0; iC < cornerInd.size(); ++iC )
minAngle = Min( minAngle, angles[ cornerInd[ iC ]]);
// find halfDivider's
for ( TGeoIndex iV1 = 0; iV1 < TGeoIndex( angles.size() ); ++iV1 )
{
int nbSegs = 0;
TGeoIndex iV2 = iV1;
do {
nbSegs += nbSeg[ iV2 ];
iV2 = helper.WrapIndex( iV2 + 1, nbSeg.size() );
} while ( nbSegs < nbSegHalf );
if ( nbSegs == nbSegHalf &&
angles[ iV1 ] + angleTol >= minAngle &&
angles[ iV2 ] + angleTol >= minAngle )
{
halfDivider[ iV1 ] = iV2;
++nbHalfDividers;
}
}
}
set< TGeoIndex > refinedCorners, treatedCorners;
for ( size_t iC = 0; iC < cornerInd.size(); ++iC ) for ( size_t iC = 0; iC < cornerInd.size(); ++iC )
{ {
int iV = cornerInd[iC]; TGeoIndex iV = cornerInd[iC];
if ( !refinedCorners.insert( iV ).second ) if ( !treatedCorners.insert( iV ).second )
continue; continue;
list< int > equalVertices; list< TGeoIndex > equVerts; // inds of vertices that can become corners
equalVertices.push_back( iV ); equVerts.push_back( iV );
int nbC[2] = { 0, 0 }; int nbC[2] = { 0, 0 };
// find equal angles backward and forward from the iV-th corner vertex // find equal angles backward and forward from the iV-th corner vertex
for ( int isFwd = 0; isFwd < 2; ++isFwd ) for ( int isFwd = 0; isFwd < 2; ++isFwd )
{ {
int dV = isFwd ? +1 : -1; int dV = isFwd ? +1 : -1;
int iCNext = helper.WrapIndex( iC + dV, cornerInd.size() ); int iCNext = helper.WrapIndex( iC + dV, cornerInd.size() );
int iVNext = helper.WrapIndex( iV + dV, angles.size() ); TGeoIndex iVNext = helper.WrapIndex( iV + dV, angles.size() );
while ( iVNext != iV ) while ( iVNext != iV )
{ {
bool equal = Abs( angles[iV] - angles[iVNext] ) < 0.1 * angles[iV]; bool equal = Abs( angles[iV] - angles[iVNext] ) < angleTol;
if ( equal ) if ( equal )
equalVertices.insert( isFwd ? equalVertices.end() : equalVertices.begin(), iVNext ); equVerts.insert( isFwd ? equVerts.end() : equVerts.begin(), iVNext );
if ( iVNext == cornerInd[ iCNext ]) if ( iVNext == cornerInd[ iCNext ])
{ {
if ( !equal ) if ( !equal )
{
if ( angles[iV] < angles[iVNext] )
refinedCorners.insert( iVNext );
break; break;
}
nbC[ isFwd ]++; nbC[ isFwd ]++;
refinedCorners.insert( cornerInd[ iCNext ] ); treatedCorners.insert( cornerInd[ iCNext ] );
iCNext = helper.WrapIndex( iCNext + dV, cornerInd.size() ); iCNext = helper.WrapIndex( iCNext + dV, cornerInd.size() );
} }
iVNext = helper.WrapIndex( iVNext + dV, angles.size() ); iVNext = helper.WrapIndex( iVNext + dV, angles.size() );
} }
if ( iVNext == iV )
break; // all angles equal
} }
// move corners to make sides equal by length
int nbEqualV = equalVertices.size(); const bool allCornersSame = ( nbC[0] == 3 );
int nbExcessV = nbEqualV - ( 1 + nbC[0] + nbC[1] ); if ( allCornersSame && nbHalfDividers > 0 )
if ( nbExcessV > 0 )
{ {
// calculate normalized length of each side enclosed between neighbor equalVertices // select two halfDivider's as corners
vector< double > curLengths; TGeoIndex hd1, hd2 = -1;
double totalLen = 0; int iC2;
vector< int > evVec( equalVertices.begin(), equalVertices.end() ); for ( iC2 = 0; iC2 < cornerInd.size() && hd2 < 0; ++iC2 )
int iEV = 0;
int iE = cornerInd[ helper.WrapIndex( iC - nbC[0] - 1, cornerInd.size() )];
int iEEnd = cornerInd[ helper.WrapIndex( iC + nbC[1] + 1, cornerInd.size() )];
while ( curLengths.size() < nbEqualV + 1 )
{ {
curLengths.push_back( totalLen ); hd1 = cornerInd[ iC2 ];
do { hd2 = halfDivider[ hd1 ];
curLengths.back() += SMESH_Algo::EdgeLength( edgeVec[ iE ]); if ( std::find( equVerts.begin(), equVerts.end(), hd2 ) == equVerts.end() )
iE = helper.WrapIndex( iE + 1, edgeVec.size()); hd2 = -1; // hd2-th vertex can't become a corner
if ( iEV < evVec.size() && iE == evVec[ iEV++ ] ) else
break; break;
} }
while( iE != iEEnd ); if ( hd2 >= 0 )
totalLen = curLengths.back(); {
} angles[ hd1 ] = 2 * M_PI; // make hd1-th vertex no more "equal"
curLengths.resize( equalVertices.size() ); angles[ hd2 ] = 2 * M_PI;
for ( size_t iS = 0; iS < curLengths.size(); ++iS ) refinedCorners.insert( hd1 );
curLengths[ iS ] /= totalLen; refinedCorners.insert( hd2 );
treatedCorners = refinedCorners;
// update cornerInd
equVerts.push_front( equVerts.back() );
equVerts.push_back( equVerts.front() );
list< TGeoIndex >::iterator hdPos =
std::find( equVerts.begin(), equVerts.end(), hd2 );
if ( hdPos == equVerts.end() ) break;
cornerInd[ helper.WrapIndex( iC2 + 0, cornerInd.size()) ] = hd1;
cornerInd[ helper.WrapIndex( iC2 + 1, cornerInd.size()) ] = *( --hdPos );
cornerInd[ helper.WrapIndex( iC2 + 2, cornerInd.size()) ] = hd2;
cornerInd[ helper.WrapIndex( iC2 + 3, cornerInd.size()) ] = *( ++hdPos, ++hdPos );
// find equalVertices most close to the ideal sub-division of all sides theVertices[ 0 ] = helper.IthVertex( 0, edgeVec[ cornerInd[0] ]);
theVertices[ 1 ] = helper.IthVertex( 0, edgeVec[ cornerInd[1] ]);
theVertices[ 2 ] = helper.IthVertex( 0, edgeVec[ cornerInd[2] ]);
theVertices[ 3 ] = helper.IthVertex( 0, edgeVec[ cornerInd[3] ]);
iC = -1;
continue;
}
}
// move corners to make sides equal by length
int nbEqualV = equVerts.size();
int nbExcessV = nbEqualV - ( 1 + nbC[0] + nbC[1] );
if ( nbExcessV > 0 ) // there is nbExcessV vertices that can become corners
{
// calculate normalized length of each "side" enclosed between neighbor equVerts
vector< double > accuLength;
double totalLen = 0;
vector< TGeoIndex > evVec( equVerts.begin(), equVerts.end() );
int iEV = 0;
TGeoIndex iE = cornerInd[ helper.WrapIndex( iC - nbC[0] - 1, cornerInd.size() )];
TGeoIndex iEEnd = cornerInd[ helper.WrapIndex( iC + nbC[1] + 1, cornerInd.size() )];
while ( accuLength.size() < nbEqualV + int( !allCornersSame ) )
{
// accumulate length of edges before iEV-th equal vertex
accuLength.push_back( totalLen );
do {
accuLength.back() += SMESH_Algo::EdgeLength( edgeVec[ iE ]);
iE = helper.WrapIndex( iE + 1, edgeVec.size());
if ( iEV < evVec.size() && iE == evVec[ iEV ] ) {
iEV++;
break; // equal vertex reached
}
}
while( iE != iEEnd );
totalLen = accuLength.back();
}
accuLength.resize( equVerts.size() );
for ( size_t iS = 0; iS < accuLength.size(); ++iS )
accuLength[ iS ] /= totalLen;
// find equVerts most close to the ideal sub-division of all sides
int iBestEV = 0; int iBestEV = 0;
int iCorner = helper.WrapIndex( iC - nbC[0], cornerInd.size() ); int iCorner = helper.WrapIndex( iC - nbC[0], cornerInd.size() );
int nbSides = 2 + nbC[0] + nbC[1]; int nbSides = Min( nbCorners, 2 + nbC[0] + nbC[1] );
for ( int iS = 1; iS < nbSides; ++iS, ++iBestEV ) for ( int iS = 1; iS < nbSides; ++iS, ++iBestEV )
{ {
double idealLen = iS / double( nbSides ); double idealLen = iS / double( nbSides );
double d, bestDist = 1.; double d, bestDist = 2.;
for ( iEV = iBestEV; iEV < curLengths.size(); ++iEV ) for ( iEV = iBestEV; iEV < accuLength.size(); ++iEV )
if (( d = Abs( idealLen - curLengths[ iEV ])) < bestDist ) {
d = Abs( idealLen - accuLength[ iEV ]);
// take into account presence of a coresponding halfDivider
const double cornerWgt = 0.5 / nbSides;
const double vertexWgt = 0.25 / nbSides;
TGeoIndex hd = halfDivider[ evVec[ iEV ]];
if ( hd < 0 )
d += vertexWgt;
else if( refinedCorners.count( hd ))
d -= cornerWgt;
else
d -= vertexWgt;
// choose vertex with the best d
if ( d < bestDist )
{ {
bestDist = d; bestDist = d;
iBestEV = iEV; iBestEV = iEV;
} }
}
if ( iBestEV > iS-1 + nbExcessV ) if ( iBestEV > iS-1 + nbExcessV )
iBestEV = iS-1 + nbExcessV; iBestEV = iS-1 + nbExcessV;
theVertices[ iCorner ] = helper.IthVertex( 0, edgeVec[ evVec[ iBestEV ]]); theVertices[ iCorner ] = helper.IthVertex( 0, edgeVec[ evVec[ iBestEV ]]);
refinedCorners.insert( evVec[ iBestEV ]);
iCorner = helper.WrapIndex( iCorner + 1, cornerInd.size() ); iCorner = helper.WrapIndex( iCorner + 1, cornerInd.size() );
} }
} // if ( nbExcessV > 0 )
else
{
refinedCorners.insert( cornerInd[ iC ]);
} }
} } // loop on cornerInd
}
// make theWire begin from the cornerInd[0]-th EDGE
while ( !theWire.front().IsSame( edgeVec[ cornerInd[0] ]))
theWire.splice( theWire.begin(), theWire, --theWire.end() );
} // if ( haveVariants )
return nbCorners; return nbCorners;
} }