1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File : SMESH_HexaFromSkin_3D.cxx
21 // Created : Wed Jan 27 12:28:07 2010
22 // Author : Edward AGAPOV (eap)
24 #include "HEXABLOCKPlugin_FromSkin_3D.hxx"
26 #include "SMDS_VolumeOfNodes.hxx"
27 #include "SMDS_VolumeTool.hxx"
28 #include "SMESH_Block.hxx"
29 #include "SMESH_MesherHelper.hxx"
33 //#include "utilities.h"
35 // Define error message
37 #define BAD_MESH_ERR \
38 error(SMESH_Comment("Can't detect block-wise structure of the input 2D mesh.\n" \
39 __FILE__ ":" )<<__LINE__)
41 #define BAD_MESH_ERR \
42 error(SMESH_Comment("Can't detect block-wise structure of the input 2D mesh"))
46 #define _DUMP_(msg) //cout << msg << endl
50 static int MYDEBUG = 1;
52 static int MYDEBUG = 1;
58 enum EBoxSides //!< sides of the block
60 B_BOTTOM=0, B_RIGHT, B_TOP, B_LEFT, B_FRONT, B_BACK, NB_BLOCK_SIDES
62 const char* SBoxSides[] = //!< names of block sides
64 "BOTTOM", "RIGHT", "TOP", "LEFT", "FRONT", "BACK", "UNDEFINED"
66 enum EQuadEdge //!< edges of quadrangle side
68 Q_BOTTOM = 0, Q_RIGHT, Q_TOP, Q_LEFT, NB_QUAD_SIDES
72 //================================================================================
74 * \brief return logical coordinates (i.e. min or max) of ends of edge
76 //================================================================================
78 bool getEdgeEnds(EQuadEdge edge, bool& xMax1, bool& yMax1, bool& xMax2, bool& yMax2 )
80 xMax1=0, yMax1=0, xMax2=1, yMax2=1;
83 case Q_BOTTOM: yMax2 = 0; break;
84 case Q_RIGHT: xMax1 = 1; break;
85 case Q_TOP: yMax1 = 1; break;
86 case Q_LEFT: xMax2 = 0; break;
93 //================================================================================
95 * \brief Description of node used to detect corner nodes
97 struct _NodeDescriptor
99 int nbInverseFaces, nbNodesInInverseFaces;
101 _NodeDescriptor(const SMDS_MeshNode* n): nbInverseFaces(0), nbNodesInInverseFaces(0)
105 set<const SMDS_MeshNode*> nodes;
106 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face );
107 while ( fIt->more() )
109 const SMDS_MeshElement* face = fIt->next();
110 nodes.insert( face->begin_nodes(), face->end_nodes() );
113 nbNodesInInverseFaces = nodes.size();
116 bool operator==(const _NodeDescriptor& other) const
119 nbInverseFaces == other.nbInverseFaces &&
120 nbNodesInInverseFaces == other.nbNodesInInverseFaces;
124 //================================================================================
126 * \brief return true if a node is at block corner
128 * This check is valid for simple cases only
130 //================================================================================
132 bool isCornerNode( const SMDS_MeshNode* n )
134 return n && n->NbInverseElements( SMDSAbs_Face ) % 2;
137 //================================================================================
139 * \brief check element type
141 //================================================================================
143 bool isQuadrangle(const SMDS_MeshElement* e)
145 return ( e && e->NbCornerNodes() == 4 );
148 //================================================================================
150 * \brief return opposite node of a quadrangle face
152 //================================================================================
154 const SMDS_MeshNode* oppositeNode(const SMDS_MeshElement* quad, int iNode)
156 return quad->GetNode( (iNode+2) % 4 );
159 //================================================================================
161 * \brief Convertor of a pair of integers to a sole index
166 _Indexer( int xSize=0, int ySize=0 ): _xSize(xSize), _ySize(ySize) {}
167 int size() const { return _xSize * _ySize; }
168 int operator()(int x, int y) const { return y * _xSize + x; }
170 //================================================================================
172 * \brief Oriented convertor of a pair of integers to a sole index
174 class _OrientedIndexer : public _Indexer
177 enum OriFlags //!< types of block side orientation
179 REV_X = 1, REV_Y = 2, SWAP_XY = 4, MAX_ORI = REV_X|REV_Y|SWAP_XY
181 _OrientedIndexer( const _Indexer& indexer, const int oriFlags ):
182 _Indexer( indexer._xSize, indexer._ySize ),
183 _xSize (indexer._xSize), _ySize(indexer._ySize),
184 _xRevFun((oriFlags & REV_X) ? & reverse : & lazy),
185 _yRevFun((oriFlags & REV_Y) ? & reverse : & lazy),
186 _swapFun((oriFlags & SWAP_XY ) ? & swap : & lazy)
188 (*_swapFun)( _xSize, _ySize );
190 //!< Return index by XY
191 int operator()(int x, int y) const
193 (*_xRevFun)( x, const_cast<int&>( _xSize ));
194 (*_yRevFun)( y, const_cast<int&>( _ySize ));
196 return _Indexer::operator()(x,y);
198 //!< Return index for a corner
199 int corner(bool xMax, bool yMax) const
201 int x = xMax, y = yMax, size = 2;
202 (*_xRevFun)( x, size );
203 (*_yRevFun)( y, size );
205 return _Indexer::operator()(x ? _Indexer::_xSize-1 : 0 , y ? _Indexer::_ySize-1 : 0);
207 int xSize() const { return _xSize; }
208 int ySize() const { return _ySize; }
213 typedef void (*TFun)(int& x, int& y);
214 TFun _xRevFun, _yRevFun, _swapFun;
216 static void lazy(int&, int&) {}
217 static void reverse(int& x, int& size) { x = size - x - 1; }
218 static void swap(int& x, int& y) { std::swap(x,y); }
220 //================================================================================
222 * \brief Structure corresponding to the meshed side of block
226 vector<const SMDS_MeshNode*> _grid;
228 int _nbBlocksExpected;
231 #ifdef _DEBUG_ // want to get SIGSEGV in case of invalid index
232 #define _grid_access_(pobj, i) pobj->_grid[ ((i) < pobj->_grid.size()) ? i : int(1e100)]
234 #define _grid_access_(pobj, i) pobj->_grid[ i ]
236 //!< Return node at XY
237 const SMDS_MeshNode* getNode(int x, int y) const { return _grid_access_(this, _index( x,y ));}
239 void setNode(int x, int y, const SMDS_MeshNode* n) { _grid_access_(this, _index( x,y )) = n; }
241 SMESH_OrientedLink getEdge(EQuadEdge edge) const
243 bool x1, y1, x2, y2; getEdgeEnds( edge, x1, y1, x2, y2 );
244 return SMESH_OrientedLink( getCornerNode ( x1, y1 ), getCornerNode( x2, y2 ));
246 //!< Return a corner node
247 const SMDS_MeshNode* getCornerNode(bool isXMax, bool isYMax) const
249 return getNode( isXMax ? _index._xSize-1 : 0 , isYMax ? _index._ySize-1 : 0 );
251 const SMDS_MeshElement* getCornerFace(const SMDS_MeshNode* cornerNode) const;
252 //!< True if all blocks this side belongs to have beem found
253 bool isBound() const { return _nbBlocksExpected <= _nbBlocksFound; }
254 //!< Return coordinates of node at XY
255 gp_XYZ getXYZ(int x, int y) const { return SMESH_MeshEditor::TNodeXYZ( getNode( x, y )); }
256 //!< Return gravity center of the four corners and the middle node
261 getXYZ( _index._xSize-1, 0 ) +
262 getXYZ( 0, _index._ySize-1 ) +
263 getXYZ( _index._xSize-1, _index._ySize-1 ) +
264 getXYZ( _index._xSize/2, _index._ySize/2 );
267 //!< Return number of mesh faces
268 int getNbFaces() const { return (_index._xSize-1) * (_index._ySize-1); }
270 //================================================================================
272 * \brief _BlockSide with changed orientation
274 struct _OrientedBlockSide
277 _OrientedIndexer _index;
279 _OrientedBlockSide( _BlockSide* side=0, const int oriFlags=0 ):
280 _side(side), _index(side ? side->_index : _Indexer(), oriFlags ) {}
281 //!< return coordinates by XY
282 gp_XYZ xyz(int x, int y) const
284 return SMESH_MeshEditor::TNodeXYZ( _grid_access_(_side, _index( x, y )) );
286 //!< safely return a node by XY
287 const SMDS_MeshNode* node(int x, int y) const
289 int i = _index( x, y );
290 return ( i < 0 || i >= _side->_grid.size()) ? 0 : _side->_grid[i];
293 SMESH_OrientedLink edge(EQuadEdge edge) const
295 bool x1, y1, x2, y2; getEdgeEnds( edge, x1, y1, x2, y2 );
296 return SMESH_OrientedLink( cornerNode ( x1, y1 ), cornerNode( x2, y2 ));
298 //!< Return a corner node
299 const SMDS_MeshNode* cornerNode(bool isXMax, bool isYMax) const
301 return _grid_access_(_side, _index.corner( isXMax, isYMax ));
303 //!< return its size in nodes
304 int getHoriSize() const { return _index.xSize(); }
305 int getVertSize() const { return _index.ySize(); }
306 //!< True if _side has been initialized
307 operator bool() const { return _side; }
308 //! Direct access to _side
309 const _BlockSide* operator->() const { return _side; }
310 _BlockSide* operator->() { return _side; }
312 //================================================================================
314 * \brief Meshed skin of block
318 _OrientedBlockSide _side[6]; // 6 sides of a sub-block
319 set<const SMDS_MeshNode*> _corners;
321 const _OrientedBlockSide& getSide(int i) const { return _side[i]; }
322 bool setSide( int i, const _OrientedBlockSide& s)
324 if (( _side[i] = s ))
326 _corners.insert( s.cornerNode(0,0));
327 _corners.insert( s.cornerNode(1,0));
328 _corners.insert( s.cornerNode(0,1));
329 _corners.insert( s.cornerNode(1,1));
333 void clear() { for (int i=0;i<6;++i) _side[i]=0; _corners.clear(); }
334 bool hasSide( const _OrientedBlockSide& s) const
336 if ( s ) for (int i=0;i<6;++i) if ( _side[i] && _side[i]._side == s._side ) return true;
339 int nbSides() const { int n=0; for (int i=0;i<6;++i) if ( _side[i] ) ++n; return n; }
340 bool isValid() const;
342 //================================================================================
344 * \brief Skin mesh possibly containing several meshed blocks
350 int findBlocks(SMESH_Mesh& mesh);
351 //!< return i-th block
352 const _Block& getBlock(int i) const { return _blocks[i]; }
353 //!< return error description
354 const SMESH_Comment& error() const { return _error; }
357 bool fillSide( _BlockSide& side,
358 const SMDS_MeshElement* cornerQuad,
359 const SMDS_MeshNode* cornerNode);
360 bool fillRowsUntilCorner(const SMDS_MeshElement* quad,
361 const SMDS_MeshNode* n1,
362 const SMDS_MeshNode* n2,
363 vector<const SMDS_MeshNode*>& verRow1,
364 vector<const SMDS_MeshNode*>& verRow2,
366 _OrientedBlockSide findBlockSide( EBoxSides startBlockSide,
367 EQuadEdge sharedSideEdge1,
368 EQuadEdge sharedSideEdge2,
369 bool withGeometricAnalysis);
370 //!< update own data and data of the side bound to block
371 void setSideBoundToBlock( _BlockSide& side )
373 if ( side._nbBlocksFound++, side.isBound() )
374 for ( int e = 0; e < int(NB_QUAD_SIDES); ++e )
375 _edge2sides[ side.getEdge( (EQuadEdge) e ) ].erase( &side );
377 //!< store reason of error
378 int error(const SMESH_Comment& reason) { _error = reason; return 0; }
380 SMESH_Comment _error;
382 list< _BlockSide > _allSides;
383 vector< _Block > _blocks;
385 //map< const SMDS_MeshNode*, set< _BlockSide* > > _corner2sides;
386 map< SMESH_OrientedLink, set< _BlockSide* > > _edge2sides;
389 //================================================================================
391 * \brief Find and return number of submeshes corresponding to blocks
393 //================================================================================
395 int _Skin::findBlocks(SMESH_Mesh& mesh)
397 SMESHDS_Mesh* meshDS = mesh.GetMeshDS();
399 // Find a node at any block corner
401 SMDS_NodeIteratorPtr nIt = meshDS->nodesIterator(/*idInceasingOrder=*/true);
402 if ( !nIt->more() ) return error("Empty mesh");
404 const SMDS_MeshNode* nCorner = 0;
405 while ( nIt->more() )
407 nCorner = nIt->next();
408 if ( isCornerNode( nCorner ))
416 // --------------------------------------------------------------------
417 // Find all block sides starting from mesh faces sharing the corner node
418 // --------------------------------------------------------------------
420 int nbFacesOnSides = 0;
421 TIDSortedElemSet cornerFaces; // corner faces of found _BlockSide's
422 list< const SMDS_MeshNode* > corners( 1, nCorner );
423 list< const SMDS_MeshNode* >::iterator corner = corners.begin();
424 while ( corner != corners.end() )
426 SMDS_ElemIteratorPtr faceIt = (*corner)->GetInverseElementIterator( SMDSAbs_Face );
427 while ( faceIt->more() )
429 const SMDS_MeshElement* face = faceIt->next();
430 if ( !cornerFaces.insert( face ).second )
431 continue; // already loaded block side
433 if ( !isQuadrangle( face ))
434 return error("Non-quadrangle elements in the input mesh");
436 if ( _allSides.empty() || !_allSides.back()._grid.empty() )
437 _allSides.push_back( _BlockSide() );
439 _BlockSide& side = _allSides.back();
440 if ( !fillSide( side, face, *corner ) )
442 if ( !_error.empty() )
447 for ( int isXMax = 0; isXMax < 2; ++isXMax )
448 for ( int isYMax = 0; isYMax < 2; ++isYMax )
450 const SMDS_MeshNode* nCorner = side.getCornerNode(isXMax,isYMax );
451 corners.push_back( nCorner );
452 cornerFaces.insert( side.getCornerFace( nCorner ));
454 for ( int e = 0; e < int(NB_QUAD_SIDES); ++e )
455 _edge2sides[ side.getEdge( (EQuadEdge) e ) ].insert( &side );
457 nbFacesOnSides += side.getNbFaces();
462 // find block sides of other domains if any
463 if ( corner == corners.end() && nbFacesOnSides < mesh.NbQuadrangles() )
465 while ( nIt->more() )
467 nCorner = nIt->next();
468 if ( isCornerNode( nCorner ))
469 corner = corners.insert( corner, nCorner );
471 nbFacesOnSides = mesh.NbQuadrangles();
475 if ( _allSides.empty() )
477 if ( _allSides.back()._grid.empty() )
478 _allSides.pop_back();
479 _DUMP_("Nb detected sides "<< _allSides.size());
481 // ---------------------------
482 // Organize sides into blocks
483 // ---------------------------
485 // analyse sharing of sides by blocks and sort sides by nb of adjacent sides
486 int nbBlockSides = 0; // total nb of block sides taking into account their sharing
487 multimap<int, _BlockSide* > sortedSides;
489 list < _BlockSide >::iterator sideIt = _allSides.begin();
490 for ( ; sideIt != _allSides.end(); ++sideIt )
492 _BlockSide& side = *sideIt;
493 bool isSharedSide = true;
495 for ( int e = 0; e < int(NB_QUAD_SIDES) && isSharedSide; ++e )
497 int nbAdj = _edge2sides[ side.getEdge( (EQuadEdge) e ) ].size();
499 isSharedSide = ( nbAdj > 2 );
501 side._nbBlocksFound = 0;
502 side._nbBlocksExpected = isSharedSide ? 2 : 1;
503 nbBlockSides += side._nbBlocksExpected;
504 sortedSides.insert( make_pair( nbAdjacent, & side ));
508 // find sides of each block
510 while ( nbBlockSides >= 6 )
512 // get any side not bound to all blocks it belongs to
513 multimap<int, _BlockSide*>::iterator i_side = sortedSides.begin();
514 while ( i_side != sortedSides.end() && i_side->second->isBound())
517 // start searching for block sides from the got side
519 if ( _blocks.empty() || _blocks.back()._side[B_FRONT] )
520 _blocks.resize( _blocks.size() + 1 );
522 _Block& block = _blocks.back();
523 block.setSide( B_FRONT, i_side->second );
524 setSideBoundToBlock( *i_side->second );
527 // edges of adjacent sides of B_FRONT corresponding to front's edges
528 EQuadEdge edgeOfFront[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT };
529 EQuadEdge edgeOfAdj [4] = { Q_BOTTOM, Q_LEFT, Q_BOTTOM, Q_LEFT };
530 // first find all sides detectable w/o advanced analysis,
531 // then repeat the search, which then may pass without advanced analysis
532 for ( int advAnalys = 0; advAnalys < 2; ++advAnalys )
534 for ( int i = 0; (ok || !advAnalys) && i < NB_QUAD_SIDES; ++i )
535 if ( !block._side[i] ) // try to find 4 sides adjacent to front side
536 ok = block.setSide( i, findBlockSide( B_FRONT, edgeOfFront[i],edgeOfAdj[i],advAnalys));
537 if ( ok || !advAnalys)
538 if ( !block._side[B_BACK] && block._side[B_TOP] ) // try to find back side by top one
539 ok = block.setSide( B_BACK, findBlockSide( B_TOP, Q_TOP, Q_TOP, advAnalys ));
540 if ( !advAnalys ) ok = true;
542 ok = block.isValid();
545 // check if just found block is same as one of previously found
547 for ( int i = 1; i < _blocks.size() && !isSame; ++i )
548 isSame = ( block._corners == _blocks[i-1]._corners );
552 // count the found sides
553 _DUMP_(endl << "** Block " << _blocks.size() << " valid: " << block.isValid());
554 for (int i = 0; i < NB_BLOCK_SIDES; ++i )
556 _DUMP_("\tSide "<< SBoxSides[i] <<" "<< block._side[ i ]._side);
557 if ( block._side[ i ] )
559 if ( ok && i != B_FRONT)
561 setSideBoundToBlock( *block._side[ i ]._side );
564 _DUMP_("\t corners "<<
565 block._side[ i ].cornerNode(0,0)->GetID() << ", " <<
566 block._side[ i ].cornerNode(1,0)->GetID() << ", " <<
567 block._side[ i ].cornerNode(1,1)->GetID() << ", " <<
568 block._side[ i ].cornerNode(0,1)->GetID() << ", "<<endl);
572 _DUMP_("\t not found"<<endl);
580 _DUMP_("Nb found blocks "<< nbBlocks <<endl);
582 if ( nbBlocks == 0 && _error.empty() )
588 //================================================================================
590 * \brief Fill block side data starting from its corner quadrangle
592 //================================================================================
594 bool _Skin::fillSide( _BlockSide& side,
595 const SMDS_MeshElement* cornerQuad,
596 const SMDS_MeshNode* nCorner)
598 // Find out size of block side mesured in nodes and by the way find two rows
599 // of nodes in two directions.
602 const SMDS_MeshElement* firstQuad = cornerQuad;
604 // get a node on block edge
605 int iCorner = firstQuad->GetNodeIndex( nCorner );
606 const SMDS_MeshNode* nOnEdge = firstQuad->GetNode( (iCorner+1) % 4);
608 // find out size of block side
609 vector<const SMDS_MeshNode*> horRow1, horRow2, verRow1, verRow2;
610 if ( !fillRowsUntilCorner( firstQuad, nCorner, nOnEdge, horRow1, horRow2, true ) ||
611 !fillRowsUntilCorner( firstQuad, nCorner, nOnEdge, verRow1, verRow2, false ))
613 nbX = horRow1.size(), nbY = verRow1.size();
616 side._index._xSize = horRow1.size();
617 side._index._ySize = verRow1.size();
618 side._grid.resize( side._index.size(), NULL );
620 for ( x = 0; x < horRow1.size(); ++x )
622 side.setNode( x, 0, horRow1[x] );
623 side.setNode( x, 1, horRow2[x] );
625 for ( y = 0; y < verRow1.size(); ++y )
627 side.setNode( 0, y, verRow1[y] );
628 side.setNode( 1, y, verRow2[y] );
631 // Find the rest nodes
633 y = 1; // y of the row to fill
634 TIDSortedElemSet emptySet, avoidSet;
637 // get next firstQuad in the next row of quadrangles
642 // o---o o o o o <- found nodes
645 int i1down, i2down, i2up;
646 const SMDS_MeshNode* n1down = side.getNode( 0, y-1 );
647 const SMDS_MeshNode* n2down = side.getNode( 1, y-1 );
648 avoidSet.clear(); avoidSet.insert( firstQuad );
649 firstQuad = SMESH_MeshEditor::FindFaceInSet( n1down, n2down, emptySet, avoidSet,
651 if ( !isQuadrangle( firstQuad ))
654 const SMDS_MeshNode* n2up = oppositeNode( firstQuad, i1down );
655 avoidSet.clear(); avoidSet.insert( firstQuad );
657 // find the rest nodes in the y-th row by faces in the row
662 const SMDS_MeshElement* quad = SMESH_MeshEditor::FindFaceInSet( n2up, n2down, emptySet,
663 avoidSet, &i2up, &i2down);
664 if ( !isQuadrangle( quad ))
667 n2up = oppositeNode( quad, i2down );
668 n2down = oppositeNode( quad, i2up );
669 avoidSet.clear(); avoidSet.insert( quad );
671 side.setNode( x, y, n2up );
675 // check side validity
677 side.getCornerFace( side.getCornerNode( 0, 0 )) &&
678 side.getCornerFace( side.getCornerNode( 1, 0 )) &&
679 side.getCornerFace( side.getCornerNode( 0, 1 )) &&
680 side.getCornerFace( side.getCornerNode( 1, 1 ));
685 //================================================================================
687 * \brief Try to find a block side adjacent to the given side by given edge
689 //================================================================================
691 _OrientedBlockSide _Skin::findBlockSide( EBoxSides startBlockSide,
692 EQuadEdge sharedSideEdge1,
693 EQuadEdge sharedSideEdge2,
694 bool withGeometricAnalysis)
696 _Block& block = _blocks.back();
697 _OrientedBlockSide& side1 = block._side[ startBlockSide ];
699 // get corner nodes of the given block edge
700 SMESH_OrientedLink edge = side1.edge( sharedSideEdge1 );
701 const SMDS_MeshNode* n1 = edge.node1();
702 const SMDS_MeshNode* n2 = edge.node2();
703 if ( edge._reversed ) swap( n1, n2 );
705 // find all sides sharing both nodes n1 and n2
706 set< _BlockSide* > sidesOnEdge = _edge2sides[ edge ]; // copy a set
708 // exclude loaded sides of block from sidesOnEdge
709 for (int i = 0; i < NB_BLOCK_SIDES; ++i )
710 if ( block._side[ i ] )
711 sidesOnEdge.erase( block._side[ i ]._side );
713 int nbSidesOnEdge = sidesOnEdge.size();
714 _DUMP_("nbSidesOnEdge "<< nbSidesOnEdge << " " << n1->GetID() << "-" << n2->GetID() );
715 if ( nbSidesOnEdge == 0 )
718 _BlockSide* foundSide = 0;
719 if ( nbSidesOnEdge == 1 )
721 foundSide = *sidesOnEdge.begin();
725 set< _BlockSide* >::iterator sideIt = sidesOnEdge.begin();
726 int nbLoadedSides = block.nbSides();
727 if ( nbLoadedSides > 1 )
729 // Find the side having more than 2 corners common with already loaded sides
730 for (; !foundSide && sideIt != sidesOnEdge.end(); ++sideIt )
732 _BlockSide* sideI = *sideIt;
733 int nbCommonCorners =
734 block._corners.count( sideI->getCornerNode(0,0)) +
735 block._corners.count( sideI->getCornerNode(1,0)) +
736 block._corners.count( sideI->getCornerNode(0,1)) +
737 block._corners.count( sideI->getCornerNode(1,1));
738 if ( nbCommonCorners > 2 )
745 if ( !withGeometricAnalysis ) return 0;
747 // Select one of found sides most close to startBlockSide
749 gp_XYZ p1 ( n1->X(),n1->Y(),n1->Z()), p2 (n2->X(),n2->Y(),n2->Z());
750 gp_Vec p1p2( p1, p2 );
752 const SMDS_MeshElement* face1 = side1->getCornerFace( n1 );
753 gp_XYZ p1Op = SMESH_MeshEditor::TNodeXYZ( oppositeNode( face1, face1->GetNodeIndex(n1)));
754 gp_Vec side1Dir( p1, p1Op );
755 gp_Ax2 pln( p1, p1p2, side1Dir ); // plane with normal p1p2 and X dir side1Dir
756 _DUMP_(" Select adjacent for "<< side1._side << " - side dir ("
757 << side1Dir.X() << ", " << side1Dir.Y() << ", " << side1Dir.Z() << ")" );
759 map < double , _BlockSide* > angleOfSide;
760 for (sideIt = sidesOnEdge.begin(); sideIt != sidesOnEdge.end(); ++sideIt )
762 _BlockSide* sideI = *sideIt;
763 const SMDS_MeshElement* faceI = sideI->getCornerFace( n1 );
764 gp_XYZ p1Op = SMESH_MeshEditor::TNodeXYZ( oppositeNode( faceI, faceI->GetNodeIndex(n1)));
765 gp_Vec sideIDir( p1, p1Op );
766 // compute angle of (sideIDir projection to pln) and (X dir of pln)
767 gp_Vec2d sideIDirProj( sideIDir * pln.XDirection(), sideIDir * pln.YDirection());
768 double angle = sideIDirProj.Angle( gp::DX2d() );
769 if ( angle < 0 ) angle += 2 * PI; // angle [0-2*PI]
770 angleOfSide.insert( make_pair( angle, sideI ));
771 _DUMP_(" "<< sideI << " - side dir ("
772 << sideIDir.X() << ", " << sideIDir.Y() << ", " << sideIDir.Z() << ")"
773 << " angle " << angle);
775 if ( nbLoadedSides == 1 )
777 double angF = angleOfSide.begin()->first, angL = angleOfSide.rbegin()->first;
778 if ( angF > PI ) angF = 2*PI - angF;
779 if ( angL > PI ) angL = 2*PI - angL;
780 foundSide = angF < angL ? angleOfSide.begin()->second : angleOfSide.rbegin()->second;
784 gp_XYZ gc(0,0,0); // gravity center of already loaded block sides
785 for (int i = 0; i < NB_BLOCK_SIDES; ++i )
786 if ( block._side[ i ] )
787 gc += block._side[ i ]._side->getGC();
790 gp_Vec gcDir( p1, gc );
791 gp_Vec2d gcDirProj( gcDir * pln.XDirection(), gcDir * pln.YDirection());
792 double gcAngle = gcDirProj.Angle( gp::DX2d() );
793 foundSide = gcAngle < 0 ? angleOfSide.rbegin()->second : angleOfSide.begin()->second;
796 _DUMP_(" selected "<< foundSide );
799 // Orient the found side correctly
801 // corners of found side corresponding to nodes n1 and n2
802 bool xMax1, yMax1, xMax2, yMax2;
803 if ( !getEdgeEnds( sharedSideEdge2, xMax1, yMax1, xMax2, yMax2 ))
804 return error(SMESH_Comment("Internal error at ")<<__FILE__<<":"<<__LINE__),
805 _OrientedBlockSide(0);
807 for ( int ori = 0; ori < _OrientedIndexer::MAX_ORI+1; ++ori )
809 _OrientedBlockSide orientedSide( foundSide, ori );
810 const SMDS_MeshNode* n12 = orientedSide.cornerNode( xMax1, yMax1);
811 const SMDS_MeshNode* n22 = orientedSide.cornerNode( xMax2, yMax2);
812 if ( n1 == n12 && n2 == n22 )
815 error(SMESH_Comment("Failed to orient a block side found by edge ")<<sharedSideEdge1
816 << " of side " << startBlockSide
817 << " of block " << _blocks.size());
821 //================================================================================
823 * \brief: Fill rows (which are actually columns,if !alongN1N2) of nodes starting
824 * from the given quadrangle until another block corner encounters.
825 * n1 and n2 are at bottom of quad, n1 is at block corner.
827 //================================================================================
829 bool _Skin::fillRowsUntilCorner(const SMDS_MeshElement* quad,
830 const SMDS_MeshNode* n1,
831 const SMDS_MeshNode* n2,
832 vector<const SMDS_MeshNode*>& row1,
833 vector<const SMDS_MeshNode*>& row2,
834 const bool alongN1N2 )
836 const SMDS_MeshNode* corner1 = n1;
838 // Store nodes of quad in the rows and find new n1 and n2 to get
839 // the next face so that new n2 is on block edge
840 int i1 = quad->GetNodeIndex( n1 );
841 int i2 = quad->GetNodeIndex( n2 );
842 row1.clear(); row2.clear();
843 row1.push_back( n1 );
846 row1.push_back( n2 );
847 row2.push_back( oppositeNode( quad, i2 ));
848 row2.push_back( n1 = oppositeNode( quad, i1 ));
852 row2.push_back( n2 );
853 row1.push_back( n2 = oppositeNode( quad, i2 ));
854 row2.push_back( n1 = oppositeNode( quad, i1 ));
857 _NodeDescriptor nDesc( row1[1] );
858 if ( nDesc == _NodeDescriptor( row1[0] ))
859 return true; // row of 2 nodes
861 // Find the rest nodes
862 TIDSortedElemSet emptySet, avoidSet;
863 //while ( !isCornerNode( n2 ))
864 while ( nDesc == _NodeDescriptor( n2 ))
866 avoidSet.clear(); avoidSet.insert( quad );
867 quad = SMESH_MeshEditor::FindFaceInSet( n1, n2, emptySet, avoidSet, &i1, &i2 );
868 if ( !isQuadrangle( quad ))
871 row1.push_back( n2 = oppositeNode( quad, i1 ));
872 row2.push_back( n1 = oppositeNode( quad, i2 ));
874 return n1 != corner1;
877 //================================================================================
879 * \brief Return a corner face by a corner node
881 //================================================================================
883 const SMDS_MeshElement* _BlockSide::getCornerFace(const SMDS_MeshNode* cornerNode) const
885 int x, y, isXMax, isYMax, found = 0;
886 for ( isXMax = 0; isXMax < 2; ++isXMax )
888 for ( isYMax = 0; isYMax < 2; ++isYMax )
890 x = isXMax ? _index._xSize-1 : 0;
891 y = isYMax ? _index._ySize-1 : 0;
892 found = ( getNode(x,y) == cornerNode );
897 if ( !found ) return 0;
898 int dx = isXMax ? -1 : +1;
899 int dy = isYMax ? -1 : +1;
900 const SMDS_MeshNode* n1 = getNode(x,y);
901 const SMDS_MeshNode* n2 = getNode(x+dx,y);
902 const SMDS_MeshNode* n3 = getNode(x,y+dy);
903 const SMDS_MeshNode* n4 = getNode(x+dx,y+dy);
904 return SMDS_Mesh::FindFace(n1, n2, n3, n4 );
907 //================================================================================
909 * \brief Checks own validity
911 //================================================================================
913 bool _Block::isValid() const
915 bool ok = ( nbSides() == 6 );
917 // check only corners depending on side selection
918 EBoxSides adjacent[4] = { B_BOTTOM, B_RIGHT, B_TOP, B_LEFT };
919 EQuadEdge edgeAdj [4] = { Q_TOP, Q_RIGHT, Q_TOP, Q_RIGHT };
920 EQuadEdge edgeBack[4] = { Q_BOTTOM, Q_RIGHT, Q_TOP, Q_LEFT };
922 for ( int i=0; ok && i < NB_QUAD_SIDES; ++i )
924 SMESH_OrientedLink eBack = _side[ B_BACK ].edge( edgeBack[i] );
925 SMESH_OrientedLink eAdja = _side[ adjacent[i] ].edge( edgeAdj[i] );
926 ok = ( eBack == eAdja );
937 HEXA_NS::Hexa* _block2Hexa( const _Block& block,
938 HEXA_NS::Document* doc,
939 std::map<HEXA_NS::Vertex*, SMDS_MeshNode*> vertexNode )
941 const SMDS_MeshNode* n000 = block.getSide(B_BOTTOM).cornerNode( 0, 0 );
942 const SMDS_MeshNode* n100 = block.getSide(B_BOTTOM).cornerNode( 1, 0 );
943 const SMDS_MeshNode* n010 = block.getSide(B_BOTTOM).cornerNode( 0, 1 );
944 const SMDS_MeshNode* n110 = block.getSide(B_BOTTOM).cornerNode( 1, 1 );
945 const SMDS_MeshNode* n001 = block.getSide(B_TOP).cornerNode( 0, 0 );
946 const SMDS_MeshNode* n101 = block.getSide(B_TOP).cornerNode( 1, 0 );
947 const SMDS_MeshNode* n011 = block.getSide(B_TOP).cornerNode( 0, 1 );
948 const SMDS_MeshNode* n111 = block.getSide(B_TOP).cornerNode( 1, 1 );
950 list<const SMDS_MeshNode* > nodeFromBlock;
951 nodeFromBlock.push_back(n000);
952 nodeFromBlock.push_back(n100);
953 nodeFromBlock.push_back(n010);
954 nodeFromBlock.push_back(n110);
955 nodeFromBlock.push_back(n001);
956 nodeFromBlock.push_back(n101);
957 nodeFromBlock.push_back(n011);
958 nodeFromBlock.push_back(n111);
959 nodeFromBlock.sort();
962 HEXA_NS::Hexa* hexa = NULL;
963 int nHexa = doc->countHexa();
964 for (int j=0; j <nHexa; ++j ){
965 hexa = doc->getHexa(j);
966 list<const SMDS_MeshNode* > nodeFromHexa;
967 int nVx = hexa->countVertex();
968 for ( int i=0; i <nVx; ++i ){
969 HEXA_NS::Vertex* v = hexa->getVertex(i);
970 const SMDS_MeshNode* n = vertexNode[v];
971 nodeFromHexa.push_back(n);
975 if ( nodeFromBlock == nodeFromHexa ){
976 // std::cout << "OK block match hexa "<< hexa <<" id = "<<hexa->getId()<<std::endl;
979 std::cout << "KO block does not match hexa "<< hexa <<" id = "<<hexa->getId()<<std::endl;
992 //=======================================================================
993 //function : SMESH_HexaFromSkin_3D
995 //=======================================================================
997 // SMESH_HexaFromSkin_3D::SMESH_HexaFromSkin_3D(int hypId, int studyId, SMESH_Gen* gen)
998 // :SMESH_3D_Algo(hypId, studyId, gen)
1000 // MESSAGE("SMESH_HexaFromSkin_3D::SMESH_HexaFromSkin_3D");
1001 // _name = "HexaFromSkin_3D";
1004 SMESH_HexaFromSkin_3D::SMESH_HexaFromSkin_3D(int hypId, int studyId, SMESH_Gen* gen, HEXA_NS::Document* doc)
1005 :SMESH_3D_Algo(hypId, studyId, gen),
1008 MESSAGE("SMESH_HexaFromSkin_3D::SMESH_HexaFromSkin_3D");
1009 _name = "HexaFromSkin_3D";
1013 SMESH_HexaFromSkin_3D::~SMESH_HexaFromSkin_3D()
1015 MESSAGE("SMESH_HexaFromSkin_3D::~SMESH_HexaFromSkin_3D");
1018 //================================================================================
1020 * \brief Main method, which generates hexaheda
1022 //================================================================================
1024 bool SMESH_HexaFromSkin_3D::Compute(SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper)
1027 int nbBlocks = skin.findBlocks(aMesh);
1028 if ( nbBlocks == 0 )
1029 return error( skin.error());
1031 vector< vector< const SMDS_MeshNode* > > columns;
1032 int x, xSize, y, ySize, z, zSize;
1035 for ( int i = 0; i < nbBlocks; ++i )
1037 const _Block& block = skin.getBlock( i );
1039 // ------------------------------------------
1040 // Fill columns of nodes with existing nodes
1041 // ------------------------------------------
1043 xSize = block.getSide(B_BOTTOM).getHoriSize();
1044 ySize = block.getSide(B_BOTTOM).getVertSize();
1045 zSize = block.getSide(B_FRONT ).getVertSize();
1046 int X = xSize - 1, Y = ySize - 1, Z = zSize - 1;
1047 colIndex = _Indexer( xSize, ySize );
1048 columns.resize( colIndex.size() );
1050 // fill node columns by front and back box sides
1051 for ( x = 0; x < xSize; ++x ) {
1052 vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )];
1053 vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )];
1054 column0.resize( zSize );
1055 column1.resize( zSize );
1056 for ( z = 0; z < zSize; ++z ) {
1057 column0[ z ] = block.getSide(B_FRONT).node( x, z );
1058 column1[ z ] = block.getSide(B_BACK) .node( x, z );
1061 // fill node columns by left and right box sides
1062 for ( y = 1; y < ySize-1; ++y ) {
1063 vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )];
1064 vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )];
1065 column0.resize( zSize );
1066 column1.resize( zSize );
1067 for ( z = 0; z < zSize; ++z ) {
1068 column0[ z ] = block.getSide(B_LEFT) .node( y, z );
1069 column1[ z ] = block.getSide(B_RIGHT).node( y, z );
1072 // get nodes from top and bottom box sides
1073 for ( x = 1; x < xSize-1; ++x ) {
1074 for ( y = 1; y < ySize-1; ++y ) {
1075 vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
1076 column.resize( zSize );
1077 column.front() = block.getSide(B_BOTTOM).node( x, y );
1078 column.back() = block.getSide(B_TOP) .node( x, y );
1082 // ----------------------------
1083 // Add internal nodes of a box
1084 // ----------------------------
1085 // projection points of internal nodes on box subshapes by which
1086 // coordinates of internal nodes are computed
1087 vector<gp_XYZ> pointOnShape( SMESH_Block::ID_Shell );
1089 // projections on vertices are constant
1090 pointOnShape[ SMESH_Block::ID_V000 ] = block.getSide(B_BOTTOM).xyz( 0, 0 );
1091 pointOnShape[ SMESH_Block::ID_V100 ] = block.getSide(B_BOTTOM).xyz( X, 0 );
1092 pointOnShape[ SMESH_Block::ID_V010 ] = block.getSide(B_BOTTOM).xyz( 0, Y );
1093 pointOnShape[ SMESH_Block::ID_V110 ] = block.getSide(B_BOTTOM).xyz( X, Y );
1094 pointOnShape[ SMESH_Block::ID_V001 ] = block.getSide(B_TOP).xyz( 0, 0 );
1095 pointOnShape[ SMESH_Block::ID_V101 ] = block.getSide(B_TOP).xyz( X, 0 );
1096 pointOnShape[ SMESH_Block::ID_V011 ] = block.getSide(B_TOP).xyz( 0, Y );
1097 pointOnShape[ SMESH_Block::ID_V111 ] = block.getSide(B_TOP).xyz( X, Y );
1099 for ( x = 1; x < xSize-1; ++x )
1101 gp_XYZ params; // normalized parameters of internal node within a unit box
1102 params.SetCoord( 1, x / double(X) );
1103 for ( y = 1; y < ySize-1; ++y )
1105 params.SetCoord( 2, y / double(Y) );
1106 // column to fill during z loop
1107 vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
1108 // projections on horizontal edges
1109 pointOnShape[ SMESH_Block::ID_Ex00 ] = block.getSide(B_BOTTOM).xyz( x, 0 );
1110 pointOnShape[ SMESH_Block::ID_Ex10 ] = block.getSide(B_BOTTOM).xyz( x, Y );
1111 pointOnShape[ SMESH_Block::ID_E0y0 ] = block.getSide(B_BOTTOM).xyz( 0, y );
1112 pointOnShape[ SMESH_Block::ID_E1y0 ] = block.getSide(B_BOTTOM).xyz( X, y );
1113 pointOnShape[ SMESH_Block::ID_Ex01 ] = block.getSide(B_TOP).xyz( x, 0 );
1114 pointOnShape[ SMESH_Block::ID_Ex11 ] = block.getSide(B_TOP).xyz( x, Y );
1115 pointOnShape[ SMESH_Block::ID_E0y1 ] = block.getSide(B_TOP).xyz( 0, y );
1116 pointOnShape[ SMESH_Block::ID_E1y1 ] = block.getSide(B_TOP).xyz( X, y );
1117 // projections on horizontal sides
1118 pointOnShape[ SMESH_Block::ID_Fxy0 ] = block.getSide(B_BOTTOM).xyz( x, y );
1119 pointOnShape[ SMESH_Block::ID_Fxy1 ] = block.getSide(B_TOP) .xyz( x, y );
1120 for ( z = 1; z < zSize-1; ++z ) // z loop
1122 params.SetCoord( 3, z / double(Z) );
1123 // projections on vertical edges
1124 pointOnShape[ SMESH_Block::ID_E00z ] = block.getSide(B_FRONT).xyz( 0, z );
1125 pointOnShape[ SMESH_Block::ID_E10z ] = block.getSide(B_FRONT).xyz( X, z );
1126 pointOnShape[ SMESH_Block::ID_E01z ] = block.getSide(B_BACK).xyz( 0, z );
1127 pointOnShape[ SMESH_Block::ID_E11z ] = block.getSide(B_BACK).xyz( X, z );
1128 // projections on vertical sides
1129 pointOnShape[ SMESH_Block::ID_Fx0z ] = block.getSide(B_FRONT).xyz( x, z );
1130 pointOnShape[ SMESH_Block::ID_Fx1z ] = block.getSide(B_BACK) .xyz( x, z );
1131 pointOnShape[ SMESH_Block::ID_F0yz ] = block.getSide(B_LEFT) .xyz( y, z );
1132 pointOnShape[ SMESH_Block::ID_F1yz ] = block.getSide(B_RIGHT).xyz( y, z );
1134 // compute internal node coordinates
1136 SMESH_Block::ShellPoint( params, pointOnShape, coords );
1137 column[ z ] = aHelper->AddNode( coords.X(), coords.Y(), coords.Z() );
1141 //cout << "----------------------------------------------------------------------"<<endl;
1142 //for ( int id = SMESH_Block::ID_V000; id < SMESH_Block::ID_Shell; ++id)
1144 // gp_XYZ p = pointOnShape[ id ];
1145 // SMESH_Block::DumpShapeID( id,cout)<<" ( "<<p.X()<<", "<<p.Y()<<", "<<p.Z()<<" )"<<endl;
1147 //cout << "Params: ( "<< params.X()<<", "<<params.Y()<<", "<<params.Z()<<" )"<<endl;
1148 //cout << "coords: ( "<< coords.X()<<", "<<coords.Y()<<", "<<coords.Z()<<" )"<<endl;
1157 // find out orientation
1158 const SMDS_MeshNode* n000 = block.getSide(B_BOTTOM).cornerNode( 0, 0 );
1159 const SMDS_MeshNode* n100 = block.getSide(B_BOTTOM).cornerNode( 1, 0 );
1160 const SMDS_MeshNode* n010 = block.getSide(B_BOTTOM).cornerNode( 0, 1 );
1161 const SMDS_MeshNode* n110 = block.getSide(B_BOTTOM).cornerNode( 1, 1 );
1162 const SMDS_MeshNode* n001 = block.getSide(B_TOP).cornerNode( 0, 0 );
1163 const SMDS_MeshNode* n101 = block.getSide(B_TOP).cornerNode( 1, 0 );
1164 const SMDS_MeshNode* n011 = block.getSide(B_TOP).cornerNode( 0, 1 );
1165 const SMDS_MeshNode* n111 = block.getSide(B_TOP).cornerNode( 1, 1 );
1166 SMDS_VolumeOfNodes probeVolume (n000,n010,n110,n100,
1167 n001,n011,n111,n101);
1168 bool isForw = SMDS_VolumeTool( &probeVolume ).IsForward();
1171 for ( x = 0; x < xSize-1; ++x ) {
1172 for ( y = 0; y < ySize-1; ++y ) {
1173 vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x, y )];
1174 vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )];
1175 vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )];
1176 vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )];
1177 // bottom face normal of a hexa mush point outside the volume
1179 for ( z = 0; z < zSize-1; ++z )
1180 aHelper->AddVolume(col00[z], col01[z], col11[z], col10[z],
1181 col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
1183 for ( z = 0; z < zSize-1; ++z )
1184 aHelper->AddVolume(col00[z], col10[z], col11[z], col01[z],
1185 col00[z+1], col10[z+1], col11[z+1], col01[z+1]);
1194 //================================================================================
1196 * \brief Main method, which generates hexaheda
1198 //================================================================================
1199 bool SMESH_HexaFromSkin_3D::Compute( SMESH_Mesh & aMesh, SMESH_MesherHelper* aHelper,
1200 std::map<HEXA_NS::Hexa*, SMESH_HexaBlocks::SMESHVolumes>& volumesOnHexa,
1201 std::map<HEXA_NS::Vertex*, SMDS_MeshNode*> vertexNode )
1203 if(MYDEBUG) MESSAGE("SMESH_HexaFromSkin_3D::Compute BEGIN");
1205 int nbBlocks = skin.findBlocks(aMesh);
1206 if ( nbBlocks == 0 )
1207 return error( skin.error());
1209 vector< vector< const SMDS_MeshNode* > > columns;
1210 int x, xSize, y, ySize, z, zSize;
1213 for ( int i = 0; i < nbBlocks; ++i )
1215 const _Block& block = skin.getBlock( i );
1217 // ------------------------------------------
1218 // Fill columns of nodes with existing nodes
1219 // ------------------------------------------
1221 xSize = block.getSide(B_BOTTOM).getHoriSize();
1222 ySize = block.getSide(B_BOTTOM).getVertSize();
1223 zSize = block.getSide(B_FRONT ).getVertSize();
1224 int X = xSize - 1, Y = ySize - 1, Z = zSize - 1;
1225 colIndex = _Indexer( xSize, ySize );
1226 columns.resize( colIndex.size() );
1228 // fill node columns by front and back box sides
1229 for ( x = 0; x < xSize; ++x ) {
1230 vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( x, 0 )];
1231 vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( x, Y )];
1232 column0.resize( zSize );
1233 column1.resize( zSize );
1234 for ( z = 0; z < zSize; ++z ) {
1235 column0[ z ] = block.getSide(B_FRONT).node( x, z );
1236 column1[ z ] = block.getSide(B_BACK) .node( x, z );
1239 // fill node columns by left and right box sides
1240 for ( y = 1; y < ySize-1; ++y ) {
1241 vector< const SMDS_MeshNode* >& column0 = columns[ colIndex( 0, y )];
1242 vector< const SMDS_MeshNode* >& column1 = columns[ colIndex( X, y )];
1243 column0.resize( zSize );
1244 column1.resize( zSize );
1245 for ( z = 0; z < zSize; ++z ) {
1246 column0[ z ] = block.getSide(B_LEFT) .node( y, z );
1247 column1[ z ] = block.getSide(B_RIGHT).node( y, z );
1250 // get nodes from top and bottom box sides
1251 for ( x = 1; x < xSize-1; ++x ) {
1252 for ( y = 1; y < ySize-1; ++y ) {
1253 vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
1254 column.resize( zSize );
1255 column.front() = block.getSide(B_BOTTOM).node( x, y );
1256 column.back() = block.getSide(B_TOP) .node( x, y );
1260 // ----------------------------
1261 // Add internal nodes of a box
1262 // ----------------------------
1263 // projection points of internal nodes on box subshapes by which
1264 // coordinates of internal nodes are computed
1265 vector<gp_XYZ> pointOnShape( SMESH_Block::ID_Shell );
1267 // projections on vertices are constant
1268 pointOnShape[ SMESH_Block::ID_V000 ] = block.getSide(B_BOTTOM).xyz( 0, 0 );
1269 pointOnShape[ SMESH_Block::ID_V100 ] = block.getSide(B_BOTTOM).xyz( X, 0 );
1270 pointOnShape[ SMESH_Block::ID_V010 ] = block.getSide(B_BOTTOM).xyz( 0, Y );
1271 pointOnShape[ SMESH_Block::ID_V110 ] = block.getSide(B_BOTTOM).xyz( X, Y );
1272 pointOnShape[ SMESH_Block::ID_V001 ] = block.getSide(B_TOP).xyz( 0, 0 );
1273 pointOnShape[ SMESH_Block::ID_V101 ] = block.getSide(B_TOP).xyz( X, 0 );
1274 pointOnShape[ SMESH_Block::ID_V011 ] = block.getSide(B_TOP).xyz( 0, Y );
1275 pointOnShape[ SMESH_Block::ID_V111 ] = block.getSide(B_TOP).xyz( X, Y );
1277 for ( x = 1; x < xSize-1; ++x )
1279 gp_XYZ params; // normalized parameters of internal node within a unit box
1280 params.SetCoord( 1, x / double(X) );
1281 for ( y = 1; y < ySize-1; ++y )
1283 params.SetCoord( 2, y / double(Y) );
1284 // column to fill during z loop
1285 vector< const SMDS_MeshNode* >& column = columns[ colIndex( x, y )];
1286 // projections on horizontal edges
1287 pointOnShape[ SMESH_Block::ID_Ex00 ] = block.getSide(B_BOTTOM).xyz( x, 0 );
1288 pointOnShape[ SMESH_Block::ID_Ex10 ] = block.getSide(B_BOTTOM).xyz( x, Y );
1289 pointOnShape[ SMESH_Block::ID_E0y0 ] = block.getSide(B_BOTTOM).xyz( 0, y );
1290 pointOnShape[ SMESH_Block::ID_E1y0 ] = block.getSide(B_BOTTOM).xyz( X, y );
1291 pointOnShape[ SMESH_Block::ID_Ex01 ] = block.getSide(B_TOP).xyz( x, 0 );
1292 pointOnShape[ SMESH_Block::ID_Ex11 ] = block.getSide(B_TOP).xyz( x, Y );
1293 pointOnShape[ SMESH_Block::ID_E0y1 ] = block.getSide(B_TOP).xyz( 0, y );
1294 pointOnShape[ SMESH_Block::ID_E1y1 ] = block.getSide(B_TOP).xyz( X, y );
1295 // projections on horizontal sides
1296 pointOnShape[ SMESH_Block::ID_Fxy0 ] = block.getSide(B_BOTTOM).xyz( x, y );
1297 pointOnShape[ SMESH_Block::ID_Fxy1 ] = block.getSide(B_TOP) .xyz( x, y );
1298 for ( z = 1; z < zSize-1; ++z ) // z loop
1300 params.SetCoord( 3, z / double(Z) );
1301 // projections on vertical edges
1302 pointOnShape[ SMESH_Block::ID_E00z ] = block.getSide(B_FRONT).xyz( 0, z );
1303 pointOnShape[ SMESH_Block::ID_E10z ] = block.getSide(B_FRONT).xyz( X, z );
1304 pointOnShape[ SMESH_Block::ID_E01z ] = block.getSide(B_BACK).xyz( 0, z );
1305 pointOnShape[ SMESH_Block::ID_E11z ] = block.getSide(B_BACK).xyz( X, z );
1306 // projections on vertical sides
1307 pointOnShape[ SMESH_Block::ID_Fx0z ] = block.getSide(B_FRONT).xyz( x, z );
1308 pointOnShape[ SMESH_Block::ID_Fx1z ] = block.getSide(B_BACK) .xyz( x, z );
1309 pointOnShape[ SMESH_Block::ID_F0yz ] = block.getSide(B_LEFT) .xyz( y, z );
1310 pointOnShape[ SMESH_Block::ID_F1yz ] = block.getSide(B_RIGHT).xyz( y, z );
1312 // compute internal node coordinates
1314 SMESH_Block::ShellPoint( params, pointOnShape, coords );
1315 column[ z ] = aHelper->AddNode( coords.X(), coords.Y(), coords.Z() );
1319 //cout << "----------------------------------------------------------------------"<<endl;
1320 //for ( int id = SMESH_Block::ID_V000; id < SMESH_Block::ID_Shell; ++id)
1322 // gp_XYZ p = pointOnShape[ id ];
1323 // SMESH_Block::DumpShapeID( id,cout)<<" ( "<<p.X()<<", "<<p.Y()<<", "<<p.Z()<<" )"<<endl;
1325 //cout << "Params: ( "<< params.X()<<", "<<params.Y()<<", "<<params.Z()<<" )"<<endl;
1326 //cout << "coords: ( "<< coords.X()<<", "<<coords.Y()<<", "<<coords.Z()<<" )"<<endl;
1335 // find out orientation
1336 const SMDS_MeshNode* n000 = block.getSide(B_BOTTOM).cornerNode( 0, 0 );
1337 const SMDS_MeshNode* n100 = block.getSide(B_BOTTOM).cornerNode( 1, 0 );
1338 const SMDS_MeshNode* n010 = block.getSide(B_BOTTOM).cornerNode( 0, 1 );
1339 const SMDS_MeshNode* n110 = block.getSide(B_BOTTOM).cornerNode( 1, 1 );
1340 const SMDS_MeshNode* n001 = block.getSide(B_TOP).cornerNode( 0, 0 );
1341 const SMDS_MeshNode* n101 = block.getSide(B_TOP).cornerNode( 1, 0 );
1342 const SMDS_MeshNode* n011 = block.getSide(B_TOP).cornerNode( 0, 1 );
1343 const SMDS_MeshNode* n111 = block.getSide(B_TOP).cornerNode( 1, 1 );
1344 SMDS_VolumeOfNodes probeVolume (n000,n010,n110,n100,
1345 n001,n011,n111,n101);
1346 bool isForw = SMDS_VolumeTool( &probeVolume ).IsForward();
1349 SMESH_HexaBlocks::SMESHVolumes volumesOnBlock; //Groups creation
1351 for ( x = 0; x < xSize-1; ++x ) {
1352 for ( y = 0; y < ySize-1; ++y ) {
1353 vector< const SMDS_MeshNode* >& col00 = columns[ colIndex( x, y )];
1354 vector< const SMDS_MeshNode* >& col10 = columns[ colIndex( x+1, y )];
1355 vector< const SMDS_MeshNode* >& col01 = columns[ colIndex( x, y+1 )];
1356 vector< const SMDS_MeshNode* >& col11 = columns[ colIndex( x+1, y+1 )];
1357 // bottom face normal of a hexa mush point outside the volume
1359 for ( z = 0; z < zSize-1; ++z ){
1360 SMDS_MeshVolume* newVolume =
1361 aHelper->AddVolume(col00[z], col01[z], col11[z], col10[z],
1362 col00[z+1], col01[z+1], col11[z+1], col10[z+1]);
1363 volumesOnBlock.push_back( newVolume );
1366 for ( z = 0; z < zSize-1; ++z ){
1367 SMDS_MeshVolume* newVolume =
1368 aHelper->AddVolume(col00[z], col10[z], col11[z], col01[z],
1369 col00[z+1], col10[z+1], col11[z+1], col01[z+1]);
1370 volumesOnBlock.push_back( newVolume );
1374 // std::cout << "block i = " << i << std::endl;
1375 HEXA_NS::Hexa* currentHexa = _block2Hexa( block, _doc, vertexNode );
1376 if ( currentHexa != NULL ){
1377 // std::cout<<"===== found ->"<<currentHexa<<" for block "<<i<<std::endl;
1378 if ( volumesOnHexa.count(currentHexa)==0 ) {
1379 // std::cout<<"added!! "<<std::endl;
1380 volumesOnHexa[currentHexa] = volumesOnBlock;
1382 // std::cout<<"already !! "<<std::endl;
1385 // std::cout<<"===== not found ->"<<currentHexa<<" for block "<<i<<std::endl;
1390 if(MYDEBUG) MESSAGE("SMESH_HexaFromSkin_3D::Compute END");
1402 //================================================================================
1404 * \brief Evaluate nb of hexa
1406 //================================================================================
1408 bool SMESH_HexaFromSkin_3D::Evaluate(SMESH_Mesh & aMesh,
1409 const TopoDS_Shape & aShape,
1410 MapShapeNbElems& aResMap)
1413 int nbBlocks = skin.findBlocks(aMesh);
1414 if ( nbBlocks == 0 )
1415 return error( skin.error());
1417 bool secondOrder = aMesh.NbFaces( ORDER_QUADRATIC );
1419 int entity = secondOrder ? SMDSEntity_Quad_Hexa : SMDSEntity_Hexa;
1420 vector<int>& nbByType = aResMap[ aMesh.GetSubMesh( aShape )];
1421 if ( entity >= nbByType.size() )
1422 nbByType.resize( SMDSEntity_Last, 0 );
1424 for ( int i = 0; i < nbBlocks; ++i )
1426 const _Block& block = skin.getBlock( i );
1428 int nbX = block.getSide(B_BOTTOM).getHoriSize();
1429 int nbY = block.getSide(B_BOTTOM).getVertSize();
1430 int nbZ = block.getSide(B_FRONT ).getVertSize();
1432 int nbHexa = (nbX-1) * (nbY-1) * (nbZ-1);
1433 int nbNodes = (nbX-2) * (nbY-2) * (nbZ-2);
1436 (nbX-2) * (nbY-2) * (nbZ-1) +
1437 (nbX-2) * (nbY-1) * (nbZ-2) +
1438 (nbX-1) * (nbY-2) * (nbZ-2);
1441 nbByType[ entity ] += nbHexa;
1442 nbByType[ SMDSEntity_Node ] += nbNodes;
1448 //================================================================================
1450 * \brief Abstract method must be defined but does nothing
1452 //================================================================================
1454 bool SMESH_HexaFromSkin_3D::CheckHypothesis(SMESH_Mesh&, const TopoDS_Shape&,
1455 Hypothesis_Status& aStatus)
1457 aStatus = SMESH_Hypothesis::HYP_OK;
1461 //================================================================================
1463 * \brief Abstract method must be defined but just reports an error as this
1464 * algo is not intended to work with shapes
1466 //================================================================================
1468 bool SMESH_HexaFromSkin_3D::Compute(SMESH_Mesh&, const TopoDS_Shape&)
1470 return error("Algorithm can't work with geometrical shapes");