0020855: [CEA] Problem with ijk algo

* Fix detection of block corners
  * Fix selection of sides
This commit is contained in:
eap 2010-05-19 08:13:54 +00:00
parent 7d30d8ec9f
commit 283c73d9d5

View File

@ -84,9 +84,42 @@ namespace
return true;
}
//================================================================================
/*!
* \brief Description of node used to detect corner nodes
*/
struct _NodeDescriptor
{
int nbInverseFaces, nbNodesInInverseFaces;
_NodeDescriptor(const SMDS_MeshNode* n): nbInverseFaces(0), nbNodesInInverseFaces(0)
{
if ( n )
{
set<const SMDS_MeshNode*> nodes;
SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face );
while ( fIt->more() )
{
const SMDS_MeshElement* face = fIt->next();
nodes.insert( face->begin_nodes(), face->end_nodes() );
nbInverseFaces++;
}
nbNodesInInverseFaces = nodes.size();
}
}
bool operator==(const _NodeDescriptor& other) const
{
return
nbInverseFaces == other.nbInverseFaces &&
nbNodesInInverseFaces == other.nbNodesInInverseFaces;
}
};
//================================================================================
/*!
* \brief return true if a node is at block corner
*
* This check is valid for simple cases only
*/
//================================================================================
@ -189,15 +222,15 @@ namespace
int _nbBlocksExpected;
int _nbBlocksFound;
#ifdef _DEBUG_
#define _grid_access_(args) _grid.at( args )
#ifdef _DEBUG_ // want to get SIGSEGV in case of invalid index
#define _grid_access_(pobj, i) pobj->_grid[ ((i) < pobj->_grid.size()) ? i : int(1e100)]
#else
#define _grid_access_(args) _grid[ args ]
#define _grid_access_(pobj, i) pobj->_grid[ i ]
#endif
//!< Return node at XY
const SMDS_MeshNode* getNode(int x, int y) const { return _grid_access_( _index( x, y )); }
const SMDS_MeshNode* getNode(int x, int y) const { return _grid_access_(this, _index( x,y ));}
//!< Set node at XY
void setNode(int x, int y, const SMDS_MeshNode* n) { _grid_access_( _index( x, y )) = n; }
void setNode(int x, int y, const SMDS_MeshNode* n) { _grid_access_(this, _index( x,y )) = n; }
//!< Return an edge
SMESH_OrientedLink getEdge(EQuadEdge edge) const
{
@ -242,7 +275,7 @@ namespace
//!< return coordinates by XY
gp_XYZ xyz(int x, int y) const
{
return SMESH_MeshEditor::TNodeXYZ( _side->_grid_access_( _index( x, y )) );
return SMESH_MeshEditor::TNodeXYZ( _grid_access_(_side, _index( x, y )) );
}
//!< safely return a node by XY
const SMDS_MeshNode* node(int x, int y) const
@ -259,7 +292,7 @@ namespace
//!< Return a corner node
const SMDS_MeshNode* cornerNode(bool isXMax, bool isYMax) const
{
return _side->_grid_access_( _index.corner( isXMax, isYMax ));
return _grid_access_(_side, _index.corner( isXMax, isYMax ));
}
//!< return its size in nodes
int getHoriSize() const { return _index.xSize(); }
@ -300,7 +333,9 @@ namespace
const SMESH_Comment& error() const { return _error; }
private:
bool fillSide( _BlockSide& side, const SMDS_MeshElement* cornerQuad);
bool fillSide( _BlockSide& side,
const SMDS_MeshElement* cornerQuad,
const SMDS_MeshNode* cornerNode);
bool fillRowsUntilCorner(const SMDS_MeshElement* quad,
const SMDS_MeshNode* n1,
const SMDS_MeshNode* n2,
@ -383,7 +418,7 @@ namespace
_allSides.push_back( _BlockSide() );
_BlockSide& side = _allSides.back();
if ( !fillSide( side, face ) )
if ( !fillSide( side, face, *corner ) )
{
if ( !_error.empty() )
return false;
@ -394,9 +429,6 @@ namespace
for ( int isYMax = 0; isYMax < 2; ++isYMax )
{
const SMDS_MeshNode* nCorner = side.getCornerNode(isXMax,isYMax );
if ( !isCornerNode( nCorner ))
return BAD_MESH_ERR;
//_corner2sides[ nCorner ].insert( &side );
corners.push_back( nCorner );
cornerFaces.insert( side.getCornerFace( nCorner ));
}
@ -425,6 +457,7 @@ namespace
return BAD_MESH_ERR;
if ( _allSides.back()._grid.empty() )
_allSides.pop_back();
_DUMP_("Nb detected sides "<< _allSides.size());
// ---------------------------
// Organize sides into blocks
@ -466,6 +499,8 @@ namespace
// edges of neighbour sides of B_FRONT corresponding to front's edges
EQuadEdge edgeOfFront[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT };
EQuadEdge edgeToFind [4] = { Q_BOTTOM, Q_LEFT, Q_BOTTOM, Q_LEFT };
// TODO: first find all sides where no choice of sides is needed,
// then perform search with selection, which is then easier
for ( int i = Q_BOTTOM; ok && i <= Q_LEFT; ++i )
ok = ( block._side[i] = findBlockSide( B_FRONT, edgeOfFront[i], edgeToFind[i]));
if ( ok )
@ -484,6 +519,24 @@ namespace
}
ok = !isSame;
}
if ( ok )
{
// check block validity
int x = block._side[B_BOTTOM].getHoriSize();
ok = ( block._side[B_TOP ].getHoriSize() == x &&
block._side[B_FRONT ].getHoriSize() == x &&
block._side[B_BACK ].getHoriSize() == x );
int y = block._side[B_BOTTOM].getVertSize();
ok = ( ok &&
block._side[B_TOP ].getVertSize() == y &&
block._side[B_LEFT ].getHoriSize() == y &&
block._side[B_RIGHT ].getHoriSize() == y);
int z = block._side[B_FRONT].getVertSize();
ok = ( ok &&
block._side[B_BACK ].getVertSize() == z &&
block._side[B_LEFT ].getVertSize() == z &&
block._side[B_RIGHT ].getVertSize() == z);
}
// count the found sides
_DUMP_(endl);
@ -525,7 +578,9 @@ namespace
*/
//================================================================================
bool _Skin::fillSide( _BlockSide& side, const SMDS_MeshElement* cornerQuad)
bool _Skin::fillSide( _BlockSide& side,
const SMDS_MeshElement* cornerQuad,
const SMDS_MeshNode* nCorner)
{
// Find out size of block side mesured in nodes and by the way find two rows
// of nodes in two directions.
@ -533,13 +588,6 @@ namespace
int x, y, nbX, nbY;
const SMDS_MeshElement* firstQuad = cornerQuad;
{
// get corner node of cornerQuad
const SMDS_MeshNode* nCorner = 0;
for ( int i = 0; i < 4 && !nCorner; ++i )
if ( isCornerNode( firstQuad->GetNode(i)))
nCorner = firstQuad->GetNode(i);
if ( !nCorner ) return false;
// get a node on block edge
int iCorner = firstQuad->GetNodeIndex( nCorner );
const SMDS_MeshNode* nOnEdge = firstQuad->GetNode( (iCorner+1) % 4);
@ -611,7 +659,14 @@ namespace
}
}
return true;
// check side validity
bool ok =
side.getCornerFace( side.getCornerNode( 0, 0 )) &&
side.getCornerFace( side.getCornerNode( 1, 0 )) &&
side.getCornerFace( side.getCornerNode( 0, 1 )) &&
side.getCornerFace( side.getCornerNode( 1, 1 ));
return ok;
}
//================================================================================
@ -658,46 +713,82 @@ namespace
}
else
{
// Select one of found sides most close to startBlockSide
// gravity center of already loaded block sides
gp_XYZ gc(0,0,0);
for (int i = 0; i < B_UNDEFINED; ++i )
if ( block._side[ i ] )
gc += block._side[ i ]._side->getGC();
gc /= nbLoadedSides;
gp_XYZ p1 ( n1->X(),n1->Y(),n1->Z()), p2 (n2->X(),n2->Y(),n2->Z());
gp_Vec p1p2( p1, p2 );
const SMDS_MeshElement* face1 = side1->getCornerFace( n1 );
gp_XYZ p1Op = SMESH_MeshEditor::TNodeXYZ( oppositeNode( face1, face1->GetNodeIndex(n1)));
gp_Vec side1Dir( p1, p1Op );
gp_Ax2 pln( p1, p1p2, side1Dir ); // plane with normal p1p2 and X dir side1Dir
_DUMP_(" Select adjacent for "<< side1._side << " - side dir ("
<< side1Dir.X() << ", " << side1Dir.Y() << ", " << side1Dir.Z() << ")" );
map < double , _BlockSide* > angleOfSide;
set< _BlockSide* >::iterator sideIt = sidesOnEdge.begin();
for (; sideIt != sidesOnEdge.end(); ++sideIt )
gp_XYZ gc(0,0,0); // gravity center of already loaded block sides
if ( nbLoadedSides > 1 )
{
_BlockSide* sideI = *sideIt;
const SMDS_MeshElement* faceI = sideI->getCornerFace( n1 );
gp_XYZ p1Op = SMESH_MeshEditor::TNodeXYZ( oppositeNode( faceI, faceI->GetNodeIndex(n1)));
gp_Vec sideIDir( p1, p1Op );
// compute angle of (sideIDir projection to pln) and (X dir of pln)
gp_Vec2d sideIDirProj( sideIDir * pln.XDirection(), sideIDir * pln.YDirection());
double angle = sideIDirProj.Angle( gp::DX2d() );
if ( angle < 0 ) angle += 2 * PI;
angleOfSide.insert( make_pair( angle, sideI ));
_DUMP_(" "<< sideI << " - side dir ("
<< sideIDir.X() << ", " << sideIDir.Y() << ", " << sideIDir.Z() << ")"
<< " angle " << angle);
// Find the side having more than 2 corners common with already loaded sides
set<const SMDS_MeshNode*> loadedCorners;
for (int i = 0; i < B_UNDEFINED; ++i )
if ( block._side[ i ] )
{
loadedCorners.insert( block._side[ i ]->getCornerNode(0,0));
loadedCorners.insert( block._side[ i ]->getCornerNode(1,0));
loadedCorners.insert( block._side[ i ]->getCornerNode(0,1));
loadedCorners.insert( block._side[ i ]->getCornerNode(1,1));
gc += block._side[ i ]._side->getGC();
}
gc /= nbLoadedSides;
for (; !foundSide && sideIt != sidesOnEdge.end(); ++sideIt )
{
_BlockSide* sideI = *sideIt;
int nbCommonCorners =
loadedCorners.count( sideI->getCornerNode(0,0)) +
loadedCorners.count( sideI->getCornerNode(1,0)) +
loadedCorners.count( sideI->getCornerNode(0,1)) +
loadedCorners.count( sideI->getCornerNode(1,1));
if ( nbCommonCorners > 2 )
foundSide = sideI;
}
}
if ( !foundSide )
{
// Select one of found sides most close to startBlockSide
gp_XYZ p1 ( n1->X(),n1->Y(),n1->Z()), p2 (n2->X(),n2->Y(),n2->Z());
gp_Vec p1p2( p1, p2 );
const SMDS_MeshElement* face1 = side1->getCornerFace( n1 );
gp_XYZ p1Op = SMESH_MeshEditor::TNodeXYZ( oppositeNode( face1, face1->GetNodeIndex(n1)));
gp_Vec side1Dir( p1, p1Op );
gp_Ax2 pln( p1, p1p2, side1Dir ); // plane with normal p1p2 and X dir side1Dir
_DUMP_(" Select adjacent for "<< side1._side << " - side dir ("
<< side1Dir.X() << ", " << side1Dir.Y() << ", " << side1Dir.Z() << ")" );
map < double , _BlockSide* > angleOfSide;
for (sidesOnEdge.begin(); sideIt != sidesOnEdge.end(); ++sideIt )
{
_BlockSide* sideI = *sideIt;
const SMDS_MeshElement* faceI = sideI->getCornerFace( n1 );
gp_XYZ p1Op = SMESH_MeshEditor::TNodeXYZ( oppositeNode( faceI, faceI->GetNodeIndex(n1)));
gp_Vec sideIDir( p1, p1Op );
// compute angle of (sideIDir projection to pln) and (X dir of pln)
gp_Vec2d sideIDirProj( sideIDir * pln.XDirection(), sideIDir * pln.YDirection());
double angle = sideIDirProj.Angle( gp::DX2d() );
if ( angle < 0 ) angle += 2 * PI; // angle [0-2*PI]
angleOfSide.insert( make_pair( angle, sideI ));
_DUMP_(" "<< sideI << " - side dir ("
<< sideIDir.X() << ", " << sideIDir.Y() << ", " << sideIDir.Z() << ")"
<< " angle " << angle);
}
if ( nbLoadedSides == 1 )
{
double angF = angleOfSide.begin()->first, angL = angleOfSide.rbegin()->first;
if ( angF > PI ) angF = 2*PI - angF;
if ( angL > PI ) angL = 2*PI - angL;
foundSide = angF < angL ? angleOfSide.begin()->second : angleOfSide.rbegin()->second;
}
else
{
gp_Vec gcDir( p1, gc );
gp_Vec2d gcDirProj( gcDir * pln.XDirection(), gcDir * pln.YDirection());
double gcAngle = gcDirProj.Angle( gp::DX2d() );
foundSide = gcAngle < 0 ? angleOfSide.rbegin()->second : angleOfSide.begin()->second;
}
}
gp_Vec gcDir( p1, gc );
gp_Vec2d gcDirProj( gcDir * pln.XDirection(), gcDir * pln.YDirection());
double gcAngle = gcDirProj.Angle( gp::DX2d() );
foundSide = gcAngle < 0 ? angleOfSide.rbegin()->second : angleOfSide.begin()->second;
_DUMP_(" selected "<< foundSide );
}
@ -759,9 +850,14 @@ namespace
row2.push_back( n1 = oppositeNode( quad, i1 ));
}
_NodeDescriptor nDesc( row1[1] );
if ( nDesc == _NodeDescriptor( row1[0] ))
return true; // row of 2 nodes
// Find the rest nodes
TIDSortedElemSet emptySet, avoidSet;
while ( !isCornerNode( n2 ))
//while ( !isCornerNode( n2 ))
while ( nDesc == _NodeDescriptor( n2 ))
{
avoidSet.clear(); avoidSet.insert( quad );
quad = SMESH_MeshEditor::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2 );