2010-05-14 21:32:37 +06:00
|
|
|
// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// 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 : StdMeshers_HexaFromSkin_3D.cxx
|
|
|
|
// Created : Wed Jan 27 12:28:07 2010
|
|
|
|
// Author : Edward AGAPOV (eap)
|
|
|
|
//
|
|
|
|
#include "StdMeshers_HexaFromSkin_3D.hxx"
|
|
|
|
|
|
|
|
#include "SMDS_VolumeOfNodes.hxx"
|
|
|
|
#include "SMDS_VolumeTool.hxx"
|
|
|
|
#include "SMESH_Block.hxx"
|
|
|
|
#include "SMESH_MesherHelper.hxx"
|
|
|
|
|
|
|
|
#include <gp_Ax2.hxx>
|
|
|
|
|
|
|
|
//#include "utilities.h"
|
|
|
|
|
|
|
|
// Define error message
|
|
|
|
#ifdef _DEBUG_
|
|
|
|
#define BAD_MESH_ERR \
|
|
|
|
error(SMESH_Comment("Can't detect block-wise structure of the input 2D mesh.\n" \
|
|
|
|
__FILE__ ":" )<<__LINE__)
|
|
|
|
#else
|
|
|
|
#define BAD_MESH_ERR \
|
|
|
|
error(SMESH_Comment("Can't detect block-wise structure of the input 2D mesh"))
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Debug output
|
|
|
|
#define _DUMP_(msg) //cout << msg << endl
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
enum EBoxSides //!< sides of the block
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, NB_BLOCK_SIDES
|
2010-05-14 21:32:37 +06:00
|
|
|
};
|
|
|
|
const char* SBoxSides[] = //!< names of block sides
|
|
|
|
{
|
|
|
|
"BOTTOM", "RIGHT", "TOP", "LEFT", "FRONT", "BACK", "UNDEFINED"
|
|
|
|
};
|
|
|
|
enum EQuadEdge //!< edges of quadrangle side
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
Q_BOTTOM = 0, Q_RIGHT, Q_TOP, Q_LEFT, NB_QUAD_SIDES
|
2010-05-14 21:32:37 +06:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief return logical coordinates (i.e. min or max) of ends of edge
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool getEdgeEnds(EQuadEdge edge, bool& xMax1, bool& yMax1, bool& xMax2, bool& yMax2 )
|
|
|
|
{
|
|
|
|
xMax1=0, yMax1=0, xMax2=1, yMax2=1;
|
|
|
|
switch( edge )
|
|
|
|
{
|
|
|
|
case Q_BOTTOM: yMax2 = 0; break;
|
|
|
|
case Q_RIGHT: xMax1 = 1; break;
|
|
|
|
case Q_TOP: yMax1 = 1; break;
|
|
|
|
case Q_LEFT: xMax2 = 0; break;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2010-05-14 21:32:37 +06:00
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief return true if a node is at block corner
|
2010-06-10 15:43:07 +06:00
|
|
|
*
|
|
|
|
* This check is valid for simple cases only
|
2010-05-14 21:32:37 +06:00
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool isCornerNode( const SMDS_MeshNode* n )
|
|
|
|
{
|
|
|
|
return n && n->NbInverseElements( SMDSAbs_Face ) % 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief check element type
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool isQuadrangle(const SMDS_MeshElement* e)
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
return ( e && e->NbCornerNodes() == 4 );
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief return opposite node of a quadrangle face
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
const SMDS_MeshNode* oppositeNode(const SMDS_MeshElement* quad, int iNode)
|
|
|
|
{
|
|
|
|
return quad->GetNode( (iNode+2) % 4 );
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Convertor of a pair of integers to a sole index
|
|
|
|
*/
|
|
|
|
struct _Indexer
|
|
|
|
{
|
|
|
|
int _xSize, _ySize;
|
|
|
|
_Indexer( int xSize=0, int ySize=0 ): _xSize(xSize), _ySize(ySize) {}
|
|
|
|
int size() const { return _xSize * _ySize; }
|
|
|
|
int operator()(int x, int y) const { return y * _xSize + x; }
|
|
|
|
};
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Oriented convertor of a pair of integers to a sole index
|
|
|
|
*/
|
|
|
|
class _OrientedIndexer : public _Indexer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum OriFlags //!< types of block side orientation
|
|
|
|
{
|
|
|
|
REV_X = 1, REV_Y = 2, SWAP_XY = 4, MAX_ORI = REV_X|REV_Y|SWAP_XY
|
|
|
|
};
|
|
|
|
_OrientedIndexer( const _Indexer& indexer, const int oriFlags ):
|
|
|
|
_Indexer( indexer._xSize, indexer._ySize ),
|
|
|
|
_xSize (indexer._xSize), _ySize(indexer._ySize),
|
|
|
|
_xRevFun((oriFlags & REV_X) ? & reverse : & lazy),
|
|
|
|
_yRevFun((oriFlags & REV_Y) ? & reverse : & lazy),
|
|
|
|
_swapFun((oriFlags & SWAP_XY ) ? & swap : & lazy)
|
|
|
|
{
|
|
|
|
(*_swapFun)( _xSize, _ySize );
|
|
|
|
}
|
|
|
|
//!< Return index by XY
|
|
|
|
int operator()(int x, int y) const
|
|
|
|
{
|
|
|
|
(*_xRevFun)( x, const_cast<int&>( _xSize ));
|
|
|
|
(*_yRevFun)( y, const_cast<int&>( _ySize ));
|
|
|
|
(*_swapFun)( x, y );
|
|
|
|
return _Indexer::operator()(x,y);
|
|
|
|
}
|
|
|
|
//!< Return index for a corner
|
|
|
|
int corner(bool xMax, bool yMax) const
|
|
|
|
{
|
|
|
|
int x = xMax, y = yMax, size = 2;
|
|
|
|
(*_xRevFun)( x, size );
|
|
|
|
(*_yRevFun)( y, size );
|
|
|
|
(*_swapFun)( x, y );
|
|
|
|
return _Indexer::operator()(x ? _Indexer::_xSize-1 : 0 , y ? _Indexer::_ySize-1 : 0);
|
|
|
|
}
|
|
|
|
int xSize() const { return _xSize; }
|
|
|
|
int ySize() const { return _ySize; }
|
|
|
|
private:
|
|
|
|
_Indexer _indexer;
|
|
|
|
int _xSize, _ySize;
|
|
|
|
|
|
|
|
typedef void (*TFun)(int& x, int& y);
|
|
|
|
TFun _xRevFun, _yRevFun, _swapFun;
|
|
|
|
|
|
|
|
static void lazy(int&, int&) {}
|
|
|
|
static void reverse(int& x, int& size) { x = size - x - 1; }
|
|
|
|
static void swap(int& x, int& y) { std::swap(x,y); }
|
|
|
|
};
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Structure corresponding to the meshed side of block
|
|
|
|
*/
|
|
|
|
struct _BlockSide
|
|
|
|
{
|
|
|
|
vector<const SMDS_MeshNode*> _grid;
|
|
|
|
_Indexer _index;
|
|
|
|
int _nbBlocksExpected;
|
|
|
|
int _nbBlocksFound;
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
#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)]
|
2010-05-14 21:32:37 +06:00
|
|
|
#else
|
2010-06-10 15:43:07 +06:00
|
|
|
#define _grid_access_(pobj, i) pobj->_grid[ i ]
|
2010-05-14 21:32:37 +06:00
|
|
|
#endif
|
|
|
|
//!< Return node at XY
|
2010-06-10 15:43:07 +06:00
|
|
|
const SMDS_MeshNode* getNode(int x, int y) const { return _grid_access_(this, _index( x,y ));}
|
2010-05-14 21:32:37 +06:00
|
|
|
//!< Set node at XY
|
2010-06-10 15:43:07 +06:00
|
|
|
void setNode(int x, int y, const SMDS_MeshNode* n) { _grid_access_(this, _index( x,y )) = n; }
|
2010-05-14 21:32:37 +06:00
|
|
|
//!< Return an edge
|
|
|
|
SMESH_OrientedLink getEdge(EQuadEdge edge) const
|
|
|
|
{
|
|
|
|
bool x1, y1, x2, y2; getEdgeEnds( edge, x1, y1, x2, y2 );
|
|
|
|
return SMESH_OrientedLink( getCornerNode ( x1, y1 ), getCornerNode( x2, y2 ));
|
|
|
|
}
|
|
|
|
//!< Return a corner node
|
|
|
|
const SMDS_MeshNode* getCornerNode(bool isXMax, bool isYMax) const
|
|
|
|
{
|
|
|
|
return getNode( isXMax ? _index._xSize-1 : 0 , isYMax ? _index._ySize-1 : 0 );
|
|
|
|
}
|
|
|
|
const SMDS_MeshElement* getCornerFace(const SMDS_MeshNode* cornerNode) const;
|
|
|
|
//!< True if all blocks this side belongs to have beem found
|
|
|
|
bool isBound() const { return _nbBlocksExpected <= _nbBlocksFound; }
|
|
|
|
//!< Return coordinates of node at XY
|
|
|
|
gp_XYZ getXYZ(int x, int y) const { return SMESH_MeshEditor::TNodeXYZ( getNode( x, y )); }
|
|
|
|
//!< Return gravity center of the four corners and the middle node
|
|
|
|
gp_XYZ getGC() const
|
|
|
|
{
|
|
|
|
gp_XYZ xyz =
|
|
|
|
getXYZ( 0, 0 ) +
|
|
|
|
getXYZ( _index._xSize-1, 0 ) +
|
|
|
|
getXYZ( 0, _index._ySize-1 ) +
|
|
|
|
getXYZ( _index._xSize-1, _index._ySize-1 ) +
|
|
|
|
getXYZ( _index._xSize/2, _index._ySize/2 );
|
|
|
|
return xyz / 5;
|
|
|
|
}
|
|
|
|
//!< Return number of mesh faces
|
|
|
|
int getNbFaces() const { return (_index._xSize-1) * (_index._ySize-1); }
|
|
|
|
};
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief _BlockSide with changed orientation
|
|
|
|
*/
|
|
|
|
struct _OrientedBlockSide
|
|
|
|
{
|
|
|
|
_BlockSide* _side;
|
|
|
|
_OrientedIndexer _index;
|
|
|
|
|
|
|
|
_OrientedBlockSide( _BlockSide* side=0, const int oriFlags=0 ):
|
|
|
|
_side(side), _index(side ? side->_index : _Indexer(), oriFlags ) {}
|
|
|
|
//!< return coordinates by XY
|
|
|
|
gp_XYZ xyz(int x, int y) const
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
return SMESH_MeshEditor::TNodeXYZ( _grid_access_(_side, _index( x, y )) );
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
//!< safely return a node by XY
|
|
|
|
const SMDS_MeshNode* node(int x, int y) const
|
|
|
|
{
|
|
|
|
int i = _index( x, y );
|
|
|
|
return ( i < 0 || i >= _side->_grid.size()) ? 0 : _side->_grid[i];
|
|
|
|
}
|
|
|
|
//!< Return an edge
|
|
|
|
SMESH_OrientedLink edge(EQuadEdge edge) const
|
|
|
|
{
|
|
|
|
bool x1, y1, x2, y2; getEdgeEnds( edge, x1, y1, x2, y2 );
|
|
|
|
return SMESH_OrientedLink( cornerNode ( x1, y1 ), cornerNode( x2, y2 ));
|
|
|
|
}
|
|
|
|
//!< Return a corner node
|
|
|
|
const SMDS_MeshNode* cornerNode(bool isXMax, bool isYMax) const
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
return _grid_access_(_side, _index.corner( isXMax, isYMax ));
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
//!< return its size in nodes
|
|
|
|
int getHoriSize() const { return _index.xSize(); }
|
|
|
|
int getVertSize() const { return _index.ySize(); }
|
|
|
|
//!< True if _side has been initialized
|
|
|
|
operator bool() const { return _side; }
|
|
|
|
//! Direct access to _side
|
|
|
|
const _BlockSide* operator->() const { return _side; }
|
|
|
|
_BlockSide* operator->() { return _side; }
|
|
|
|
};
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Meshed skin of block
|
|
|
|
*/
|
|
|
|
struct _Block
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
_OrientedBlockSide _side[6]; // 6 sides of a sub-block
|
|
|
|
set<const SMDS_MeshNode*> _corners;
|
2010-05-14 21:32:37 +06:00
|
|
|
|
|
|
|
const _OrientedBlockSide& getSide(int i) const { return _side[i]; }
|
2010-06-10 15:43:07 +06:00
|
|
|
bool setSide( int i, const _OrientedBlockSide& s)
|
|
|
|
{
|
|
|
|
if (( _side[i] = s ))
|
|
|
|
{
|
|
|
|
_corners.insert( s.cornerNode(0,0));
|
|
|
|
_corners.insert( s.cornerNode(1,0));
|
|
|
|
_corners.insert( s.cornerNode(0,1));
|
|
|
|
_corners.insert( s.cornerNode(1,1));
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
void clear() { for (int i=0;i<6;++i) _side[i]=0; _corners.clear(); }
|
2010-05-14 21:32:37 +06:00
|
|
|
bool hasSide( const _OrientedBlockSide& s) const
|
|
|
|
{
|
|
|
|
if ( s ) for (int i=0;i<6;++i) if ( _side[i] && _side[i]._side == s._side ) return true;
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-10 15:43:07 +06:00
|
|
|
int nbSides() const { int n=0; for (int i=0;i<6;++i) if ( _side[i] ) ++n; return n; }
|
|
|
|
bool isValid() const;
|
2010-05-14 21:32:37 +06:00
|
|
|
};
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Skin mesh possibly containing several meshed blocks
|
|
|
|
*/
|
|
|
|
class _Skin
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
int findBlocks(SMESH_Mesh& mesh);
|
|
|
|
//!< return i-th block
|
|
|
|
const _Block& getBlock(int i) const { return _blocks[i]; }
|
|
|
|
//!< return error description
|
|
|
|
const SMESH_Comment& error() const { return _error; }
|
|
|
|
|
|
|
|
private:
|
2010-06-10 15:43:07 +06:00
|
|
|
bool fillSide( _BlockSide& side,
|
|
|
|
const SMDS_MeshElement* cornerQuad,
|
|
|
|
const SMDS_MeshNode* cornerNode);
|
2010-05-14 21:32:37 +06:00
|
|
|
bool fillRowsUntilCorner(const SMDS_MeshElement* quad,
|
|
|
|
const SMDS_MeshNode* n1,
|
|
|
|
const SMDS_MeshNode* n2,
|
|
|
|
vector<const SMDS_MeshNode*>& verRow1,
|
|
|
|
vector<const SMDS_MeshNode*>& verRow2,
|
|
|
|
bool alongN1N2 );
|
|
|
|
_OrientedBlockSide findBlockSide( EBoxSides startBlockSide,
|
|
|
|
EQuadEdge sharedSideEdge1,
|
2010-06-10 15:43:07 +06:00
|
|
|
EQuadEdge sharedSideEdge2,
|
|
|
|
bool withGeometricAnalysis);
|
2010-05-14 21:32:37 +06:00
|
|
|
//!< update own data and data of the side bound to block
|
|
|
|
void setSideBoundToBlock( _BlockSide& side )
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
if ( side._nbBlocksFound++, side.isBound() )
|
|
|
|
for ( int e = 0; e < int(NB_QUAD_SIDES); ++e )
|
2010-05-14 21:32:37 +06:00
|
|
|
_edge2sides[ side.getEdge( (EQuadEdge) e ) ].erase( &side );
|
|
|
|
}
|
|
|
|
//!< store reason of error
|
|
|
|
int error(const SMESH_Comment& reason) { _error = reason; return 0; }
|
|
|
|
|
|
|
|
SMESH_Comment _error;
|
|
|
|
|
|
|
|
list< _BlockSide > _allSides;
|
|
|
|
vector< _Block > _blocks;
|
|
|
|
|
|
|
|
//map< const SMDS_MeshNode*, set< _BlockSide* > > _corner2sides;
|
|
|
|
map< SMESH_OrientedLink, set< _BlockSide* > > _edge2sides;
|
|
|
|
};
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Find and return number of submeshes corresponding to blocks
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
int _Skin::findBlocks(SMESH_Mesh& mesh)
|
|
|
|
{
|
|
|
|
SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
|
|
|
|
|
|
|
|
// Find a node at any block corner
|
|
|
|
|
|
|
|
SMDS_NodeIteratorPtr nIt = meshDS->nodesIterator(/*idInceasingOrder=*/true);
|
|
|
|
if ( !nIt->more() ) return error("Empty mesh");
|
|
|
|
|
|
|
|
const SMDS_MeshNode* nCorner = 0;
|
|
|
|
while ( nIt->more() )
|
|
|
|
{
|
|
|
|
nCorner = nIt->next();
|
|
|
|
if ( isCornerNode( nCorner ))
|
|
|
|
break;
|
|
|
|
else
|
|
|
|
nCorner = 0;
|
|
|
|
}
|
|
|
|
if ( !nCorner )
|
|
|
|
return BAD_MESH_ERR;
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
// Find all block sides starting from mesh faces sharing the corner node
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
|
|
|
int nbFacesOnSides = 0;
|
|
|
|
TIDSortedElemSet cornerFaces; // corner faces of found _BlockSide's
|
|
|
|
list< const SMDS_MeshNode* > corners( 1, nCorner );
|
|
|
|
list< const SMDS_MeshNode* >::iterator corner = corners.begin();
|
|
|
|
while ( corner != corners.end() )
|
|
|
|
{
|
|
|
|
SMDS_ElemIteratorPtr faceIt = (*corner)->GetInverseElementIterator( SMDSAbs_Face );
|
|
|
|
while ( faceIt->more() )
|
|
|
|
{
|
|
|
|
const SMDS_MeshElement* face = faceIt->next();
|
|
|
|
if ( !cornerFaces.insert( face ).second )
|
|
|
|
continue; // already loaded block side
|
|
|
|
|
|
|
|
if ( !isQuadrangle( face ))
|
|
|
|
return error("Non-quadrangle elements in the input mesh");
|
|
|
|
|
|
|
|
if ( _allSides.empty() || !_allSides.back()._grid.empty() )
|
|
|
|
_allSides.push_back( _BlockSide() );
|
|
|
|
|
|
|
|
_BlockSide& side = _allSides.back();
|
2010-06-10 15:43:07 +06:00
|
|
|
if ( !fillSide( side, face, *corner ) )
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
|
|
|
if ( !_error.empty() )
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for ( int isXMax = 0; isXMax < 2; ++isXMax )
|
|
|
|
for ( int isYMax = 0; isYMax < 2; ++isYMax )
|
|
|
|
{
|
|
|
|
const SMDS_MeshNode* nCorner = side.getCornerNode(isXMax,isYMax );
|
|
|
|
corners.push_back( nCorner );
|
|
|
|
cornerFaces.insert( side.getCornerFace( nCorner ));
|
|
|
|
}
|
2010-06-10 15:43:07 +06:00
|
|
|
for ( int e = 0; e < int(NB_QUAD_SIDES); ++e )
|
2010-05-14 21:32:37 +06:00
|
|
|
_edge2sides[ side.getEdge( (EQuadEdge) e ) ].insert( &side );
|
|
|
|
|
|
|
|
nbFacesOnSides += side.getNbFaces();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++corner;
|
|
|
|
|
|
|
|
// find block sides of other domains if any
|
|
|
|
if ( corner == corners.end() && nbFacesOnSides < mesh.NbQuadrangles() )
|
|
|
|
{
|
|
|
|
while ( nIt->more() )
|
|
|
|
{
|
|
|
|
nCorner = nIt->next();
|
|
|
|
if ( isCornerNode( nCorner ))
|
|
|
|
corner = corners.insert( corner, nCorner );
|
|
|
|
}
|
|
|
|
nbFacesOnSides = mesh.NbQuadrangles();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( _allSides.empty() )
|
|
|
|
return BAD_MESH_ERR;
|
|
|
|
if ( _allSides.back()._grid.empty() )
|
|
|
|
_allSides.pop_back();
|
2010-06-10 15:43:07 +06:00
|
|
|
_DUMP_("Nb detected sides "<< _allSides.size());
|
2010-05-14 21:32:37 +06:00
|
|
|
|
|
|
|
// ---------------------------
|
|
|
|
// Organize sides into blocks
|
|
|
|
// ---------------------------
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
// analyse sharing of sides by blocks and sort sides by nb of adjacent sides
|
|
|
|
int nbBlockSides = 0; // total nb of block sides taking into account their sharing
|
|
|
|
multimap<int, _BlockSide* > sortedSides;
|
|
|
|
{
|
|
|
|
list < _BlockSide >::iterator sideIt = _allSides.begin();
|
|
|
|
for ( ; sideIt != _allSides.end(); ++sideIt )
|
|
|
|
{
|
|
|
|
_BlockSide& side = *sideIt;
|
|
|
|
bool isSharedSide = true;
|
|
|
|
int nbAdjacent = 0;
|
|
|
|
for ( int e = 0; e < int(NB_QUAD_SIDES) && isSharedSide; ++e )
|
|
|
|
{
|
|
|
|
int nbAdj = _edge2sides[ side.getEdge( (EQuadEdge) e ) ].size();
|
|
|
|
nbAdjacent += nbAdj;
|
|
|
|
isSharedSide = ( nbAdj > 2 );
|
|
|
|
}
|
|
|
|
side._nbBlocksFound = 0;
|
|
|
|
side._nbBlocksExpected = isSharedSide ? 2 : 1;
|
|
|
|
nbBlockSides += side._nbBlocksExpected;
|
|
|
|
sortedSides.insert( make_pair( nbAdjacent, & side ));
|
|
|
|
}
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
// find sides of each block
|
|
|
|
int nbBlocks = 0;
|
|
|
|
while ( nbBlockSides >= 6 )
|
|
|
|
{
|
|
|
|
// get any side not bound to all blocks it belongs to
|
2010-06-10 15:43:07 +06:00
|
|
|
multimap<int, _BlockSide*>::iterator i_side = sortedSides.begin();
|
|
|
|
while ( i_side != sortedSides.end() && i_side->second->isBound())
|
|
|
|
++i_side;
|
2010-05-14 21:32:37 +06:00
|
|
|
|
|
|
|
// start searching for block sides from the got side
|
|
|
|
bool ok = true;
|
|
|
|
if ( _blocks.empty() || _blocks.back()._side[B_FRONT] )
|
|
|
|
_blocks.resize( _blocks.size() + 1 );
|
|
|
|
|
|
|
|
_Block& block = _blocks.back();
|
2010-06-10 15:43:07 +06:00
|
|
|
block.setSide( B_FRONT, i_side->second );
|
|
|
|
setSideBoundToBlock( *i_side->second );
|
2010-05-14 21:32:37 +06:00
|
|
|
nbBlockSides--;
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
// edges of adjacent sides of B_FRONT corresponding to front's edges
|
|
|
|
EQuadEdge edgeOfFront[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT };
|
|
|
|
EQuadEdge edgeOfAdj [4] = { Q_BOTTOM, Q_LEFT, Q_BOTTOM, Q_LEFT };
|
|
|
|
// first find all sides detectable w/o advanced analysis,
|
|
|
|
// then repeat the search, which then may pass without advanced analysis
|
|
|
|
for ( int advAnalys = 0; advAnalys < 2; ++advAnalys )
|
|
|
|
{
|
|
|
|
for ( int i = 0; (ok || !advAnalys) && i < NB_QUAD_SIDES; ++i )
|
|
|
|
if ( !block._side[i] ) // try to find 4 sides adjacent to front side
|
|
|
|
ok = block.setSide( i, findBlockSide( B_FRONT, edgeOfFront[i],edgeOfAdj[i],advAnalys));
|
|
|
|
if ( ok || !advAnalys)
|
|
|
|
if ( !block._side[B_BACK] && block._side[B_TOP] ) // try to find back side by top one
|
|
|
|
ok = block.setSide( B_BACK, findBlockSide( B_TOP, Q_TOP, Q_TOP, advAnalys ));
|
|
|
|
if ( !advAnalys ) ok = true;
|
|
|
|
}
|
|
|
|
ok = block.isValid();
|
2010-05-14 21:32:37 +06:00
|
|
|
if ( ok )
|
|
|
|
{
|
|
|
|
// check if just found block is same as one of previously found
|
|
|
|
bool isSame = false;
|
|
|
|
for ( int i = 1; i < _blocks.size() && !isSame; ++i )
|
2010-06-10 15:43:07 +06:00
|
|
|
isSame = ( block._corners == _blocks[i-1]._corners );
|
2010-05-14 21:32:37 +06:00
|
|
|
ok = !isSame;
|
|
|
|
}
|
|
|
|
|
|
|
|
// count the found sides
|
2010-06-10 15:43:07 +06:00
|
|
|
_DUMP_(endl << "** Block " << _blocks.size() << " valid: " << block.isValid());
|
|
|
|
for (int i = 0; i < NB_BLOCK_SIDES; ++i )
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
_DUMP_("\tSide "<< SBoxSides[i] <<" "<< block._side[ i ]._side);
|
2010-05-14 21:32:37 +06:00
|
|
|
if ( block._side[ i ] )
|
|
|
|
{
|
|
|
|
if ( ok && i != B_FRONT)
|
|
|
|
{
|
|
|
|
setSideBoundToBlock( *block._side[ i ]._side );
|
|
|
|
nbBlockSides--;
|
|
|
|
}
|
2010-06-10 15:43:07 +06:00
|
|
|
_DUMP_("\t corners "<<
|
|
|
|
block._side[ i ].cornerNode(0,0)->GetID() << ", " <<
|
|
|
|
block._side[ i ].cornerNode(1,0)->GetID() << ", " <<
|
|
|
|
block._side[ i ].cornerNode(1,1)->GetID() << ", " <<
|
|
|
|
block._side[ i ].cornerNode(0,1)->GetID() << ", "<<endl);
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
_DUMP_("\t not found"<<endl);
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( !ok )
|
2010-06-10 15:43:07 +06:00
|
|
|
block.clear();
|
2010-05-14 21:32:37 +06:00
|
|
|
else
|
|
|
|
nbBlocks++;
|
|
|
|
}
|
2010-06-10 15:43:07 +06:00
|
|
|
_DUMP_("Nb found blocks "<< nbBlocks <<endl);
|
|
|
|
|
2010-05-14 21:32:37 +06:00
|
|
|
if ( nbBlocks == 0 && _error.empty() )
|
|
|
|
return BAD_MESH_ERR;
|
|
|
|
|
|
|
|
return nbBlocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Fill block side data starting from its corner quadrangle
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
bool _Skin::fillSide( _BlockSide& side,
|
|
|
|
const SMDS_MeshElement* cornerQuad,
|
|
|
|
const SMDS_MeshNode* nCorner)
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
|
|
|
// Find out size of block side mesured in nodes and by the way find two rows
|
|
|
|
// of nodes in two directions.
|
|
|
|
|
|
|
|
int x, y, nbX, nbY;
|
|
|
|
const SMDS_MeshElement* firstQuad = cornerQuad;
|
|
|
|
{
|
|
|
|
// get a node on block edge
|
|
|
|
int iCorner = firstQuad->GetNodeIndex( nCorner );
|
|
|
|
const SMDS_MeshNode* nOnEdge = firstQuad->GetNode( (iCorner+1) % 4);
|
|
|
|
|
|
|
|
// find out size of block side
|
|
|
|
vector<const SMDS_MeshNode*> horRow1, horRow2, verRow1, verRow2;
|
|
|
|
if ( !fillRowsUntilCorner( firstQuad, nCorner, nOnEdge, horRow1, horRow2, true ) ||
|
|
|
|
!fillRowsUntilCorner( firstQuad, nCorner, nOnEdge, verRow1, verRow2, false ))
|
|
|
|
return false;
|
|
|
|
nbX = horRow1.size(), nbY = verRow1.size();
|
|
|
|
|
|
|
|
// store found nodes
|
|
|
|
side._index._xSize = horRow1.size();
|
|
|
|
side._index._ySize = verRow1.size();
|
|
|
|
side._grid.resize( side._index.size(), NULL );
|
|
|
|
|
|
|
|
for ( x = 0; x < horRow1.size(); ++x )
|
|
|
|
{
|
|
|
|
side.setNode( x, 0, horRow1[x] );
|
|
|
|
side.setNode( x, 1, horRow2[x] );
|
|
|
|
}
|
|
|
|
for ( y = 0; y < verRow1.size(); ++y )
|
|
|
|
{
|
|
|
|
side.setNode( 0, y, verRow1[y] );
|
|
|
|
side.setNode( 1, y, verRow2[y] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Find the rest nodes
|
|
|
|
|
|
|
|
y = 1; // y of the row to fill
|
|
|
|
TIDSortedElemSet emptySet, avoidSet;
|
|
|
|
while ( ++y < nbY )
|
|
|
|
{
|
|
|
|
// get next firstQuad in the next row of quadrangles
|
|
|
|
//
|
|
|
|
// n2up
|
|
|
|
// o---o <- y row
|
|
|
|
// | |
|
|
|
|
// o---o o o o o <- found nodes
|
|
|
|
//n1down n2down
|
|
|
|
//
|
|
|
|
int i1down, i2down, i2up;
|
|
|
|
const SMDS_MeshNode* n1down = side.getNode( 0, y-1 );
|
|
|
|
const SMDS_MeshNode* n2down = side.getNode( 1, y-1 );
|
|
|
|
avoidSet.clear(); avoidSet.insert( firstQuad );
|
|
|
|
firstQuad = SMESH_MeshEditor::FindFaceInSet( n1down, n2down, emptySet, avoidSet,
|
|
|
|
&i1down, &i2down);
|
|
|
|
if ( !isQuadrangle( firstQuad ))
|
|
|
|
return BAD_MESH_ERR;
|
|
|
|
|
|
|
|
const SMDS_MeshNode* n2up = oppositeNode( firstQuad, i1down );
|
|
|
|
avoidSet.clear(); avoidSet.insert( firstQuad );
|
|
|
|
|
|
|
|
// find the rest nodes in the y-th row by faces in the row
|
|
|
|
|
|
|
|
x = 1;
|
|
|
|
while ( ++x < nbX )
|
|
|
|
{
|
|
|
|
const SMDS_MeshElement* quad = SMESH_MeshEditor::FindFaceInSet( n2up, n2down, emptySet,
|
|
|
|
avoidSet, &i2up, &i2down);
|
|
|
|
if ( !isQuadrangle( quad ))
|
|
|
|
return BAD_MESH_ERR;
|
|
|
|
|
|
|
|
n2up = oppositeNode( quad, i2down );
|
|
|
|
n2down = oppositeNode( quad, i2up );
|
|
|
|
avoidSet.clear(); avoidSet.insert( quad );
|
|
|
|
|
|
|
|
side.setNode( x, y, n2up );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
// 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;
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Try to find a block side adjacent to the given side by given edge
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
_OrientedBlockSide _Skin::findBlockSide( EBoxSides startBlockSide,
|
|
|
|
EQuadEdge sharedSideEdge1,
|
2010-06-10 15:43:07 +06:00
|
|
|
EQuadEdge sharedSideEdge2,
|
|
|
|
bool withGeometricAnalysis)
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
|
|
|
_Block& block = _blocks.back();
|
|
|
|
_OrientedBlockSide& side1 = block._side[ startBlockSide ];
|
|
|
|
|
|
|
|
// get corner nodes of the given block edge
|
|
|
|
SMESH_OrientedLink edge = side1.edge( sharedSideEdge1 );
|
|
|
|
const SMDS_MeshNode* n1 = edge.node1();
|
|
|
|
const SMDS_MeshNode* n2 = edge.node2();
|
|
|
|
if ( edge._reversed ) swap( n1, n2 );
|
|
|
|
|
|
|
|
// find all sides sharing both nodes n1 and n2
|
|
|
|
set< _BlockSide* > sidesOnEdge = _edge2sides[ edge ]; // copy a set
|
|
|
|
|
|
|
|
// exclude loaded sides of block from sidesOnEdge
|
2010-06-10 15:43:07 +06:00
|
|
|
for (int i = 0; i < NB_BLOCK_SIDES; ++i )
|
2010-05-14 21:32:37 +06:00
|
|
|
if ( block._side[ i ] )
|
|
|
|
sidesOnEdge.erase( block._side[ i ]._side );
|
2010-06-10 15:43:07 +06:00
|
|
|
|
2010-05-14 21:32:37 +06:00
|
|
|
int nbSidesOnEdge = sidesOnEdge.size();
|
|
|
|
_DUMP_("nbSidesOnEdge "<< nbSidesOnEdge << " " << n1->GetID() << "-" << n2->GetID() );
|
|
|
|
if ( nbSidesOnEdge == 0 )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
_BlockSide* foundSide = 0;
|
2010-06-10 15:43:07 +06:00
|
|
|
if ( nbSidesOnEdge == 1 )
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
|
|
|
foundSide = *sidesOnEdge.begin();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
set< _BlockSide* >::iterator sideIt = sidesOnEdge.begin();
|
2010-06-10 15:43:07 +06:00
|
|
|
int nbLoadedSides = block.nbSides();
|
|
|
|
if ( nbLoadedSides > 1 )
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
2010-06-10 15:43:07 +06:00
|
|
|
// Find the side having more than 2 corners common with already loaded sides
|
|
|
|
for (; !foundSide && sideIt != sidesOnEdge.end(); ++sideIt )
|
|
|
|
{
|
|
|
|
_BlockSide* sideI = *sideIt;
|
|
|
|
int nbCommonCorners =
|
|
|
|
block._corners.count( sideI->getCornerNode(0,0)) +
|
|
|
|
block._corners.count( sideI->getCornerNode(1,0)) +
|
|
|
|
block._corners.count( sideI->getCornerNode(0,1)) +
|
|
|
|
block._corners.count( sideI->getCornerNode(1,1));
|
|
|
|
if ( nbCommonCorners > 2 )
|
|
|
|
foundSide = sideI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !foundSide )
|
|
|
|
{
|
|
|
|
if ( !withGeometricAnalysis ) return 0;
|
|
|
|
|
|
|
|
// 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 (sideIt = 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_XYZ gc(0,0,0); // gravity center of already loaded block sides
|
|
|
|
for (int i = 0; i < NB_BLOCK_SIDES; ++i )
|
|
|
|
if ( block._side[ i ] )
|
|
|
|
gc += block._side[ i ]._side->getGC();
|
|
|
|
gc /= nbLoadedSides;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2010-05-14 21:32:37 +06:00
|
|
|
}
|
|
|
|
_DUMP_(" selected "<< foundSide );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Orient the found side correctly
|
|
|
|
|
|
|
|
// corners of found side corresponding to nodes n1 and n2
|
|
|
|
bool xMax1, yMax1, xMax2, yMax2;
|
|
|
|
if ( !getEdgeEnds( sharedSideEdge2, xMax1, yMax1, xMax2, yMax2 ))
|
|
|
|
return error(SMESH_Comment("Internal error at ")<<__FILE__<<":"<<__LINE__),
|
|
|
|
_OrientedBlockSide(0);
|
|
|
|
|
|
|
|
for ( int ori = 0; ori < _OrientedIndexer::MAX_ORI+1; ++ori )
|
|
|
|
{
|
|
|
|
_OrientedBlockSide orientedSide( foundSide, ori );
|
|
|
|
const SMDS_MeshNode* n12 = orientedSide.cornerNode( xMax1, yMax1);
|
|
|
|
const SMDS_MeshNode* n22 = orientedSide.cornerNode( xMax2, yMax2);
|
|
|
|
if ( n1 == n12 && n2 == n22 )
|
|
|
|
return orientedSide;
|
|
|
|
}
|
|
|
|
error(SMESH_Comment("Failed to orient a block side found by edge ")<<sharedSideEdge1
|
|
|
|
<< " of side " << startBlockSide
|
|
|
|
<< " of block " << _blocks.size());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief: Fill rows (which are actually columns,if !alongN1N2) of nodes starting
|
|
|
|
* from the given quadrangle until another block corner encounters.
|
|
|
|
* n1 and n2 are at bottom of quad, n1 is at block corner.
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool _Skin::fillRowsUntilCorner(const SMDS_MeshElement* quad,
|
|
|
|
const SMDS_MeshNode* n1,
|
|
|
|
const SMDS_MeshNode* n2,
|
|
|
|
vector<const SMDS_MeshNode*>& row1,
|
|
|
|
vector<const SMDS_MeshNode*>& row2,
|
|
|
|
const bool alongN1N2 )
|
|
|
|
{
|
|
|
|
const SMDS_MeshNode* corner1 = n1;
|
|
|
|
|
|
|
|
// Store nodes of quad in the rows and find new n1 and n2 to get
|
|
|
|
// the next face so that new n2 is on block edge
|
|
|
|
int i1 = quad->GetNodeIndex( n1 );
|
|
|
|
int i2 = quad->GetNodeIndex( n2 );
|
|
|
|
row1.clear(); row2.clear();
|
|
|
|
row1.push_back( n1 );
|
|
|
|
if ( alongN1N2 )
|
|
|
|
{
|
|
|
|
row1.push_back( n2 );
|
|
|
|
row2.push_back( oppositeNode( quad, i2 ));
|
|
|
|
row2.push_back( n1 = oppositeNode( quad, i1 ));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
row2.push_back( n2 );
|
|
|
|
row1.push_back( n2 = oppositeNode( quad, i2 ));
|
|
|
|
row2.push_back( n1 = oppositeNode( quad, i1 ));
|
|
|
|
}
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
_NodeDescriptor nDesc( row1[1] );
|
|
|
|
if ( nDesc == _NodeDescriptor( row1[0] ))
|
|
|
|
return true; // row of 2 nodes
|
|
|
|
|
2010-05-14 21:32:37 +06:00
|
|
|
// Find the rest nodes
|
|
|
|
TIDSortedElemSet emptySet, avoidSet;
|
2010-06-10 15:43:07 +06:00
|
|
|
//while ( !isCornerNode( n2 ))
|
|
|
|
while ( nDesc == _NodeDescriptor( n2 ))
|
2010-05-14 21:32:37 +06:00
|
|
|
{
|
|
|
|
avoidSet.clear(); avoidSet.insert( quad );
|
|
|
|
quad = SMESH_MeshEditor::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2 );
|
|
|
|
if ( !isQuadrangle( quad ))
|
|
|
|
return BAD_MESH_ERR;
|
|
|
|
|
|
|
|
row1.push_back( n2 = oppositeNode( quad, i1 ));
|
|
|
|
row2.push_back( n1 = oppositeNode( quad, i2 ));
|
|
|
|
}
|
|
|
|
return n1 != corner1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Return a corner face by a corner node
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
const SMDS_MeshElement* _BlockSide::getCornerFace(const SMDS_MeshNode* cornerNode) const
|
|
|
|
{
|
|
|
|
int x, y, isXMax, isYMax, found = 0;
|
|
|
|
for ( isXMax = 0; isXMax < 2; ++isXMax )
|
|
|
|
{
|
|
|
|
for ( isYMax = 0; isYMax < 2; ++isYMax )
|
|
|
|
{
|
|
|
|
x = isXMax ? _index._xSize-1 : 0;
|
|
|
|
y = isYMax ? _index._ySize-1 : 0;
|
|
|
|
found = ( getNode(x,y) == cornerNode );
|
|
|
|
if ( found ) break;
|
|
|
|
}
|
|
|
|
if ( found ) break;
|
|
|
|
}
|
|
|
|
if ( !found ) return 0;
|
|
|
|
int dx = isXMax ? -1 : +1;
|
|
|
|
int dy = isYMax ? -1 : +1;
|
|
|
|
const SMDS_MeshNode* n1 = getNode(x,y);
|
|
|
|
const SMDS_MeshNode* n2 = getNode(x+dx,y);
|
|
|
|
const SMDS_MeshNode* n3 = getNode(x,y+dy);
|
|
|
|
const SMDS_MeshNode* n4 = getNode(x+dx,y+dy);
|
|
|
|
return SMDS_Mesh::FindFace(n1, n2, n3, n4 );
|
|
|
|
}
|
|
|
|
|
2010-06-10 15:43:07 +06:00
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Checks own validity
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool _Block::isValid() const
|
|
|
|
{
|
|
|
|
bool ok = ( nbSides() == 6 );
|
|
|
|
|
|
|
|
// check only corners depending on side selection
|
|
|
|
EBoxSides adjacent[4] = { B_BOTTOM, B_RIGHT, B_TOP, B_LEFT };
|
|
|
|
EQuadEdge edgeAdj [4] = { Q_TOP, Q_RIGHT, Q_TOP, Q_RIGHT };
|
|
|
|
EQuadEdge edgeBack[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT };
|
|
|
|
|
|
|
|
for ( int i=0; ok && i < NB_QUAD_SIDES; ++i )
|
|
|
|
{
|
|
|
|
SMESH_OrientedLink eBack = _side[ B_BACK ].edge( edgeBack[i] );
|
|
|
|
SMESH_OrientedLink eAdja = _side[ adjacent[i] ].edge( edgeAdj[i] );
|
|
|
|
ok = ( eBack == eAdja );
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
2010-05-14 21:32:37 +06:00
|
|
|
|
|
|
|
//=======================================================================
|
|
|
|
//function : StdMeshers_HexaFromSkin_3D
|
|
|
|
//purpose :
|
|
|
|
//=======================================================================
|
|
|
|
|
|
|
|
StdMeshers_HexaFromSkin_3D::StdMeshers_HexaFromSkin_3D(int hypId, int studyId, SMESH_Gen* gen)
|
|
|
|
:SMESH_3D_Algo(hypId, studyId, gen)
|
|
|
|
{
|
|
|
|
MESSAGE("StdMeshers_HexaFromSkin_3D::StdMeshers_HexaFromSkin_3D");
|
|
|
|
_name = "HexaFromSkin_3D";
|
|
|
|
}
|
|
|
|
|
|
|
|
StdMeshers_HexaFromSkin_3D::~StdMeshers_HexaFromSkin_3D()
|
|
|
|
{
|
|
|
|
MESSAGE("StdMeshers_HexaFromSkin_3D::~StdMeshers_HexaFromSkin_3D");
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Main method, which generates hexaheda
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool StdMeshers_HexaFromSkin_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper)
|
|
|
|
{
|
|
|
|
_Skin skin;
|
|
|
|
int nbBlocks = skin.findBlocks(aMesh);
|
|
|
|
if ( nbBlocks == 0 )
|
|
|
|
return error( skin.error());
|
|
|
|
|
|
|
|
vector< vector< const SMDS_MeshNode* > > columns;
|
|
|
|
int x, xSize, y, ySize, z, zSize;
|
|
|
|
_Indexer colIndex;
|
|
|
|
|
|
|
|
for ( int i = 0; i < nbBlocks; ++i )
|
|
|
|
{
|
|
|
|
const _Block& block = skin.getBlock( i );
|
|
|
|
|
|
|
|
// ------------------------------------------
|
|
|
|
// Fill columns of nodes with existing nodes
|
|
|
|
// ------------------------------------------
|
|
|
|
|
|
|
|
xSize = block.getSide(B_BOTTOM).getHoriSize();
|
|
|
|
ySize = block.getSide(B_BOTTOM).getVertSize();
|
|
|
|
zSize = block.getSide(B_FRONT ).getVertSize();
|
|
|
|
int X = xSize - 1, Y = ySize - 1, Z = zSize - 1;
|
|
|
|
colIndex = _Indexer( xSize, ySize );
|
|
|
|
columns.resize( colIndex.size() );
|
|
|
|
|
|
|
|
// fill node columns by front and back box sides
|
|
|
|
for ( x = 0; x < xSize; ++x ) {
|
|
|
|
vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )];
|
|
|
|
vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )];
|
|
|
|
column0.resize( zSize );
|
|
|
|
column1.resize( zSize );
|
|
|
|
for ( z = 0; z < zSize; ++z ) {
|
|
|
|
column0[ z ] = block.getSide(B_FRONT).node( x, z );
|
|
|
|
column1[ z ] = block.getSide(B_BACK) .node( x, z );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// fill node columns by left and right box sides
|
|
|
|
for ( y = 1; y < ySize-1; ++y ) {
|
|
|
|
vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )];
|
|
|
|
vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )];
|
|
|
|
column0.resize( zSize );
|
|
|
|
column1.resize( zSize );
|
|
|
|
for ( z = 0; z < zSize; ++z ) {
|
|
|
|
column0[ z ] = block.getSide(B_LEFT) .node( y, z );
|
|
|
|
column1[ z ] = block.getSide(B_RIGHT).node( y, z );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// get nodes from top and bottom box sides
|
|
|
|
for ( x = 1; x < xSize-1; ++x ) {
|
|
|
|
for ( y = 1; y < ySize-1; ++y ) {
|
|
|
|
vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
|
|
|
|
column.resize( zSize );
|
|
|
|
column.front() = block.getSide(B_BOTTOM).node( x, y );
|
|
|
|
column.back() = block.getSide(B_TOP) .node( x, y );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------
|
|
|
|
// Add internal nodes of a box
|
|
|
|
// ----------------------------
|
|
|
|
// projection points of internal nodes on box subshapes by which
|
|
|
|
// coordinates of internal nodes are computed
|
|
|
|
vector<gp_XYZ> pointOnShape( SMESH_Block::ID_Shell );
|
|
|
|
|
|
|
|
// projections on vertices are constant
|
|
|
|
pointOnShape[ SMESH_Block::ID_V000 ] = block.getSide(B_BOTTOM).xyz( 0, 0 );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V100 ] = block.getSide(B_BOTTOM).xyz( X, 0 );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V010 ] = block.getSide(B_BOTTOM).xyz( 0, Y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V110 ] = block.getSide(B_BOTTOM).xyz( X, Y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V001 ] = block.getSide(B_TOP).xyz( 0, 0 );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V101 ] = block.getSide(B_TOP).xyz( X, 0 );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V011 ] = block.getSide(B_TOP).xyz( 0, Y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_V111 ] = block.getSide(B_TOP).xyz( X, Y );
|
|
|
|
|
|
|
|
for ( x = 1; x < xSize-1; ++x )
|
|
|
|
{
|
|
|
|
gp_XYZ params; // normalized parameters of internal node within a unit box
|
|
|
|
params.SetCoord( 1, x / double(X) );
|
|
|
|
for ( y = 1; y < ySize-1; ++y )
|
|
|
|
{
|
|
|
|
params.SetCoord( 2, y / double(Y) );
|
|
|
|
// column to fill during z loop
|
|
|
|
vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
|
|
|
|
// projections on horizontal edges
|
|
|
|
pointOnShape[ SMESH_Block::ID_Ex00 ] = block.getSide(B_BOTTOM).xyz( x, 0 );
|
|
|
|
pointOnShape[ SMESH_Block::ID_Ex10 ] = block.getSide(B_BOTTOM).xyz( x, Y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E0y0 ] = block.getSide(B_BOTTOM).xyz( 0, y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E1y0 ] = block.getSide(B_BOTTOM).xyz( X, y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_Ex01 ] = block.getSide(B_TOP).xyz( x, 0 );
|
|
|
|
pointOnShape[ SMESH_Block::ID_Ex11 ] = block.getSide(B_TOP).xyz( x, Y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E0y1 ] = block.getSide(B_TOP).xyz( 0, y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E1y1 ] = block.getSide(B_TOP).xyz( X, y );
|
|
|
|
// projections on horizontal sides
|
|
|
|
pointOnShape[ SMESH_Block::ID_Fxy0 ] = block.getSide(B_BOTTOM).xyz( x, y );
|
|
|
|
pointOnShape[ SMESH_Block::ID_Fxy1 ] = block.getSide(B_TOP) .xyz( x, y );
|
|
|
|
for ( z = 1; z < zSize-1; ++z ) // z loop
|
|
|
|
{
|
|
|
|
params.SetCoord( 3, z / double(Z) );
|
|
|
|
// projections on vertical edges
|
|
|
|
pointOnShape[ SMESH_Block::ID_E00z ] = block.getSide(B_FRONT).xyz( 0, z );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E10z ] = block.getSide(B_FRONT).xyz( X, z );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E01z ] = block.getSide(B_BACK).xyz( 0, z );
|
|
|
|
pointOnShape[ SMESH_Block::ID_E11z ] = block.getSide(B_BACK).xyz( X, z );
|
|
|
|
// projections on vertical sides
|
|
|
|
pointOnShape[ SMESH_Block::ID_Fx0z ] = block.getSide(B_FRONT).xyz( x, z );
|
|
|
|
pointOnShape[ SMESH_Block::ID_Fx1z ] = block.getSide(B_BACK) .xyz( x, z );
|
|
|
|
pointOnShape[ SMESH_Block::ID_F0yz ] = block.getSide(B_LEFT) .xyz( y, z );
|
|
|
|
pointOnShape[ SMESH_Block::ID_F1yz ] = block.getSide(B_RIGHT).xyz( y, z );
|
|
|
|
|
|
|
|
// compute internal node coordinates
|
|
|
|
gp_XYZ coords;
|
|
|
|
SMESH_Block::ShellPoint( params, pointOnShape, coords );
|
|
|
|
column[ z ] = aHelper->AddNode( coords.X(), coords.Y(), coords.Z() );
|
|
|
|
|
|
|
|
#ifdef DEB_GRID
|
|
|
|
// debug
|
|
|
|
//cout << "----------------------------------------------------------------------"<<endl;
|
|
|
|
//for ( int id = SMESH_Block::ID_V000; id < SMESH_Block::ID_Shell; ++id)
|
|
|
|
//{
|
|
|
|
// gp_XYZ p = pointOnShape[ id ];
|
|
|
|
// SMESH_Block::DumpShapeID( id,cout)<<" ( "<<p.X()<<", "<<p.Y()<<", "<<p.Z()<<" )"<<endl;
|
|
|
|
//}
|
|
|
|
//cout << "Params: ( "<< params.X()<<", "<<params.Y()<<", "<<params.Z()<<" )"<<endl;
|
|
|
|
//cout << "coords: ( "<< coords.X()<<", "<<coords.Y()<<", "<<coords.Z()<<" )"<<endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// ----------------
|
|
|
|
// Add hexahedrons
|
|
|
|
// ----------------
|
|
|
|
|
|
|
|
// find out orientation
|
|
|
|
const SMDS_MeshNode* n000 = block.getSide(B_BOTTOM).cornerNode( 0, 0 );
|
|
|
|
const SMDS_MeshNode* n100 = block.getSide(B_BOTTOM).cornerNode( 1, 0 );
|
|
|
|
const SMDS_MeshNode* n010 = block.getSide(B_BOTTOM).cornerNode( 0, 1 );
|
|
|
|
const SMDS_MeshNode* n110 = block.getSide(B_BOTTOM).cornerNode( 1, 1 );
|
|
|
|
const SMDS_MeshNode* n001 = block.getSide(B_TOP).cornerNode( 0, 0 );
|
|
|
|
const SMDS_MeshNode* n101 = block.getSide(B_TOP).cornerNode( 1, 0 );
|
|
|
|
const SMDS_MeshNode* n011 = block.getSide(B_TOP).cornerNode( 0, 1 );
|
|
|
|
const SMDS_MeshNode* n111 = block.getSide(B_TOP).cornerNode( 1, 1 );
|
|
|
|
SMDS_VolumeOfNodes probeVolume (n000,n010,n110,n100,
|
|
|
|
n001,n011,n111,n101);
|
|
|
|
bool isForw = SMDS_VolumeTool( &probeVolume ).IsForward();
|
|
|
|
|
|
|
|
// add elements
|
|
|
|
for ( x = 0; x < xSize-1; ++x ) {
|
|
|
|
for ( y = 0; y < ySize-1; ++y ) {
|
|
|
|
vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x, y )];
|
|
|
|
vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )];
|
|
|
|
vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )];
|
|
|
|
vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )];
|
|
|
|
// bottom face normal of a hexa mush point outside the volume
|
|
|
|
if ( isForw )
|
|
|
|
for ( z = 0; z < zSize-1; ++z )
|
|
|
|
aHelper->AddVolume(col00[z], col01[z], col11[z], col10[z],
|
|
|
|
col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
|
|
|
|
else
|
|
|
|
for ( z = 0; z < zSize-1; ++z )
|
|
|
|
aHelper->AddVolume(col00[z], col10[z], col11[z], col01[z],
|
|
|
|
col00[z+1], col10[z+1], col11[z+1], col01[z+1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // loop on blocks
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Evaluate nb of hexa
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool StdMeshers_HexaFromSkin_3D::Evaluate(SMESH_Mesh & aMesh,
|
|
|
|
const TopoDS_Shape & aShape,
|
|
|
|
MapShapeNbElems& aResMap)
|
|
|
|
{
|
|
|
|
_Skin skin;
|
|
|
|
int nbBlocks = skin.findBlocks(aMesh);
|
|
|
|
if ( nbBlocks == 0 )
|
|
|
|
return error( skin.error());
|
|
|
|
|
|
|
|
bool secondOrder = aMesh.NbFaces( ORDER_QUADRATIC );
|
|
|
|
|
|
|
|
int entity = secondOrder ? SMDSEntity_Quad_Hexa : SMDSEntity_Hexa;
|
|
|
|
vector<int>& nbByType = aResMap[ aMesh.GetSubMesh( aShape )];
|
|
|
|
if ( entity >= nbByType.size() )
|
|
|
|
nbByType.resize( SMDSEntity_Last, 0 );
|
|
|
|
|
|
|
|
for ( int i = 0; i < nbBlocks; ++i )
|
|
|
|
{
|
|
|
|
const _Block& block = skin.getBlock( i );
|
|
|
|
|
|
|
|
int nbX = block.getSide(B_BOTTOM).getHoriSize();
|
|
|
|
int nbY = block.getSide(B_BOTTOM).getVertSize();
|
|
|
|
int nbZ = block.getSide(B_FRONT ).getVertSize();
|
|
|
|
|
|
|
|
int nbHexa = (nbX-1) * (nbY-1) * (nbZ-1);
|
|
|
|
int nbNodes = (nbX-2) * (nbY-2) * (nbZ-2);
|
|
|
|
if ( secondOrder )
|
|
|
|
nbNodes +=
|
|
|
|
(nbX-2) * (nbY-2) * (nbZ-1) +
|
|
|
|
(nbX-2) * (nbY-1) * (nbZ-2) +
|
|
|
|
(nbX-1) * (nbY-2) * (nbZ-2);
|
|
|
|
|
|
|
|
|
|
|
|
nbByType[ entity ] += nbHexa;
|
|
|
|
nbByType[ SMDSEntity_Node ] += nbNodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Abstract method must be defined but does nothing
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool StdMeshers_HexaFromSkin_3D::CheckHypothesis(SMESH_Mesh&, const TopoDS_Shape&,
|
|
|
|
Hypothesis_Status& aStatus)
|
|
|
|
{
|
|
|
|
aStatus = SMESH_Hypothesis::HYP_OK;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//================================================================================
|
|
|
|
/*!
|
|
|
|
* \brief Abstract method must be defined but just reports an error as this
|
|
|
|
* algo is not intended to work with shapes
|
|
|
|
*/
|
|
|
|
//================================================================================
|
|
|
|
|
|
|
|
bool StdMeshers_HexaFromSkin_3D::Compute(SMESH_Mesh&, const TopoDS_Shape&)
|
|
|
|
{
|
|
|
|
return error("Algorithm can't work with geometrical shapes");
|
|
|
|
}
|
|
|
|
|