1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
27 #include "SMESH_MeshEditor.hxx"
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_MesherHelper.hxx"
44 #include "SMESH_OctreeNode.hxx"
45 #include "SMESH_Group.hxx"
47 #include "utilities.h"
49 #include <BRep_Tool.hxx>
51 #include <Extrema_GenExtPS.hxx>
52 #include <Extrema_POnSurf.hxx>
53 #include <Geom2d_Curve.hxx>
54 #include <GeomAdaptor_Surface.hxx>
55 #include <Geom_Curve.hxx>
56 #include <Geom_Surface.hxx>
57 #include <TColStd_ListOfInteger.hxx>
59 #include <TopExp_Explorer.hxx>
60 #include <TopTools_ListIteratorOfListOfShape.hxx>
61 #include <TopTools_ListOfShape.hxx>
62 #include <TopTools_SequenceOfShape.hxx>
64 #include <TopoDS_Face.hxx>
70 #include <gp_Trsf.hxx>
79 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
82 using namespace SMESH::Controls;
84 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
85 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
86 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> > TNodeOfNodeVecMap;
87 //typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr;
88 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> > TElemOfVecOfMapNodesMap;
90 struct TNodeXYZ : public gp_XYZ {
91 TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
94 //=======================================================================
95 //function : SMESH_MeshEditor
97 //=======================================================================
99 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
100 :myMesh( theMesh ) // theMesh may be NULL
104 //=======================================================================
108 //=======================================================================
111 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
112 const SMDSAbs_ElementType type,
116 SMDS_MeshElement* e = 0;
117 int nbnode = node.size();
118 SMESHDS_Mesh* mesh = GetMeshDS();
122 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
123 else e = mesh->AddEdge (node[0], node[1] );
124 else if ( nbnode == 3 )
125 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
126 else e = mesh->AddEdge (node[0], node[1], node[2] );
131 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
132 else e = mesh->AddFace (node[0], node[1], node[2] );
133 else if (nbnode == 4)
134 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
135 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
136 else if (nbnode == 6)
137 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
138 node[4], node[5], ID);
139 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
141 else if (nbnode == 8)
142 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
143 node[4], node[5], node[6], node[7], ID);
144 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
145 node[4], node[5], node[6], node[7] );
147 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
148 else e = mesh->AddPolygonalFace (node );
154 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
155 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
156 else if (nbnode == 5)
157 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
159 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
161 else if (nbnode == 6)
162 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
163 node[4], node[5], ID);
164 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
166 else if (nbnode == 8)
167 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
168 node[4], node[5], node[6], node[7], ID);
169 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
170 node[4], node[5], node[6], node[7] );
171 else if (nbnode == 10)
172 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173 node[4], node[5], node[6], node[7],
174 node[8], node[9], ID);
175 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
176 node[4], node[5], node[6], node[7],
178 else if (nbnode == 13)
179 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180 node[4], node[5], node[6], node[7],
181 node[8], node[9], node[10],node[11],
183 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
184 node[4], node[5], node[6], node[7],
185 node[8], node[9], node[10],node[11],
187 else if (nbnode == 15)
188 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7],
190 node[8], node[9], node[10],node[11],
191 node[12],node[13],node[14],ID);
192 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
193 node[4], node[5], node[6], node[7],
194 node[8], node[9], node[10],node[11],
195 node[12],node[13],node[14] );
196 else if (nbnode == 20)
197 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
198 node[4], node[5], node[6], node[7],
199 node[8], node[9], node[10],node[11],
200 node[12],node[13],node[14],node[15],
201 node[16],node[17],node[18],node[19],ID);
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
205 node[12],node[13],node[14],node[15],
206 node[16],node[17],node[18],node[19] );
212 //=======================================================================
216 //=======================================================================
218 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
219 const SMDSAbs_ElementType type,
223 vector<const SMDS_MeshNode*> nodes;
224 nodes.reserve( nodeIDs.size() );
225 vector<int>::const_iterator id = nodeIDs.begin();
226 while ( id != nodeIDs.end() ) {
227 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
228 nodes.push_back( node );
232 return AddElement( nodes, type, isPoly, ID );
235 //=======================================================================
237 //purpose : Remove a node or an element.
238 // Modify a compute state of sub-meshes which become empty
239 //=======================================================================
241 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
244 myLastCreatedElems.Clear();
245 myLastCreatedNodes.Clear();
247 SMESHDS_Mesh* aMesh = GetMeshDS();
248 set< SMESH_subMesh *> smmap;
250 list<int>::const_iterator it = theIDs.begin();
251 for ( ; it != theIDs.end(); it++ ) {
252 const SMDS_MeshElement * elem;
254 elem = aMesh->FindNode( *it );
256 elem = aMesh->FindElement( *it );
260 // Notify VERTEX sub-meshes about modification
262 const SMDS_MeshNode* node = cast2Node( elem );
263 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
264 if ( int aShapeID = node->GetPosition()->GetShapeId() )
265 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
268 // Find sub-meshes to notify about modification
269 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
270 // while ( nodeIt->more() ) {
271 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
272 // const SMDS_PositionPtr& aPosition = node->GetPosition();
273 // if ( aPosition.get() ) {
274 // if ( int aShapeID = aPosition->GetShapeId() ) {
275 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
276 // smmap.insert( sm );
283 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
285 aMesh->RemoveElement( elem );
288 // Notify sub-meshes about modification
289 if ( !smmap.empty() ) {
290 set< SMESH_subMesh *>::iterator smIt;
291 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
292 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
295 // // Check if the whole mesh becomes empty
296 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
297 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
302 //=======================================================================
303 //function : FindShape
304 //purpose : Return an index of the shape theElem is on
305 // or zero if a shape not found
306 //=======================================================================
308 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
310 myLastCreatedElems.Clear();
311 myLastCreatedNodes.Clear();
313 SMESHDS_Mesh * aMesh = GetMeshDS();
314 if ( aMesh->ShapeToMesh().IsNull() )
317 if ( theElem->GetType() == SMDSAbs_Node ) {
318 const SMDS_PositionPtr& aPosition =
319 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
320 if ( aPosition.get() )
321 return aPosition->GetShapeId();
326 TopoDS_Shape aShape; // the shape a node is on
327 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
328 while ( nodeIt->more() ) {
329 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
330 const SMDS_PositionPtr& aPosition = node->GetPosition();
331 if ( aPosition.get() ) {
332 int aShapeID = aPosition->GetShapeId();
333 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
335 if ( sm->Contains( theElem ))
337 if ( aShape.IsNull() )
338 aShape = aMesh->IndexToShape( aShapeID );
341 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
346 // None of nodes is on a proper shape,
347 // find the shape among ancestors of aShape on which a node is
348 if ( aShape.IsNull() ) {
349 //MESSAGE ("::FindShape() - NONE node is on shape")
352 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
353 for ( ; ancIt.More(); ancIt.Next() ) {
354 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
355 if ( sm && sm->Contains( theElem ))
356 return aMesh->ShapeToIndex( ancIt.Value() );
359 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
363 //=======================================================================
364 //function : IsMedium
366 //=======================================================================
368 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
369 const SMDSAbs_ElementType typeToCheck)
371 bool isMedium = false;
372 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
373 while (it->more() && !isMedium ) {
374 const SMDS_MeshElement* elem = it->next();
375 isMedium = elem->IsMediumNode(node);
380 //=======================================================================
381 //function : ShiftNodesQuadTria
383 // Shift nodes in the array corresponded to quadratic triangle
384 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
385 //=======================================================================
386 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
388 const SMDS_MeshNode* nd1 = aNodes[0];
389 aNodes[0] = aNodes[1];
390 aNodes[1] = aNodes[2];
392 const SMDS_MeshNode* nd2 = aNodes[3];
393 aNodes[3] = aNodes[4];
394 aNodes[4] = aNodes[5];
398 //=======================================================================
399 //function : GetNodesFromTwoTria
401 // Shift nodes in the array corresponded to quadratic triangle
402 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
403 //=======================================================================
404 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
405 const SMDS_MeshElement * theTria2,
406 const SMDS_MeshNode* N1[],
407 const SMDS_MeshNode* N2[])
409 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
412 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
415 if(it->more()) return false;
416 it = theTria2->nodesIterator();
419 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
422 if(it->more()) return false;
424 int sames[3] = {-1,-1,-1};
436 if(nbsames!=2) return false;
438 ShiftNodesQuadTria(N1);
440 ShiftNodesQuadTria(N1);
443 i = sames[0] + sames[1] + sames[2];
445 ShiftNodesQuadTria(N2);
447 // now we receive following N1 and N2 (using numeration as above image)
448 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
449 // i.e. first nodes from both arrays determ new diagonal
453 //=======================================================================
454 //function : InverseDiag
455 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
456 // but having other common link.
457 // Return False if args are improper
458 //=======================================================================
460 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
461 const SMDS_MeshElement * theTria2 )
463 myLastCreatedElems.Clear();
464 myLastCreatedNodes.Clear();
466 if (!theTria1 || !theTria2)
469 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
470 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
473 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
474 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
478 // put nodes in array and find out indices of the same ones
479 const SMDS_MeshNode* aNodes [6];
480 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
482 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
483 while ( it->more() ) {
484 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
486 if ( i > 2 ) // theTria2
487 // find same node of theTria1
488 for ( int j = 0; j < 3; j++ )
489 if ( aNodes[ i ] == aNodes[ j ]) {
498 return false; // theTria1 is not a triangle
499 it = theTria2->nodesIterator();
501 if ( i == 6 && it->more() )
502 return false; // theTria2 is not a triangle
505 // find indices of 1,2 and of A,B in theTria1
506 int iA = 0, iB = 0, i1 = 0, i2 = 0;
507 for ( i = 0; i < 6; i++ ) {
508 if ( sameInd [ i ] == 0 )
515 // nodes 1 and 2 should not be the same
516 if ( aNodes[ i1 ] == aNodes[ i2 ] )
520 aNodes[ iA ] = aNodes[ i2 ];
522 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
524 //MESSAGE( theTria1 << theTria2 );
526 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
527 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
529 //MESSAGE( theTria1 << theTria2 );
533 } // end if(F1 && F2)
535 // check case of quadratic faces
536 const SMDS_QuadraticFaceOfNodes* QF1 =
537 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
538 if(!QF1) return false;
539 const SMDS_QuadraticFaceOfNodes* QF2 =
540 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
541 if(!QF2) return false;
544 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
545 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
553 const SMDS_MeshNode* N1 [6];
554 const SMDS_MeshNode* N2 [6];
555 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
557 // now we receive following N1 and N2 (using numeration as above image)
558 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
559 // i.e. first nodes from both arrays determ new diagonal
561 const SMDS_MeshNode* N1new [6];
562 const SMDS_MeshNode* N2new [6];
575 // replaces nodes in faces
576 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
577 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
582 //=======================================================================
583 //function : findTriangles
584 //purpose : find triangles sharing theNode1-theNode2 link
585 //=======================================================================
587 static bool findTriangles(const SMDS_MeshNode * theNode1,
588 const SMDS_MeshNode * theNode2,
589 const SMDS_MeshElement*& theTria1,
590 const SMDS_MeshElement*& theTria2)
592 if ( !theNode1 || !theNode2 ) return false;
594 theTria1 = theTria2 = 0;
596 set< const SMDS_MeshElement* > emap;
597 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
599 const SMDS_MeshElement* elem = it->next();
600 if ( elem->NbNodes() == 3 )
603 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
605 const SMDS_MeshElement* elem = it->next();
606 if ( emap.find( elem ) != emap.end() )
608 // theTria1 must be element with minimum ID
609 if( theTria1->GetID() < elem->GetID() ) {
622 return ( theTria1 && theTria2 );
625 //=======================================================================
626 //function : InverseDiag
627 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
628 // with ones built on the same 4 nodes but having other common link.
629 // Return false if proper faces not found
630 //=======================================================================
632 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
633 const SMDS_MeshNode * theNode2)
635 myLastCreatedElems.Clear();
636 myLastCreatedNodes.Clear();
638 MESSAGE( "::InverseDiag()" );
640 const SMDS_MeshElement *tr1, *tr2;
641 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
644 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
645 //if (!F1) return false;
646 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
647 //if (!F2) return false;
650 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
651 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
655 // put nodes in array
656 // and find indices of 1,2 and of A in tr1 and of B in tr2
657 int i, iA1 = 0, i1 = 0;
658 const SMDS_MeshNode* aNodes1 [3];
659 SMDS_ElemIteratorPtr it;
660 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
661 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
662 if ( aNodes1[ i ] == theNode1 )
663 iA1 = i; // node A in tr1
664 else if ( aNodes1[ i ] != theNode2 )
668 const SMDS_MeshNode* aNodes2 [3];
669 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
670 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
671 if ( aNodes2[ i ] == theNode2 )
672 iB2 = i; // node B in tr2
673 else if ( aNodes2[ i ] != theNode1 )
677 // nodes 1 and 2 should not be the same
678 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
682 aNodes1[ iA1 ] = aNodes2[ i2 ];
684 aNodes2[ iB2 ] = aNodes1[ i1 ];
686 //MESSAGE( tr1 << tr2 );
688 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
689 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
691 //MESSAGE( tr1 << tr2 );
696 // check case of quadratic faces
697 const SMDS_QuadraticFaceOfNodes* QF1 =
698 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
699 if(!QF1) return false;
700 const SMDS_QuadraticFaceOfNodes* QF2 =
701 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
702 if(!QF2) return false;
703 return InverseDiag(tr1,tr2);
706 //=======================================================================
707 //function : getQuadrangleNodes
708 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
709 // fusion of triangles tr1 and tr2 having shared link on
710 // theNode1 and theNode2
711 //=======================================================================
713 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
714 const SMDS_MeshNode * theNode1,
715 const SMDS_MeshNode * theNode2,
716 const SMDS_MeshElement * tr1,
717 const SMDS_MeshElement * tr2 )
719 if( tr1->NbNodes() != tr2->NbNodes() )
721 // find the 4-th node to insert into tr1
722 const SMDS_MeshNode* n4 = 0;
723 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
725 while ( !n4 && i<3 ) {
726 const SMDS_MeshNode * n = cast2Node( it->next() );
728 bool isDiag = ( n == theNode1 || n == theNode2 );
732 // Make an array of nodes to be in a quadrangle
733 int iNode = 0, iFirstDiag = -1;
734 it = tr1->nodesIterator();
737 const SMDS_MeshNode * n = cast2Node( it->next() );
739 bool isDiag = ( n == theNode1 || n == theNode2 );
741 if ( iFirstDiag < 0 )
743 else if ( iNode - iFirstDiag == 1 )
744 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
746 else if ( n == n4 ) {
747 return false; // tr1 and tr2 should not have all the same nodes
749 theQuadNodes[ iNode++ ] = n;
751 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
752 theQuadNodes[ iNode ] = n4;
757 //=======================================================================
758 //function : DeleteDiag
759 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
760 // with a quadrangle built on the same 4 nodes.
761 // Return false if proper faces not found
762 //=======================================================================
764 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
765 const SMDS_MeshNode * theNode2)
767 myLastCreatedElems.Clear();
768 myLastCreatedNodes.Clear();
770 MESSAGE( "::DeleteDiag()" );
772 const SMDS_MeshElement *tr1, *tr2;
773 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
776 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
777 //if (!F1) return false;
778 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
779 //if (!F2) return false;
782 const SMDS_MeshNode* aNodes [ 4 ];
783 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
786 //MESSAGE( endl << tr1 << tr2 );
788 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
789 myLastCreatedElems.Append(tr1);
790 GetMeshDS()->RemoveElement( tr2 );
792 //MESSAGE( endl << tr1 );
797 // check case of quadratic faces
798 const SMDS_QuadraticFaceOfNodes* QF1 =
799 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
800 if(!QF1) return false;
801 const SMDS_QuadraticFaceOfNodes* QF2 =
802 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
803 if(!QF2) return false;
806 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
807 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
815 const SMDS_MeshNode* N1 [6];
816 const SMDS_MeshNode* N2 [6];
817 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
819 // now we receive following N1 and N2 (using numeration as above image)
820 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
821 // i.e. first nodes from both arrays determ new diagonal
823 const SMDS_MeshNode* aNodes[8];
833 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
834 myLastCreatedElems.Append(tr1);
835 GetMeshDS()->RemoveElement( tr2 );
837 // remove middle node (9)
838 GetMeshDS()->RemoveNode( N1[4] );
843 //=======================================================================
844 //function : Reorient
845 //purpose : Reverse theElement orientation
846 //=======================================================================
848 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
850 myLastCreatedElems.Clear();
851 myLastCreatedNodes.Clear();
855 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
856 if ( !it || !it->more() )
859 switch ( theElem->GetType() ) {
863 if(!theElem->IsQuadratic()) {
864 int i = theElem->NbNodes();
865 vector<const SMDS_MeshNode*> aNodes( i );
867 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
868 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
871 // quadratic elements
872 if(theElem->GetType()==SMDSAbs_Edge) {
873 vector<const SMDS_MeshNode*> aNodes(3);
874 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
875 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
876 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
877 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
880 int nbn = theElem->NbNodes();
881 vector<const SMDS_MeshNode*> aNodes(nbn);
882 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
884 for(; i<nbn/2; i++) {
885 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
887 for(i=0; i<nbn/2; i++) {
888 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
890 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
894 case SMDSAbs_Volume: {
895 if (theElem->IsPoly()) {
896 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
897 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
899 MESSAGE("Warning: bad volumic element");
903 int nbFaces = aPolyedre->NbFaces();
904 vector<const SMDS_MeshNode *> poly_nodes;
905 vector<int> quantities (nbFaces);
907 // reverse each face of the polyedre
908 for (int iface = 1; iface <= nbFaces; iface++) {
909 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
910 quantities[iface - 1] = nbFaceNodes;
912 for (inode = nbFaceNodes; inode >= 1; inode--) {
913 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
914 poly_nodes.push_back(curNode);
918 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
922 SMDS_VolumeTool vTool;
923 if ( !vTool.Set( theElem ))
926 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
935 //=======================================================================
936 //function : getBadRate
938 //=======================================================================
940 static double getBadRate (const SMDS_MeshElement* theElem,
941 SMESH::Controls::NumericalFunctorPtr& theCrit)
943 SMESH::Controls::TSequenceOfXYZ P;
944 if ( !theElem || !theCrit->GetPoints( theElem, P ))
946 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
947 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
950 //=======================================================================
951 //function : QuadToTri
952 //purpose : Cut quadrangles into triangles.
953 // theCrit is used to select a diagonal to cut
954 //=======================================================================
956 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
957 SMESH::Controls::NumericalFunctorPtr theCrit)
959 myLastCreatedElems.Clear();
960 myLastCreatedNodes.Clear();
962 MESSAGE( "::QuadToTri()" );
964 if ( !theCrit.get() )
967 SMESHDS_Mesh * aMesh = GetMeshDS();
969 Handle(Geom_Surface) surface;
970 SMESH_MesherHelper helper( *GetMesh() );
972 TIDSortedElemSet::iterator itElem;
973 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
974 const SMDS_MeshElement* elem = *itElem;
975 if ( !elem || elem->GetType() != SMDSAbs_Face )
977 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
980 // retrieve element nodes
981 const SMDS_MeshNode* aNodes [8];
982 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
984 while ( itN->more() )
985 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
987 // compare two sets of possible triangles
988 double aBadRate1, aBadRate2; // to what extent a set is bad
989 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
990 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
991 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
993 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
994 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
995 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
997 int aShapeId = FindShape( elem );
998 const SMDS_MeshElement* newElem = 0;
1000 if( !elem->IsQuadratic() ) {
1002 // split liner quadrangle
1004 if ( aBadRate1 <= aBadRate2 ) {
1005 // tr1 + tr2 is better
1006 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1007 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1010 // tr3 + tr4 is better
1011 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1012 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1017 // split quadratic quadrangle
1019 // get surface elem is on
1020 if ( aShapeId != helper.GetSubShapeID() ) {
1024 shape = aMesh->IndexToShape( aShapeId );
1025 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1026 TopoDS_Face face = TopoDS::Face( shape );
1027 surface = BRep_Tool::Surface( face );
1028 if ( !surface.IsNull() )
1029 helper.SetSubShape( shape );
1033 const SMDS_MeshNode* aNodes [8];
1034 const SMDS_MeshNode* inFaceNode = 0;
1035 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1037 while ( itN->more() ) {
1038 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1039 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1040 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1042 inFaceNode = aNodes[ i-1 ];
1045 // find middle point for (0,1,2,3)
1046 // and create a node in this point;
1048 if ( surface.IsNull() ) {
1050 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1054 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1057 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1059 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1061 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1062 myLastCreatedNodes.Append(newN);
1064 // create a new element
1065 const SMDS_MeshNode* N[6];
1066 if ( aBadRate1 <= aBadRate2 ) {
1073 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1074 aNodes[6], aNodes[7], newN );
1083 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1084 aNodes[7], aNodes[4], newN );
1086 aMesh->ChangeElementNodes( elem, N, 6 );
1090 // care of a new element
1092 myLastCreatedElems.Append(newElem);
1093 AddToSameGroups( newElem, elem, aMesh );
1095 // put a new triangle on the same shape
1097 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1102 //=======================================================================
1103 //function : BestSplit
1104 //purpose : Find better diagonal for cutting.
1105 //=======================================================================
1106 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1107 SMESH::Controls::NumericalFunctorPtr theCrit)
1109 myLastCreatedElems.Clear();
1110 myLastCreatedNodes.Clear();
1115 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1118 if( theQuad->NbNodes()==4 ||
1119 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1121 // retrieve element nodes
1122 const SMDS_MeshNode* aNodes [4];
1123 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1125 //while (itN->more())
1127 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1129 // compare two sets of possible triangles
1130 double aBadRate1, aBadRate2; // to what extent a set is bad
1131 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1132 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1133 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1135 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1136 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1137 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1139 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1140 return 1; // diagonal 1-3
1142 return 2; // diagonal 2-4
1147 //=======================================================================
1148 //function : AddToSameGroups
1149 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1150 //=======================================================================
1152 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1153 const SMDS_MeshElement* elemInGroups,
1154 SMESHDS_Mesh * aMesh)
1156 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1157 if (!groups.empty()) {
1158 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1159 for ( ; grIt != groups.end(); grIt++ ) {
1160 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1161 if ( group && group->Contains( elemInGroups ))
1162 group->SMDSGroup().Add( elemToAdd );
1168 //=======================================================================
1169 //function : RemoveElemFromGroups
1170 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1171 //=======================================================================
1172 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1173 SMESHDS_Mesh * aMesh)
1175 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1176 if (!groups.empty())
1178 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1179 for (; GrIt != groups.end(); GrIt++)
1181 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1182 if (!grp || grp->IsEmpty()) continue;
1183 grp->SMDSGroup().Remove(removeelem);
1188 //=======================================================================
1189 //function : ReplaceElemInGroups
1190 //purpose : replace elemToRm by elemToAdd in the all groups
1191 //=======================================================================
1193 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1194 const SMDS_MeshElement* elemToAdd,
1195 SMESHDS_Mesh * aMesh)
1197 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1198 if (!groups.empty()) {
1199 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1200 for ( ; grIt != groups.end(); grIt++ ) {
1201 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1202 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1203 group->SMDSGroup().Add( elemToAdd );
1208 //=======================================================================
1209 //function : QuadToTri
1210 //purpose : Cut quadrangles into triangles.
1211 // theCrit is used to select a diagonal to cut
1212 //=======================================================================
1214 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1215 const bool the13Diag)
1217 myLastCreatedElems.Clear();
1218 myLastCreatedNodes.Clear();
1220 MESSAGE( "::QuadToTri()" );
1222 SMESHDS_Mesh * aMesh = GetMeshDS();
1224 Handle(Geom_Surface) surface;
1225 SMESH_MesherHelper helper( *GetMesh() );
1227 TIDSortedElemSet::iterator itElem;
1228 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1229 const SMDS_MeshElement* elem = *itElem;
1230 if ( !elem || elem->GetType() != SMDSAbs_Face )
1232 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1233 if(!isquad) continue;
1235 if(elem->NbNodes()==4) {
1236 // retrieve element nodes
1237 const SMDS_MeshNode* aNodes [4];
1238 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1240 while ( itN->more() )
1241 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1243 int aShapeId = FindShape( elem );
1244 const SMDS_MeshElement* newElem = 0;
1246 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1247 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1250 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1251 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1253 myLastCreatedElems.Append(newElem);
1254 // put a new triangle on the same shape and add to the same groups
1256 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1257 AddToSameGroups( newElem, elem, aMesh );
1260 // Quadratic quadrangle
1262 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1264 // get surface elem is on
1265 int aShapeId = FindShape( elem );
1266 if ( aShapeId != helper.GetSubShapeID() ) {
1270 shape = aMesh->IndexToShape( aShapeId );
1271 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1272 TopoDS_Face face = TopoDS::Face( shape );
1273 surface = BRep_Tool::Surface( face );
1274 if ( !surface.IsNull() )
1275 helper.SetSubShape( shape );
1279 const SMDS_MeshNode* aNodes [8];
1280 const SMDS_MeshNode* inFaceNode = 0;
1281 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1283 while ( itN->more() ) {
1284 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1285 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1286 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1288 inFaceNode = aNodes[ i-1 ];
1292 // find middle point for (0,1,2,3)
1293 // and create a node in this point;
1295 if ( surface.IsNull() ) {
1297 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1301 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1304 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1306 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1308 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1309 myLastCreatedNodes.Append(newN);
1311 // create a new element
1312 const SMDS_MeshElement* newElem = 0;
1313 const SMDS_MeshNode* N[6];
1321 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1322 aNodes[6], aNodes[7], newN );
1331 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1332 aNodes[7], aNodes[4], newN );
1334 myLastCreatedElems.Append(newElem);
1335 aMesh->ChangeElementNodes( elem, N, 6 );
1336 // put a new triangle on the same shape and add to the same groups
1338 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1339 AddToSameGroups( newElem, elem, aMesh );
1346 //=======================================================================
1347 //function : getAngle
1349 //=======================================================================
1351 double getAngle(const SMDS_MeshElement * tr1,
1352 const SMDS_MeshElement * tr2,
1353 const SMDS_MeshNode * n1,
1354 const SMDS_MeshNode * n2)
1356 double angle = 2*PI; // bad angle
1359 SMESH::Controls::TSequenceOfXYZ P1, P2;
1360 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1361 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1364 if(!tr1->IsQuadratic())
1365 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1367 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1368 if ( N1.SquareMagnitude() <= gp::Resolution() )
1370 if(!tr2->IsQuadratic())
1371 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1373 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1374 if ( N2.SquareMagnitude() <= gp::Resolution() )
1377 // find the first diagonal node n1 in the triangles:
1378 // take in account a diagonal link orientation
1379 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1380 for ( int t = 0; t < 2; t++ ) {
1381 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1382 int i = 0, iDiag = -1;
1383 while ( it->more()) {
1384 const SMDS_MeshElement *n = it->next();
1385 if ( n == n1 || n == n2 )
1389 if ( i - iDiag == 1 )
1390 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1398 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1401 angle = N1.Angle( N2 );
1406 // =================================================
1407 // class generating a unique ID for a pair of nodes
1408 // and able to return nodes by that ID
1409 // =================================================
1413 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1414 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1417 long GetLinkID (const SMDS_MeshNode * n1,
1418 const SMDS_MeshNode * n2) const
1420 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1423 bool GetNodes (const long theLinkID,
1424 const SMDS_MeshNode* & theNode1,
1425 const SMDS_MeshNode* & theNode2) const
1427 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1428 if ( !theNode1 ) return false;
1429 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1430 if ( !theNode2 ) return false;
1436 const SMESHDS_Mesh* myMesh;
1441 //=======================================================================
1442 //function : TriToQuad
1443 //purpose : Fuse neighbour triangles into quadrangles.
1444 // theCrit is used to select a neighbour to fuse with.
1445 // theMaxAngle is a max angle between element normals at which
1446 // fusion is still performed.
1447 //=======================================================================
1449 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1450 SMESH::Controls::NumericalFunctorPtr theCrit,
1451 const double theMaxAngle)
1453 myLastCreatedElems.Clear();
1454 myLastCreatedNodes.Clear();
1456 MESSAGE( "::TriToQuad()" );
1458 if ( !theCrit.get() )
1461 SMESHDS_Mesh * aMesh = GetMeshDS();
1463 // Prepare data for algo: build
1464 // 1. map of elements with their linkIDs
1465 // 2. map of linkIDs with their elements
1467 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1468 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1469 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1470 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1472 TIDSortedElemSet::iterator itElem;
1473 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1474 const SMDS_MeshElement* elem = *itElem;
1475 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1476 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1477 if(!IsTria) continue;
1479 // retrieve element nodes
1480 const SMDS_MeshNode* aNodes [4];
1481 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1484 aNodes[ i++ ] = cast2Node( itN->next() );
1485 aNodes[ 3 ] = aNodes[ 0 ];
1488 for ( i = 0; i < 3; i++ ) {
1489 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1490 // check if elements sharing a link can be fused
1491 itLE = mapLi_listEl.find( link );
1492 if ( itLE != mapLi_listEl.end() ) {
1493 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1495 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1496 //if ( FindShape( elem ) != FindShape( elem2 ))
1497 // continue; // do not fuse triangles laying on different shapes
1498 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1499 continue; // avoid making badly shaped quads
1500 (*itLE).second.push_back( elem );
1503 mapLi_listEl[ link ].push_back( elem );
1505 mapEl_setLi [ elem ].insert( link );
1508 // Clean the maps from the links shared by a sole element, ie
1509 // links to which only one element is bound in mapLi_listEl
1511 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1512 int nbElems = (*itLE).second.size();
1513 if ( nbElems < 2 ) {
1514 const SMDS_MeshElement* elem = (*itLE).second.front();
1515 SMESH_TLink link = (*itLE).first;
1516 mapEl_setLi[ elem ].erase( link );
1517 if ( mapEl_setLi[ elem ].empty() )
1518 mapEl_setLi.erase( elem );
1522 // Algo: fuse triangles into quadrangles
1524 while ( ! mapEl_setLi.empty() ) {
1525 // Look for the start element:
1526 // the element having the least nb of shared links
1527 const SMDS_MeshElement* startElem = 0;
1529 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1530 int nbLinks = (*itEL).second.size();
1531 if ( nbLinks < minNbLinks ) {
1532 startElem = (*itEL).first;
1533 minNbLinks = nbLinks;
1534 if ( minNbLinks == 1 )
1539 // search elements to fuse starting from startElem or links of elements
1540 // fused earlyer - startLinks
1541 list< SMESH_TLink > startLinks;
1542 while ( startElem || !startLinks.empty() ) {
1543 while ( !startElem && !startLinks.empty() ) {
1544 // Get an element to start, by a link
1545 SMESH_TLink linkId = startLinks.front();
1546 startLinks.pop_front();
1547 itLE = mapLi_listEl.find( linkId );
1548 if ( itLE != mapLi_listEl.end() ) {
1549 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1550 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1551 for ( ; itE != listElem.end() ; itE++ )
1552 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1554 mapLi_listEl.erase( itLE );
1559 // Get candidates to be fused
1560 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1561 const SMESH_TLink *link12, *link13;
1563 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1564 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1565 ASSERT( !setLi.empty() );
1566 set< SMESH_TLink >::iterator itLi;
1567 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1569 const SMESH_TLink & link = (*itLi);
1570 itLE = mapLi_listEl.find( link );
1571 if ( itLE == mapLi_listEl.end() )
1574 const SMDS_MeshElement* elem = (*itLE).second.front();
1576 elem = (*itLE).second.back();
1577 mapLi_listEl.erase( itLE );
1578 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1589 // add other links of elem to list of links to re-start from
1590 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1591 set< SMESH_TLink >::iterator it;
1592 for ( it = links.begin(); it != links.end(); it++ ) {
1593 const SMESH_TLink& link2 = (*it);
1594 if ( link2 != link )
1595 startLinks.push_back( link2 );
1599 // Get nodes of possible quadrangles
1600 const SMDS_MeshNode *n12 [4], *n13 [4];
1601 bool Ok12 = false, Ok13 = false;
1602 const SMDS_MeshNode *linkNode1, *linkNode2;
1604 linkNode1 = link12->first;
1605 linkNode2 = link12->second;
1606 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1610 linkNode1 = link13->first;
1611 linkNode2 = link13->second;
1612 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1616 // Choose a pair to fuse
1617 if ( Ok12 && Ok13 ) {
1618 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1619 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1620 double aBadRate12 = getBadRate( &quad12, theCrit );
1621 double aBadRate13 = getBadRate( &quad13, theCrit );
1622 if ( aBadRate13 < aBadRate12 )
1629 // and remove fused elems and removed links from the maps
1630 mapEl_setLi.erase( tr1 );
1632 mapEl_setLi.erase( tr2 );
1633 mapLi_listEl.erase( *link12 );
1634 if(tr1->NbNodes()==3) {
1635 if( tr1->GetID() < tr2->GetID() ) {
1636 aMesh->ChangeElementNodes( tr1, n12, 4 );
1637 myLastCreatedElems.Append(tr1);
1638 aMesh->RemoveElement( tr2 );
1641 aMesh->ChangeElementNodes( tr2, n12, 4 );
1642 myLastCreatedElems.Append(tr2);
1643 aMesh->RemoveElement( tr1);
1647 const SMDS_MeshNode* N1 [6];
1648 const SMDS_MeshNode* N2 [6];
1649 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1650 // now we receive following N1 and N2 (using numeration as above image)
1651 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1652 // i.e. first nodes from both arrays determ new diagonal
1653 const SMDS_MeshNode* aNodes[8];
1662 if( tr1->GetID() < tr2->GetID() ) {
1663 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1664 myLastCreatedElems.Append(tr1);
1665 GetMeshDS()->RemoveElement( tr2 );
1668 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1669 myLastCreatedElems.Append(tr2);
1670 GetMeshDS()->RemoveElement( tr1 );
1672 // remove middle node (9)
1673 GetMeshDS()->RemoveNode( N1[4] );
1677 mapEl_setLi.erase( tr3 );
1678 mapLi_listEl.erase( *link13 );
1679 if(tr1->NbNodes()==3) {
1680 if( tr1->GetID() < tr2->GetID() ) {
1681 aMesh->ChangeElementNodes( tr1, n13, 4 );
1682 myLastCreatedElems.Append(tr1);
1683 aMesh->RemoveElement( tr3 );
1686 aMesh->ChangeElementNodes( tr3, n13, 4 );
1687 myLastCreatedElems.Append(tr3);
1688 aMesh->RemoveElement( tr1 );
1692 const SMDS_MeshNode* N1 [6];
1693 const SMDS_MeshNode* N2 [6];
1694 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1695 // now we receive following N1 and N2 (using numeration as above image)
1696 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1697 // i.e. first nodes from both arrays determ new diagonal
1698 const SMDS_MeshNode* aNodes[8];
1707 if( tr1->GetID() < tr2->GetID() ) {
1708 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1709 myLastCreatedElems.Append(tr1);
1710 GetMeshDS()->RemoveElement( tr3 );
1713 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1714 myLastCreatedElems.Append(tr3);
1715 GetMeshDS()->RemoveElement( tr1 );
1717 // remove middle node (9)
1718 GetMeshDS()->RemoveNode( N1[4] );
1722 // Next element to fuse: the rejected one
1724 startElem = Ok12 ? tr3 : tr2;
1726 } // if ( startElem )
1727 } // while ( startElem || !startLinks.empty() )
1728 } // while ( ! mapEl_setLi.empty() )
1734 /*#define DUMPSO(txt) \
1735 // cout << txt << endl;
1736 //=============================================================================
1740 //=============================================================================
1741 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1745 int tmp = idNodes[ i1 ];
1746 idNodes[ i1 ] = idNodes[ i2 ];
1747 idNodes[ i2 ] = tmp;
1748 gp_Pnt Ptmp = P[ i1 ];
1751 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1754 //=======================================================================
1755 //function : SortQuadNodes
1756 //purpose : Set 4 nodes of a quadrangle face in a good order.
1757 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1759 //=======================================================================
1761 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1766 for ( i = 0; i < 4; i++ ) {
1767 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1769 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1772 gp_Vec V1(P[0], P[1]);
1773 gp_Vec V2(P[0], P[2]);
1774 gp_Vec V3(P[0], P[3]);
1776 gp_Vec Cross1 = V1 ^ V2;
1777 gp_Vec Cross2 = V2 ^ V3;
1780 if (Cross1.Dot(Cross2) < 0)
1785 if (Cross1.Dot(Cross2) < 0)
1789 swap ( i, i + 1, idNodes, P );
1791 // for ( int ii = 0; ii < 4; ii++ ) {
1792 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1793 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1799 //=======================================================================
1800 //function : SortHexaNodes
1801 //purpose : Set 8 nodes of a hexahedron in a good order.
1802 // Return success status
1803 //=======================================================================
1805 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1810 DUMPSO( "INPUT: ========================================");
1811 for ( i = 0; i < 8; i++ ) {
1812 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1813 if ( !n ) return false;
1814 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1815 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1817 DUMPSO( "========================================");
1820 set<int> faceNodes; // ids of bottom face nodes, to be found
1821 set<int> checkedId1; // ids of tried 2-nd nodes
1822 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1823 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1824 int iMin, iLoop1 = 0;
1826 // Loop to try the 2-nd nodes
1828 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1830 // Find not checked 2-nd node
1831 for ( i = 1; i < 8; i++ )
1832 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1833 int id1 = idNodes[i];
1834 swap ( 1, i, idNodes, P );
1835 checkedId1.insert ( id1 );
1839 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1840 // ie that all but meybe one (id3 which is on the same face) nodes
1841 // lay on the same side from the triangle plane.
1843 bool manyInPlane = false; // more than 4 nodes lay in plane
1845 while ( ++iLoop2 < 6 ) {
1847 // get 1-2-3 plane coeffs
1848 Standard_Real A, B, C, D;
1849 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1850 if ( N.SquareMagnitude() > gp::Resolution() )
1852 gp_Pln pln ( P[0], N );
1853 pln.Coefficients( A, B, C, D );
1855 // find the node (iMin) closest to pln
1856 Standard_Real dist[ 8 ], minDist = DBL_MAX;
1858 for ( i = 3; i < 8; i++ ) {
1859 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1860 if ( fabs( dist[i] ) < minDist ) {
1861 minDist = fabs( dist[i] );
1864 if ( fabs( dist[i] ) <= tol )
1865 idInPln.insert( idNodes[i] );
1868 // there should not be more than 4 nodes in bottom plane
1869 if ( idInPln.size() > 1 )
1871 DUMPSO( "### idInPln.size() = " << idInPln.size());
1872 // idInPlane does not contain the first 3 nodes
1873 if ( manyInPlane || idInPln.size() == 5)
1874 return false; // all nodes in one plane
1877 // set the 1-st node to be not in plane
1878 for ( i = 3; i < 8; i++ ) {
1879 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1880 DUMPSO( "### Reset 0-th node");
1881 swap( 0, i, idNodes, P );
1886 // reset to re-check second nodes
1887 leastDist = DBL_MAX;
1891 break; // from iLoop2;
1894 // check that the other 4 nodes are on the same side
1895 bool sameSide = true;
1896 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1897 for ( i = 3; sameSide && i < 8; i++ ) {
1899 sameSide = ( isNeg == dist[i] <= 0.);
1902 // keep best solution
1903 if ( sameSide && minDist < leastDist ) {
1904 leastDist = minDist;
1906 faceNodes.insert( idNodes[ 1 ] );
1907 faceNodes.insert( idNodes[ 2 ] );
1908 faceNodes.insert( idNodes[ iMin ] );
1909 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1910 << " leastDist = " << leastDist);
1911 if ( leastDist <= DBL_MIN )
1916 // set next 3-d node to check
1917 int iNext = 2 + iLoop2;
1919 DUMPSO( "Try 2-nd");
1920 swap ( 2, iNext, idNodes, P );
1922 } // while ( iLoop2 < 6 )
1925 if ( faceNodes.empty() ) return false;
1927 // Put the faceNodes in proper places
1928 for ( i = 4; i < 8; i++ ) {
1929 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1930 // find a place to put
1932 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1934 DUMPSO( "Set faceNodes");
1935 swap ( iTo, i, idNodes, P );
1940 // Set nodes of the found bottom face in good order
1941 DUMPSO( " Found bottom face: ");
1942 i = SortQuadNodes( theMesh, idNodes );
1944 gp_Pnt Ptmp = P[ i ];
1949 // for ( int ii = 0; ii < 4; ii++ ) {
1950 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1951 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1954 // Gravity center of the top and bottom faces
1955 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1956 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1958 // Get direction from the bottom to the top face
1959 gp_Vec upDir ( aGCb, aGCt );
1960 Standard_Real upDirSize = upDir.Magnitude();
1961 if ( upDirSize <= gp::Resolution() ) return false;
1964 // Assure that the bottom face normal points up
1965 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1966 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1967 if ( Nb.Dot( upDir ) < 0 ) {
1968 DUMPSO( "Reverse bottom face");
1969 swap( 1, 3, idNodes, P );
1972 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1973 Standard_Real minDist = DBL_MAX;
1974 for ( i = 4; i < 8; i++ ) {
1975 // projection of P[i] to the plane defined by P[0] and upDir
1976 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1977 Standard_Real sqDist = P[0].SquareDistance( Pp );
1978 if ( sqDist < minDist ) {
1983 DUMPSO( "Set 4-th");
1984 swap ( 4, iMin, idNodes, P );
1986 // Set nodes of the top face in good order
1987 DUMPSO( "Sort top face");
1988 i = SortQuadNodes( theMesh, &idNodes[4] );
1991 gp_Pnt Ptmp = P[ i ];
1996 // Assure that direction of the top face normal is from the bottom face
1997 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
1998 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
1999 if ( Nt.Dot( upDir ) < 0 ) {
2000 DUMPSO( "Reverse top face");
2001 swap( 5, 7, idNodes, P );
2004 // DUMPSO( "OUTPUT: ========================================");
2005 // for ( i = 0; i < 8; i++ ) {
2006 // float *p = ugrid->GetPoint(idNodes[i]);
2007 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2013 //================================================================================
2015 * \brief Return nodes linked to the given one
2016 * \param theNode - the node
2017 * \param linkedNodes - the found nodes
2018 * \param type - the type of elements to check
2020 * Medium nodes are ignored
2022 //================================================================================
2024 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2025 TIDSortedElemSet & linkedNodes,
2026 SMDSAbs_ElementType type )
2028 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2029 while ( elemIt->more() )
2031 const SMDS_MeshElement* elem = elemIt->next();
2032 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2033 if ( elem->GetType() == SMDSAbs_Volume )
2035 SMDS_VolumeTool vol( elem );
2036 while ( nodeIt->more() ) {
2037 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2038 if ( theNode != n && vol.IsLinked( theNode, n ))
2039 linkedNodes.insert( n );
2044 for ( int i = 0; nodeIt->more(); ++i ) {
2045 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2046 if ( n == theNode ) {
2047 int iBefore = i - 1;
2049 if ( elem->IsQuadratic() ) {
2050 int nb = elem->NbNodes() / 2;
2051 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2052 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2054 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2055 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2062 //=======================================================================
2063 //function : laplacianSmooth
2064 //purpose : pulls theNode toward the center of surrounding nodes directly
2065 // connected to that node along an element edge
2066 //=======================================================================
2068 void laplacianSmooth(const SMDS_MeshNode* theNode,
2069 const Handle(Geom_Surface)& theSurface,
2070 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2072 // find surrounding nodes
2074 TIDSortedElemSet nodeSet;
2075 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2077 // compute new coodrs
2079 double coord[] = { 0., 0., 0. };
2080 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2081 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2082 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2083 if ( theSurface.IsNull() ) { // smooth in 3D
2084 coord[0] += node->X();
2085 coord[1] += node->Y();
2086 coord[2] += node->Z();
2088 else { // smooth in 2D
2089 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2090 gp_XY* uv = theUVMap[ node ];
2091 coord[0] += uv->X();
2092 coord[1] += uv->Y();
2095 int nbNodes = nodeSet.size();
2098 coord[0] /= nbNodes;
2099 coord[1] /= nbNodes;
2101 if ( !theSurface.IsNull() ) {
2102 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2103 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2104 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2110 coord[2] /= nbNodes;
2114 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2117 //=======================================================================
2118 //function : centroidalSmooth
2119 //purpose : pulls theNode toward the element-area-weighted centroid of the
2120 // surrounding elements
2121 //=======================================================================
2123 void centroidalSmooth(const SMDS_MeshNode* theNode,
2124 const Handle(Geom_Surface)& theSurface,
2125 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2127 gp_XYZ aNewXYZ(0.,0.,0.);
2128 SMESH::Controls::Area anAreaFunc;
2129 double totalArea = 0.;
2134 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2135 while ( elemIt->more() )
2137 const SMDS_MeshElement* elem = elemIt->next();
2140 gp_XYZ elemCenter(0.,0.,0.);
2141 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2142 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2143 int nn = elem->NbNodes();
2144 if(elem->IsQuadratic()) nn = nn/2;
2146 //while ( itN->more() ) {
2148 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2150 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2151 aNodePoints.push_back( aP );
2152 if ( !theSurface.IsNull() ) { // smooth in 2D
2153 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2154 gp_XY* uv = theUVMap[ aNode ];
2155 aP.SetCoord( uv->X(), uv->Y(), 0. );
2159 double elemArea = anAreaFunc.GetValue( aNodePoints );
2160 totalArea += elemArea;
2162 aNewXYZ += elemCenter * elemArea;
2164 aNewXYZ /= totalArea;
2165 if ( !theSurface.IsNull() ) {
2166 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2167 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2172 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2175 //=======================================================================
2176 //function : getClosestUV
2177 //purpose : return UV of closest projection
2178 //=======================================================================
2180 static bool getClosestUV (Extrema_GenExtPS& projector,
2181 const gp_Pnt& point,
2184 projector.Perform( point );
2185 if ( projector.IsDone() ) {
2186 double u, v, minVal = DBL_MAX;
2187 for ( int i = projector.NbExt(); i > 0; i-- )
2188 if ( projector.Value( i ) < minVal ) {
2189 minVal = projector.Value( i );
2190 projector.Point( i ).Parameter( u, v );
2192 result.SetCoord( u, v );
2198 //=======================================================================
2200 //purpose : Smooth theElements during theNbIterations or until a worst
2201 // element has aspect ratio <= theTgtAspectRatio.
2202 // Aspect Ratio varies in range [1.0, inf].
2203 // If theElements is empty, the whole mesh is smoothed.
2204 // theFixedNodes contains additionally fixed nodes. Nodes built
2205 // on edges and boundary nodes are always fixed.
2206 //=======================================================================
2208 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2209 set<const SMDS_MeshNode*> & theFixedNodes,
2210 const SmoothMethod theSmoothMethod,
2211 const int theNbIterations,
2212 double theTgtAspectRatio,
2215 myLastCreatedElems.Clear();
2216 myLastCreatedNodes.Clear();
2218 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2220 if ( theTgtAspectRatio < 1.0 )
2221 theTgtAspectRatio = 1.0;
2223 const double disttol = 1.e-16;
2225 SMESH::Controls::AspectRatio aQualityFunc;
2227 SMESHDS_Mesh* aMesh = GetMeshDS();
2229 if ( theElems.empty() ) {
2230 // add all faces to theElems
2231 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2232 while ( fIt->more() ) {
2233 const SMDS_MeshElement* face = fIt->next();
2234 theElems.insert( face );
2237 // get all face ids theElems are on
2238 set< int > faceIdSet;
2239 TIDSortedElemSet::iterator itElem;
2241 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2242 int fId = FindShape( *itElem );
2243 // check that corresponding submesh exists and a shape is face
2245 faceIdSet.find( fId ) == faceIdSet.end() &&
2246 aMesh->MeshElements( fId )) {
2247 TopoDS_Shape F = aMesh->IndexToShape( fId );
2248 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2249 faceIdSet.insert( fId );
2252 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2254 // ===============================================
2255 // smooth elements on each TopoDS_Face separately
2256 // ===============================================
2258 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2259 for ( ; fId != faceIdSet.rend(); ++fId ) {
2260 // get face surface and submesh
2261 Handle(Geom_Surface) surface;
2262 SMESHDS_SubMesh* faceSubMesh = 0;
2264 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2265 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2266 bool isUPeriodic = false, isVPeriodic = false;
2268 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2269 surface = BRep_Tool::Surface( face );
2270 faceSubMesh = aMesh->MeshElements( *fId );
2271 fToler2 = BRep_Tool::Tolerance( face );
2272 fToler2 *= fToler2 * 10.;
2273 isUPeriodic = surface->IsUPeriodic();
2275 vPeriod = surface->UPeriod();
2276 isVPeriodic = surface->IsVPeriodic();
2278 uPeriod = surface->VPeriod();
2279 surface->Bounds( u1, u2, v1, v2 );
2281 // ---------------------------------------------------------
2282 // for elements on a face, find movable and fixed nodes and
2283 // compute UV for them
2284 // ---------------------------------------------------------
2285 bool checkBoundaryNodes = false;
2286 bool isQuadratic = false;
2287 set<const SMDS_MeshNode*> setMovableNodes;
2288 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2289 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2290 list< const SMDS_MeshElement* > elemsOnFace;
2292 Extrema_GenExtPS projector;
2293 GeomAdaptor_Surface surfAdaptor;
2294 if ( !surface.IsNull() ) {
2295 surfAdaptor.Load( surface );
2296 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2298 int nbElemOnFace = 0;
2299 itElem = theElems.begin();
2300 // loop on not yet smoothed elements: look for elems on a face
2301 while ( itElem != theElems.end() ) {
2302 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2303 break; // all elements found
2305 const SMDS_MeshElement* elem = *itElem;
2306 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2307 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2311 elemsOnFace.push_back( elem );
2312 theElems.erase( itElem++ );
2316 isQuadratic = elem->IsQuadratic();
2318 // get movable nodes of elem
2319 const SMDS_MeshNode* node;
2320 SMDS_TypeOfPosition posType;
2321 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2322 int nn = 0, nbn = elem->NbNodes();
2323 if(elem->IsQuadratic())
2325 while ( nn++ < nbn ) {
2326 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2327 const SMDS_PositionPtr& pos = node->GetPosition();
2328 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2329 if (posType != SMDS_TOP_EDGE &&
2330 posType != SMDS_TOP_VERTEX &&
2331 theFixedNodes.find( node ) == theFixedNodes.end())
2333 // check if all faces around the node are on faceSubMesh
2334 // because a node on edge may be bound to face
2335 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2337 if ( faceSubMesh ) {
2338 while ( eIt->more() && all ) {
2339 const SMDS_MeshElement* e = eIt->next();
2340 all = faceSubMesh->Contains( e );
2344 setMovableNodes.insert( node );
2346 checkBoundaryNodes = true;
2348 if ( posType == SMDS_TOP_3DSPACE )
2349 checkBoundaryNodes = true;
2352 if ( surface.IsNull() )
2355 // get nodes to check UV
2356 list< const SMDS_MeshNode* > uvCheckNodes;
2357 itN = elem->nodesIterator();
2358 nn = 0; nbn = elem->NbNodes();
2359 if(elem->IsQuadratic())
2361 while ( nn++ < nbn ) {
2362 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2363 if ( uvMap.find( node ) == uvMap.end() )
2364 uvCheckNodes.push_back( node );
2365 // add nodes of elems sharing node
2366 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2367 // while ( eIt->more() ) {
2368 // const SMDS_MeshElement* e = eIt->next();
2369 // if ( e != elem ) {
2370 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2371 // while ( nIt->more() ) {
2372 // const SMDS_MeshNode* n =
2373 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2374 // if ( uvMap.find( n ) == uvMap.end() )
2375 // uvCheckNodes.push_back( n );
2381 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2382 for ( ; n != uvCheckNodes.end(); ++n ) {
2385 const SMDS_PositionPtr& pos = node->GetPosition();
2386 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2388 switch ( posType ) {
2389 case SMDS_TOP_FACE: {
2390 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2391 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2394 case SMDS_TOP_EDGE: {
2395 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2396 Handle(Geom2d_Curve) pcurve;
2397 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2398 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2399 if ( !pcurve.IsNull() ) {
2400 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2401 uv = pcurve->Value( u ).XY();
2405 case SMDS_TOP_VERTEX: {
2406 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2407 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2408 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2413 // check existing UV
2414 bool project = true;
2415 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2416 double dist1 = DBL_MAX, dist2 = 0;
2417 if ( posType != SMDS_TOP_3DSPACE ) {
2418 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2419 project = dist1 > fToler2;
2421 if ( project ) { // compute new UV
2423 if ( !getClosestUV( projector, pNode, newUV )) {
2424 MESSAGE("Node Projection Failed " << node);
2428 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2430 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2432 if ( posType != SMDS_TOP_3DSPACE )
2433 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2434 if ( dist2 < dist1 )
2438 // store UV in the map
2439 listUV.push_back( uv );
2440 uvMap.insert( make_pair( node, &listUV.back() ));
2442 } // loop on not yet smoothed elements
2444 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2445 checkBoundaryNodes = true;
2447 // fix nodes on mesh boundary
2449 if ( checkBoundaryNodes ) {
2450 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2451 map< NLink, int >::iterator link_nb;
2452 // put all elements links to linkNbMap
2453 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2454 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2455 const SMDS_MeshElement* elem = (*elemIt);
2456 int nbn = elem->NbNodes();
2457 if(elem->IsQuadratic())
2459 // loop on elem links: insert them in linkNbMap
2460 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2461 for ( int iN = 0; iN < nbn; ++iN ) {
2462 curNode = elem->GetNode( iN );
2464 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2465 else link = make_pair( prevNode , curNode );
2467 link_nb = linkNbMap.find( link );
2468 if ( link_nb == linkNbMap.end() )
2469 linkNbMap.insert( make_pair ( link, 1 ));
2474 // remove nodes that are in links encountered only once from setMovableNodes
2475 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2476 if ( link_nb->second == 1 ) {
2477 setMovableNodes.erase( link_nb->first.first );
2478 setMovableNodes.erase( link_nb->first.second );
2483 // -----------------------------------------------------
2484 // for nodes on seam edge, compute one more UV ( uvMap2 );
2485 // find movable nodes linked to nodes on seam and which
2486 // are to be smoothed using the second UV ( uvMap2 )
2487 // -----------------------------------------------------
2489 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2490 if ( !surface.IsNull() ) {
2491 TopExp_Explorer eExp( face, TopAbs_EDGE );
2492 for ( ; eExp.More(); eExp.Next() ) {
2493 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2494 if ( !BRep_Tool::IsClosed( edge, face ))
2496 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2497 if ( !sm ) continue;
2498 // find out which parameter varies for a node on seam
2501 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2502 if ( pcurve.IsNull() ) continue;
2503 uv1 = pcurve->Value( f );
2505 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2506 if ( pcurve.IsNull() ) continue;
2507 uv2 = pcurve->Value( f );
2508 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2510 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2511 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2513 // get nodes on seam and its vertices
2514 list< const SMDS_MeshNode* > seamNodes;
2515 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2516 while ( nSeamIt->more() ) {
2517 const SMDS_MeshNode* node = nSeamIt->next();
2518 if ( !isQuadratic || !IsMedium( node ))
2519 seamNodes.push_back( node );
2521 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2522 for ( ; vExp.More(); vExp.Next() ) {
2523 sm = aMesh->MeshElements( vExp.Current() );
2525 nSeamIt = sm->GetNodes();
2526 while ( nSeamIt->more() )
2527 seamNodes.push_back( nSeamIt->next() );
2530 // loop on nodes on seam
2531 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2532 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2533 const SMDS_MeshNode* nSeam = *noSeIt;
2534 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2535 if ( n_uv == uvMap.end() )
2538 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2539 // set the second UV
2540 listUV.push_back( *n_uv->second );
2541 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2542 if ( uvMap2.empty() )
2543 uvMap2 = uvMap; // copy the uvMap contents
2544 uvMap2[ nSeam ] = &listUV.back();
2546 // collect movable nodes linked to ones on seam in nodesNearSeam
2547 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2548 while ( eIt->more() ) {
2549 const SMDS_MeshElement* e = eIt->next();
2550 int nbUseMap1 = 0, nbUseMap2 = 0;
2551 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2552 int nn = 0, nbn = e->NbNodes();
2553 if(e->IsQuadratic()) nbn = nbn/2;
2554 while ( nn++ < nbn )
2556 const SMDS_MeshNode* n =
2557 static_cast<const SMDS_MeshNode*>( nIt->next() );
2559 setMovableNodes.find( n ) == setMovableNodes.end() )
2561 // add only nodes being closer to uv2 than to uv1
2562 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2563 0.5 * ( n->Y() + nSeam->Y() ),
2564 0.5 * ( n->Z() + nSeam->Z() ));
2566 getClosestUV( projector, pMid, uv );
2567 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2568 nodesNearSeam.insert( n );
2574 // for centroidalSmooth all element nodes must
2575 // be on one side of a seam
2576 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2577 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2579 while ( nn++ < nbn ) {
2580 const SMDS_MeshNode* n =
2581 static_cast<const SMDS_MeshNode*>( nIt->next() );
2582 setMovableNodes.erase( n );
2586 } // loop on nodes on seam
2587 } // loop on edge of a face
2588 } // if ( !face.IsNull() )
2590 if ( setMovableNodes.empty() ) {
2591 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2592 continue; // goto next face
2600 double maxRatio = -1., maxDisplacement = -1.;
2601 set<const SMDS_MeshNode*>::iterator nodeToMove;
2602 for ( it = 0; it < theNbIterations; it++ ) {
2603 maxDisplacement = 0.;
2604 nodeToMove = setMovableNodes.begin();
2605 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2606 const SMDS_MeshNode* node = (*nodeToMove);
2607 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2610 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2611 if ( theSmoothMethod == LAPLACIAN )
2612 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2614 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2616 // node displacement
2617 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2618 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2619 if ( aDispl > maxDisplacement )
2620 maxDisplacement = aDispl;
2622 // no node movement => exit
2623 //if ( maxDisplacement < 1.e-16 ) {
2624 if ( maxDisplacement < disttol ) {
2625 MESSAGE("-- no node movement --");
2629 // check elements quality
2631 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2632 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2633 const SMDS_MeshElement* elem = (*elemIt);
2634 if ( !elem || elem->GetType() != SMDSAbs_Face )
2636 SMESH::Controls::TSequenceOfXYZ aPoints;
2637 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2638 double aValue = aQualityFunc.GetValue( aPoints );
2639 if ( aValue > maxRatio )
2643 if ( maxRatio <= theTgtAspectRatio ) {
2644 MESSAGE("-- quality achived --");
2647 if (it+1 == theNbIterations) {
2648 MESSAGE("-- Iteration limit exceeded --");
2650 } // smoothing iterations
2652 MESSAGE(" Face id: " << *fId <<
2653 " Nb iterstions: " << it <<
2654 " Displacement: " << maxDisplacement <<
2655 " Aspect Ratio " << maxRatio);
2657 // ---------------------------------------
2658 // new nodes positions are computed,
2659 // record movement in DS and set new UV
2660 // ---------------------------------------
2661 nodeToMove = setMovableNodes.begin();
2662 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2663 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2664 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2665 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2666 if ( node_uv != uvMap.end() ) {
2667 gp_XY* uv = node_uv->second;
2669 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2673 // move medium nodes of quadratic elements
2676 SMESH_MesherHelper helper( *GetMesh() );
2677 if ( !face.IsNull() )
2678 helper.SetSubShape( face );
2679 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2680 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2681 const SMDS_QuadraticFaceOfNodes* QF =
2682 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2684 vector<const SMDS_MeshNode*> Ns;
2685 Ns.reserve(QF->NbNodes()+1);
2686 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2687 while ( anIter->more() )
2688 Ns.push_back( anIter->next() );
2689 Ns.push_back( Ns[0] );
2691 for(int i=0; i<QF->NbNodes(); i=i+2) {
2692 if ( !surface.IsNull() ) {
2693 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2694 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2695 gp_XY uv = ( uv1 + uv2 ) / 2.;
2696 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2697 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2700 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2701 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2702 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2704 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2705 fabs( Ns[i+1]->Y() - y ) > disttol ||
2706 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2707 // we have to move i+1 node
2708 aMesh->MoveNode( Ns[i+1], x, y, z );
2715 } // loop on face ids
2719 //=======================================================================
2720 //function : isReverse
2721 //purpose : Return true if normal of prevNodes is not co-directied with
2722 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2723 // iNotSame is where prevNodes and nextNodes are different
2724 //=======================================================================
2726 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2727 vector<const SMDS_MeshNode*> nextNodes,
2731 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2732 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2734 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2735 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2736 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2737 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2739 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2740 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2741 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2742 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2744 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2746 return (vA ^ vB) * vN < 0.0;
2749 //=======================================================================
2751 * \brief Create elements by sweeping an element
2752 * \param elem - element to sweep
2753 * \param newNodesItVec - nodes generated from each node of the element
2754 * \param newElems - generated elements
2755 * \param nbSteps - number of sweeping steps
2756 * \param srcElements - to append elem for each generated element
2758 //=======================================================================
2760 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2761 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2762 list<const SMDS_MeshElement*>& newElems,
2764 SMESH_SequenceOfElemPtr& srcElements)
2766 SMESHDS_Mesh* aMesh = GetMeshDS();
2768 // Loop on elem nodes:
2769 // find new nodes and detect same nodes indices
2770 int nbNodes = elem->NbNodes();
2771 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2772 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2773 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2774 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2776 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2777 vector<int> sames(nbNodes);
2778 vector<bool> issimple(nbNodes);
2780 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2781 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2782 const SMDS_MeshNode* node = nnIt->first;
2783 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2784 if ( listNewNodes.empty() ) {
2788 issimple[iNode] = (listNewNodes.size()==nbSteps);
2790 itNN[ iNode ] = listNewNodes.begin();
2791 prevNod[ iNode ] = node;
2792 nextNod[ iNode ] = listNewNodes.front();
2793 if( !issimple[iNode] ) {
2794 if ( prevNod[ iNode ] != nextNod [ iNode ])
2795 iNotSameNode = iNode;
2799 sames[nbSame++] = iNode;
2804 //cout<<" nbSame = "<<nbSame<<endl;
2805 if ( nbSame == nbNodes || nbSame > 2) {
2806 //MESSAGE( " Too many same nodes of element " << elem->GetID() );
2807 INFOS( " Too many same nodes of element " << elem->GetID() );
2811 // if( elem->IsQuadratic() && nbSame>0 ) {
2812 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2816 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2817 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2819 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2820 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2821 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2825 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2826 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2827 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2828 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2830 // check element orientation
2832 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2833 //MESSAGE("Reversed elem " << elem );
2837 std::swap( iBeforeSame, iAfterSame );
2840 // make new elements
2841 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2843 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2844 if(issimple[iNode]) {
2845 nextNod[ iNode ] = *itNN[ iNode ];
2849 if( elem->GetType()==SMDSAbs_Node ) {
2850 // we have to use two nodes
2851 midlNod[ iNode ] = *itNN[ iNode ];
2853 nextNod[ iNode ] = *itNN[ iNode ];
2856 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2857 // we have to use each second node
2859 nextNod[ iNode ] = *itNN[ iNode ];
2863 // we have to use two nodes
2864 midlNod[ iNode ] = *itNN[ iNode ];
2866 nextNod[ iNode ] = *itNN[ iNode ];
2871 SMDS_MeshElement* aNewElem = 0;
2872 if(!elem->IsPoly()) {
2873 switch ( nbNodes ) {
2877 if ( nbSame == 0 ) {
2879 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2881 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2887 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2888 nextNod[ 1 ], nextNod[ 0 ] );
2890 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2891 nextNod[ iNotSameNode ] );
2895 case 3: { // TRIANGLE or quadratic edge
2896 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2898 if ( nbSame == 0 ) // --- pentahedron
2899 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2900 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2902 else if ( nbSame == 1 ) // --- pyramid
2903 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2904 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2905 nextNod[ iSameNode ]);
2907 else // 2 same nodes: --- tetrahedron
2908 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2909 nextNod[ iNotSameNode ]);
2911 else { // quadratic edge
2912 if(nbSame==0) { // quadratic quadrangle
2913 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2914 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2916 else if(nbSame==1) { // quadratic triangle
2918 return; // medium node on axis
2920 else if(sames[0]==0) {
2921 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2922 nextNod[2], midlNod[1], prevNod[2]);
2924 else { // sames[0]==1
2925 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2926 midlNod[0], nextNod[2], prevNod[2]);
2935 case 4: { // QUADRANGLE
2937 if ( nbSame == 0 ) // --- hexahedron
2938 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2939 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2941 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2942 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2943 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2944 nextNod[ iSameNode ]);
2945 newElems.push_back( aNewElem );
2946 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2947 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2948 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2950 else if ( nbSame == 2 ) { // pentahedron
2951 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2952 // iBeforeSame is same too
2953 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2954 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2955 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2957 // iAfterSame is same too
2958 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2959 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2960 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2964 case 6: { // quadratic triangle
2965 // create pentahedron with 15 nodes
2967 if(i0>0) { // reversed case
2968 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2969 nextNod[0], nextNod[2], nextNod[1],
2970 prevNod[5], prevNod[4], prevNod[3],
2971 nextNod[5], nextNod[4], nextNod[3],
2972 midlNod[0], midlNod[2], midlNod[1]);
2974 else { // not reversed case
2975 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2976 nextNod[0], nextNod[1], nextNod[2],
2977 prevNod[3], prevNod[4], prevNod[5],
2978 nextNod[3], nextNod[4], nextNod[5],
2979 midlNod[0], midlNod[1], midlNod[2]);
2982 else if(nbSame==1) {
2983 // 2d order pyramid of 13 nodes
2984 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
2985 // int n12,int n23,int n34,int n41,
2986 // int n15,int n25,int n35,int n45, int ID);
2988 int n1,n4,n41,n15,n45;
2989 if(i0>0) { // reversed case
2990 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
2991 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
2997 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
2998 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3003 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3004 nextNod[n4], prevNod[n4], prevNod[n5],
3005 midlNod[n1], nextNod[n41],
3006 midlNod[n4], prevNod[n41],
3007 prevNod[n15], nextNod[n15],
3008 nextNod[n45], prevNod[n45]);
3010 else if(nbSame==2) {
3011 // 2d order tetrahedron of 10 nodes
3012 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3013 // int n12,int n23,int n31,
3014 // int n14,int n24,int n34, int ID);
3015 int n1 = iNotSameNode;
3016 int n2,n3,n12,n23,n31;
3017 if(i0>0) { // reversed case
3018 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3019 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3025 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3026 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3031 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3032 prevNod[n12], prevNod[n23], prevNod[n31],
3033 midlNod[n1], nextNod[n12], nextNod[n31]);
3037 case 8: { // quadratic quadrangle
3039 // create hexahedron with 20 nodes
3040 if(i0>0) { // reversed case
3041 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3042 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3043 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3044 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3045 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3047 else { // not reversed case
3048 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3049 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3050 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3051 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3052 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3055 else if(nbSame==1) {
3056 // --- pyramid + pentahedron - can not be created since it is needed
3057 // additional middle node ot the center of face
3058 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3061 else if(nbSame==2) {
3062 // 2d order Pentahedron with 15 nodes
3063 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3064 // int n12,int n23,int n31,int n45,int n56,int n64,
3065 // int n14,int n25,int n36, int ID);
3067 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3068 // iBeforeSame is same too
3075 // iAfterSame is same too
3081 int n12,n45,n14,n25;
3082 if(i0>0) { //reversed case
3094 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3095 prevNod[n4], prevNod[n5], nextNod[n5],
3096 prevNod[n12], midlNod[n2], nextNod[n12],
3097 prevNod[n45], midlNod[n5], nextNod[n45],
3098 prevNod[n14], prevNod[n25], nextNod[n25]);
3103 // realized for extrusion only
3104 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3105 //vector<int> quantities (nbNodes + 2);
3107 //quantities[0] = nbNodes; // bottom of prism
3108 //for (int inode = 0; inode < nbNodes; inode++) {
3109 // polyedre_nodes[inode] = prevNod[inode];
3112 //quantities[1] = nbNodes; // top of prism
3113 //for (int inode = 0; inode < nbNodes; inode++) {
3114 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3117 //for (int iface = 0; iface < nbNodes; iface++) {
3118 // quantities[iface + 2] = 4;
3119 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3120 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3121 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3122 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3123 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3125 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3132 // realized for extrusion only
3133 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3134 vector<int> quantities (nbNodes + 2);
3136 quantities[0] = nbNodes; // bottom of prism
3137 for (int inode = 0; inode < nbNodes; inode++) {
3138 polyedre_nodes[inode] = prevNod[inode];
3141 quantities[1] = nbNodes; // top of prism
3142 for (int inode = 0; inode < nbNodes; inode++) {
3143 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3146 for (int iface = 0; iface < nbNodes; iface++) {
3147 quantities[iface + 2] = 4;
3148 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3149 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3150 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3151 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3152 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3154 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3158 newElems.push_back( aNewElem );
3159 myLastCreatedElems.Append(aNewElem);
3160 srcElements.Append( elem );
3163 // set new prev nodes
3164 for ( iNode = 0; iNode < nbNodes; iNode++ )
3165 prevNod[ iNode ] = nextNod[ iNode ];
3170 //=======================================================================
3172 * \brief Create 1D and 2D elements around swept elements
3173 * \param mapNewNodes - source nodes and ones generated from them
3174 * \param newElemsMap - source elements and ones generated from them
3175 * \param elemNewNodesMap - nodes generated from each node of each element
3176 * \param elemSet - all swept elements
3177 * \param nbSteps - number of sweeping steps
3178 * \param srcElements - to append elem for each generated element
3180 //=======================================================================
3182 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3183 TElemOfElemListMap & newElemsMap,
3184 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3185 TIDSortedElemSet& elemSet,
3187 SMESH_SequenceOfElemPtr& srcElements)
3189 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3190 SMESHDS_Mesh* aMesh = GetMeshDS();
3192 // Find nodes belonging to only one initial element - sweep them to get edges.
3194 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3195 for ( ; nList != mapNewNodes.end(); nList++ ) {
3196 const SMDS_MeshNode* node =
3197 static_cast<const SMDS_MeshNode*>( nList->first );
3198 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3199 int nbInitElems = 0;
3200 const SMDS_MeshElement* el = 0;
3201 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3202 while ( eIt->more() && nbInitElems < 2 ) {
3204 SMDSAbs_ElementType type = el->GetType();
3205 if ( type == SMDSAbs_Volume || type < highType ) continue;
3206 if ( type > highType ) {
3210 if ( elemSet.find(el) != elemSet.end() )
3213 if ( nbInitElems < 2 ) {
3214 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3215 if(!NotCreateEdge) {
3216 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3217 list<const SMDS_MeshElement*> newEdges;
3218 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3223 // Make a ceiling for each element ie an equal element of last new nodes.
3224 // Find free links of faces - make edges and sweep them into faces.
3226 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3227 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3228 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3229 const SMDS_MeshElement* elem = itElem->first;
3230 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3232 if ( elem->GetType() == SMDSAbs_Edge ) {
3233 // create a ceiling edge
3234 if (!elem->IsQuadratic()) {
3235 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3236 vecNewNodes[ 1 ]->second.back())) {
3237 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3238 vecNewNodes[ 1 ]->second.back()));
3239 srcElements.Append( myLastCreatedElems.Last() );
3243 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3244 vecNewNodes[ 1 ]->second.back(),
3245 vecNewNodes[ 2 ]->second.back())) {
3246 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3247 vecNewNodes[ 1 ]->second.back(),
3248 vecNewNodes[ 2 ]->second.back()));
3249 srcElements.Append( myLastCreatedElems.Last() );
3253 if ( elem->GetType() != SMDSAbs_Face )
3256 if(itElem->second.size()==0) continue;
3258 bool hasFreeLinks = false;
3260 TIDSortedElemSet avoidSet;
3261 avoidSet.insert( elem );
3263 set<const SMDS_MeshNode*> aFaceLastNodes;
3264 int iNode, nbNodes = vecNewNodes.size();
3265 if(!elem->IsQuadratic()) {
3266 // loop on the face nodes
3267 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3268 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3269 // look for free links of the face
3270 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3271 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3272 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3273 // check if a link is free
3274 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3275 hasFreeLinks = true;
3276 // make an edge and a ceiling for a new edge
3277 if ( !aMesh->FindEdge( n1, n2 )) {
3278 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3279 srcElements.Append( myLastCreatedElems.Last() );
3281 n1 = vecNewNodes[ iNode ]->second.back();
3282 n2 = vecNewNodes[ iNext ]->second.back();
3283 if ( !aMesh->FindEdge( n1, n2 )) {
3284 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3285 srcElements.Append( myLastCreatedElems.Last() );
3290 else { // elem is quadratic face
3291 int nbn = nbNodes/2;
3292 for ( iNode = 0; iNode < nbn; iNode++ ) {
3293 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3294 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3295 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3296 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3297 // check if a link is free
3298 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3299 hasFreeLinks = true;
3300 // make an edge and a ceiling for a new edge
3302 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3303 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3304 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3305 srcElements.Append( myLastCreatedElems.Last() );
3307 n1 = vecNewNodes[ iNode ]->second.back();
3308 n2 = vecNewNodes[ iNext ]->second.back();
3309 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3310 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3311 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3312 srcElements.Append( myLastCreatedElems.Last() );
3316 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3317 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3321 // sweep free links into faces
3323 if ( hasFreeLinks ) {
3324 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3325 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3327 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3328 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3329 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3330 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3332 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3333 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3335 while ( iVol++ < volNb ) v++;
3336 // find indices of free faces of a volume and their source edges
3337 list< int > freeInd;
3338 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3339 SMDS_VolumeTool vTool( *v );
3340 int iF, nbF = vTool.NbFaces();
3341 for ( iF = 0; iF < nbF; iF ++ ) {
3342 if (vTool.IsFreeFace( iF ) &&
3343 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3344 initNodeSet != faceNodeSet) // except an initial face
3346 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3348 freeInd.push_back( iF );
3349 // find source edge of a free face iF
3350 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3351 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3352 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3353 initNodeSet.begin(), initNodeSet.end(),
3354 commonNodes.begin());
3355 if ( (*v)->IsQuadratic() )
3356 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3358 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3360 if ( !srcEdges.back() )
3362 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3363 << iF << " of volume #" << vTool.ID() << endl;
3368 if ( freeInd.empty() )
3371 // create faces for all steps;
3372 // if such a face has been already created by sweep of edge,
3373 // assure that its orientation is OK
3374 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3376 vTool.SetExternalNormal();
3377 list< int >::iterator ind = freeInd.begin();
3378 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3379 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3381 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3382 int nbn = vTool.NbFaceNodes( *ind );
3384 case 3: { ///// triangle
3385 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3387 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3388 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3389 aMesh->ChangeElementNodes( f, nodes, nbn );
3392 case 4: { ///// quadrangle
3393 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3395 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3396 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3397 aMesh->ChangeElementNodes( f, nodes, nbn );
3401 if( (*v)->IsQuadratic() ) {
3402 if(nbn==6) { /////// quadratic triangle
3403 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3404 nodes[1], nodes[3], nodes[5] );
3406 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3407 nodes[1], nodes[3], nodes[5]));
3409 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3410 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3411 tmpnodes[0] = nodes[0];
3412 tmpnodes[1] = nodes[2];
3413 tmpnodes[2] = nodes[4];
3414 tmpnodes[3] = nodes[1];
3415 tmpnodes[4] = nodes[3];
3416 tmpnodes[5] = nodes[5];
3417 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3420 else { /////// quadratic quadrangle
3421 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3422 nodes[1], nodes[3], nodes[5], nodes[7] );
3424 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3425 nodes[1], nodes[3], nodes[5], nodes[7]));
3427 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3428 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3429 tmpnodes[0] = nodes[0];
3430 tmpnodes[1] = nodes[2];
3431 tmpnodes[2] = nodes[4];
3432 tmpnodes[3] = nodes[6];
3433 tmpnodes[4] = nodes[1];
3434 tmpnodes[5] = nodes[3];
3435 tmpnodes[6] = nodes[5];
3436 tmpnodes[7] = nodes[7];
3437 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3441 else { //////// polygon
3442 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3443 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3445 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3446 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3447 aMesh->ChangeElementNodes( f, nodes, nbn );
3450 while ( srcElements.Length() < myLastCreatedElems.Length() )
3451 srcElements.Append( *srcEdge );
3453 } // loop on free faces
3455 // go to the next volume
3457 while ( iVol++ < nbVolumesByStep ) v++;
3460 } // sweep free links into faces
3462 // Make a ceiling face with a normal external to a volume
3464 SMDS_VolumeTool lastVol( itElem->second.back() );
3466 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3468 lastVol.SetExternalNormal();
3469 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3470 int nbn = lastVol.NbFaceNodes( iF );
3473 if (!hasFreeLinks ||
3474 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3475 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3478 if (!hasFreeLinks ||
3479 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3480 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3483 if(itElem->second.back()->IsQuadratic()) {
3485 if (!hasFreeLinks ||
3486 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3487 nodes[1], nodes[3], nodes[5]) ) {
3488 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3489 nodes[1], nodes[3], nodes[5]));
3493 if (!hasFreeLinks ||
3494 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3495 nodes[1], nodes[3], nodes[5], nodes[7]) )
3496 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3497 nodes[1], nodes[3], nodes[5], nodes[7]));
3501 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3502 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3503 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3507 while ( srcElements.Length() < myLastCreatedElems.Length() )
3508 srcElements.Append( myLastCreatedElems.Last() );
3510 } // loop on swept elements
3513 //=======================================================================
3514 //function : RotationSweep
3516 //=======================================================================
3518 SMESH_MeshEditor::PGroupIDs
3519 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3520 const gp_Ax1& theAxis,
3521 const double theAngle,
3522 const int theNbSteps,
3523 const double theTol,
3524 const bool theMakeGroups,
3525 const bool theMakeWalls)
3527 myLastCreatedElems.Clear();
3528 myLastCreatedNodes.Clear();
3530 // source elements for each generated one
3531 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3533 MESSAGE( "RotationSweep()");
3535 aTrsf.SetRotation( theAxis, theAngle );
3537 aTrsf2.SetRotation( theAxis, theAngle/2. );
3539 gp_Lin aLine( theAxis );
3540 double aSqTol = theTol * theTol;
3542 SMESHDS_Mesh* aMesh = GetMeshDS();
3544 TNodeOfNodeListMap mapNewNodes;
3545 TElemOfVecOfNnlmiMap mapElemNewNodes;
3546 TElemOfElemListMap newElemsMap;
3549 TIDSortedElemSet::iterator itElem;
3550 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3551 const SMDS_MeshElement* elem = *itElem;
3552 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3554 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3555 newNodesItVec.reserve( elem->NbNodes() );
3557 // loop on elem nodes
3558 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3559 while ( itN->more() ) {
3560 // check if a node has been already sweeped
3561 const SMDS_MeshNode* node = cast2Node( itN->next() );
3563 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3565 aXYZ.Coord( coord[0], coord[1], coord[2] );
3566 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3568 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3569 if ( nIt == mapNewNodes.end() ) {
3570 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3571 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3574 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3576 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3577 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3578 const SMDS_MeshNode * newNode = node;
3579 for ( int i = 0; i < theNbSteps; i++ ) {
3581 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3583 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3584 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3585 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3586 myLastCreatedNodes.Append(newNode);
3587 srcNodes.Append( node );
3588 listNewNodes.push_back( newNode );
3589 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3590 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3593 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3595 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3596 myLastCreatedNodes.Append(newNode);
3597 srcNodes.Append( node );
3598 listNewNodes.push_back( newNode );
3601 listNewNodes.push_back( newNode );
3602 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3603 listNewNodes.push_back( newNode );
3610 // if current elem is quadratic and current node is not medium
3611 // we have to check - may be it is needed to insert additional nodes
3612 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3613 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3614 if(listNewNodes.size()==theNbSteps) {
3615 listNewNodes.clear();
3617 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3619 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3620 const SMDS_MeshNode * newNode = node;
3622 for(int i = 0; i<theNbSteps; i++) {
3623 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3624 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3625 cout<<" 3 AddNode: "<<newNode;
3626 myLastCreatedNodes.Append(newNode);
3627 listNewNodes.push_back( newNode );
3628 srcNodes.Append( node );
3629 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3630 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3631 cout<<" 4 AddNode: "<<newNode;
3632 myLastCreatedNodes.Append(newNode);
3633 srcNodes.Append( node );
3634 listNewNodes.push_back( newNode );
3638 listNewNodes.push_back( newNode );
3644 newNodesItVec.push_back( nIt );
3646 // make new elements
3647 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3651 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3653 PGroupIDs newGroupIDs;
3654 if ( theMakeGroups )
3655 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3661 //=======================================================================
3662 //function : CreateNode
3664 //=======================================================================
3665 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3668 const double tolnode,
3669 SMESH_SequenceOfNode& aNodes)
3671 myLastCreatedElems.Clear();
3672 myLastCreatedNodes.Clear();
3675 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3677 // try to search in sequence of existing nodes
3678 // if aNodes.Length()>0 we 'nave to use given sequence
3679 // else - use all nodes of mesh
3680 if(aNodes.Length()>0) {
3682 for(i=1; i<=aNodes.Length(); i++) {
3683 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3684 if(P1.Distance(P2)<tolnode)
3685 return aNodes.Value(i);
3689 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3690 while(itn->more()) {
3691 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3692 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3693 if(P1.Distance(P2)<tolnode)
3698 // create new node and return it
3699 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3700 myLastCreatedNodes.Append(NewNode);
3705 //=======================================================================
3706 //function : ExtrusionSweep
3708 //=======================================================================
3710 SMESH_MeshEditor::PGroupIDs
3711 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3712 const gp_Vec& theStep,
3713 const int theNbSteps,
3714 TElemOfElemListMap& newElemsMap,
3715 const bool theMakeGroups,
3717 const double theTolerance)
3719 ExtrusParam aParams;
3720 aParams.myDir = gp_Dir(theStep);
3721 aParams.myNodes.Clear();
3722 aParams.mySteps = new TColStd_HSequenceOfReal;
3724 for(i=1; i<=theNbSteps; i++)
3725 aParams.mySteps->Append(theStep.Magnitude());
3728 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3732 //=======================================================================
3733 //function : ExtrusionSweep
3735 //=======================================================================
3737 SMESH_MeshEditor::PGroupIDs
3738 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3739 ExtrusParam& theParams,
3740 TElemOfElemListMap& newElemsMap,
3741 const bool theMakeGroups,
3743 const double theTolerance)
3745 myLastCreatedElems.Clear();
3746 myLastCreatedNodes.Clear();
3748 // source elements for each generated one
3749 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3751 SMESHDS_Mesh* aMesh = GetMeshDS();
3753 int nbsteps = theParams.mySteps->Length();
3755 TNodeOfNodeListMap mapNewNodes;
3756 //TNodeOfNodeVecMap mapNewNodes;
3757 TElemOfVecOfNnlmiMap mapElemNewNodes;
3758 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3761 TIDSortedElemSet::iterator itElem;
3762 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3763 // check element type
3764 const SMDS_MeshElement* elem = *itElem;
3765 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3768 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3769 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3770 newNodesItVec.reserve( elem->NbNodes() );
3772 // loop on elem nodes
3773 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3774 while ( itN->more() )
3776 // check if a node has been already sweeped
3777 const SMDS_MeshNode* node = cast2Node( itN->next() );
3778 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3779 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3780 if ( nIt == mapNewNodes.end() ) {
3781 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3782 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3783 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3784 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3785 //vecNewNodes.reserve(nbsteps);
3788 double coord[] = { node->X(), node->Y(), node->Z() };
3789 //int nbsteps = theParams.mySteps->Length();
3790 for ( int i = 0; i < nbsteps; i++ ) {
3791 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3792 // create additional node
3793 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3794 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3795 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3796 if( theFlags & EXTRUSION_FLAG_SEW ) {
3797 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3798 theTolerance, theParams.myNodes);
3799 listNewNodes.push_back( newNode );
3802 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3803 myLastCreatedNodes.Append(newNode);
3804 srcNodes.Append( node );
3805 listNewNodes.push_back( newNode );
3808 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3809 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3810 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3811 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3812 if( theFlags & EXTRUSION_FLAG_SEW ) {
3813 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3814 theTolerance, theParams.myNodes);
3815 listNewNodes.push_back( newNode );
3816 //vecNewNodes[i]=newNode;
3819 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3820 myLastCreatedNodes.Append(newNode);
3821 srcNodes.Append( node );
3822 listNewNodes.push_back( newNode );
3823 //vecNewNodes[i]=newNode;
3828 // if current elem is quadratic and current node is not medium
3829 // we have to check - may be it is needed to insert additional nodes
3830 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3831 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3832 if(listNewNodes.size()==nbsteps) {
3833 listNewNodes.clear();
3834 double coord[] = { node->X(), node->Y(), node->Z() };
3835 for ( int i = 0; i < nbsteps; i++ ) {
3836 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3837 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3838 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3839 if( theFlags & EXTRUSION_FLAG_SEW ) {
3840 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3841 theTolerance, theParams.myNodes);
3842 listNewNodes.push_back( newNode );
3845 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3846 myLastCreatedNodes.Append(newNode);
3847 srcNodes.Append( node );
3848 listNewNodes.push_back( newNode );
3850 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3851 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3852 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3853 if( theFlags & EXTRUSION_FLAG_SEW ) {
3854 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3855 theTolerance, theParams.myNodes);
3856 listNewNodes.push_back( newNode );
3859 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3860 myLastCreatedNodes.Append(newNode);
3861 srcNodes.Append( node );
3862 listNewNodes.push_back( newNode );
3868 newNodesItVec.push_back( nIt );
3870 // make new elements
3871 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3874 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3875 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3877 PGroupIDs newGroupIDs;
3878 if ( theMakeGroups )
3879 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3885 //=======================================================================
3886 //class : SMESH_MeshEditor_PathPoint
3887 //purpose : auxiliary class
3888 //=======================================================================
3889 class SMESH_MeshEditor_PathPoint {
3891 SMESH_MeshEditor_PathPoint() {
3892 myPnt.SetCoord(99., 99., 99.);
3893 myTgt.SetCoord(1.,0.,0.);
3897 void SetPnt(const gp_Pnt& aP3D){
3900 void SetTangent(const gp_Dir& aTgt){
3903 void SetAngle(const double& aBeta){
3906 void SetParameter(const double& aPrm){
3909 const gp_Pnt& Pnt()const{
3912 const gp_Dir& Tangent()const{
3915 double Angle()const{
3918 double Parameter()const{
3930 //=======================================================================
3931 //function : ExtrusionAlongTrack
3933 //=======================================================================
3934 SMESH_MeshEditor::Extrusion_Error
3935 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3936 SMESH_subMesh* theTrack,
3937 const SMDS_MeshNode* theN1,
3938 const bool theHasAngles,
3939 list<double>& theAngles,
3940 const bool theLinearVariation,
3941 const bool theHasRefPoint,
3942 const gp_Pnt& theRefPoint,
3943 const bool theMakeGroups)
3945 myLastCreatedElems.Clear();
3946 myLastCreatedNodes.Clear();
3949 std::list<double> aPrms;
3950 TIDSortedElemSet::iterator itElem;
3953 TopoDS_Edge aTrackEdge;
3954 TopoDS_Vertex aV1, aV2;
3956 SMDS_ElemIteratorPtr aItE;
3957 SMDS_NodeIteratorPtr aItN;
3958 SMDSAbs_ElementType aTypeE;
3960 TNodeOfNodeListMap mapNewNodes;
3963 aNbE = theElements.size();
3966 return EXTR_NO_ELEMENTS;
3968 // 1.1 Track Pattern
3971 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3973 aItE = pSubMeshDS->GetElements();
3974 while ( aItE->more() ) {
3975 const SMDS_MeshElement* pE = aItE->next();
3976 aTypeE = pE->GetType();
3977 // Pattern must contain links only
3978 if ( aTypeE != SMDSAbs_Edge )
3979 return EXTR_PATH_NOT_EDGE;
3982 list<SMESH_MeshEditor_PathPoint> fullList;
3984 const TopoDS_Shape& aS = theTrack->GetSubShape();
3985 // Sub shape for the Pattern must be an Edge or Wire
3986 if( aS.ShapeType() == TopAbs_EDGE ) {
3987 aTrackEdge = TopoDS::Edge( aS );
3988 // the Edge must not be degenerated
3989 if ( BRep_Tool::Degenerated( aTrackEdge ) )
3990 return EXTR_BAD_PATH_SHAPE;
3991 TopExp::Vertices( aTrackEdge, aV1, aV2 );
3992 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3993 const SMDS_MeshNode* aN1 = aItN->next();
3994 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3995 const SMDS_MeshNode* aN2 = aItN->next();
3996 // starting node must be aN1 or aN2
3997 if ( !( aN1 == theN1 || aN2 == theN1 ) )
3998 return EXTR_BAD_STARTING_NODE;
3999 aItN = pSubMeshDS->GetNodes();
4000 while ( aItN->more() ) {
4001 const SMDS_MeshNode* pNode = aItN->next();
4002 const SMDS_EdgePosition* pEPos =
4003 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4004 double aT = pEPos->GetUParameter();
4005 aPrms.push_back( aT );
4007 //Extrusion_Error err =
4008 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4010 else if( aS.ShapeType() == TopAbs_WIRE ) {
4011 list< SMESH_subMesh* > LSM;
4012 TopTools_SequenceOfShape Edges;
4013 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4014 while(itSM->more()) {
4015 SMESH_subMesh* SM = itSM->next();
4017 const TopoDS_Shape& aS = SM->GetSubShape();
4020 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4021 int startNid = theN1->GetID();
4022 TColStd_MapOfInteger UsedNums;
4023 int NbEdges = Edges.Length();
4025 for(; i<=NbEdges; i++) {
4027 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4028 for(; itLSM!=LSM.end(); itLSM++) {
4030 if(UsedNums.Contains(k)) continue;
4031 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4032 SMESH_subMesh* locTrack = *itLSM;
4033 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4034 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4035 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4036 const SMDS_MeshNode* aN1 = aItN->next();
4037 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4038 const SMDS_MeshNode* aN2 = aItN->next();
4039 // starting node must be aN1 or aN2
4040 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4041 // 2. Collect parameters on the track edge
4043 aItN = locMeshDS->GetNodes();
4044 while ( aItN->more() ) {
4045 const SMDS_MeshNode* pNode = aItN->next();
4046 const SMDS_EdgePosition* pEPos =
4047 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4048 double aT = pEPos->GetUParameter();
4049 aPrms.push_back( aT );
4051 list<SMESH_MeshEditor_PathPoint> LPP;
4052 //Extrusion_Error err =
4053 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4054 LLPPs.push_back(LPP);
4056 // update startN for search following egde
4057 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4058 else startNid = aN1->GetID();
4062 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4063 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4064 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4065 for(; itPP!=firstList.end(); itPP++) {
4066 fullList.push_back( *itPP );
4068 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4069 fullList.pop_back();
4071 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4072 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4073 itPP = currList.begin();
4074 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4075 gp_Dir D1 = PP1.Tangent();
4076 gp_Dir D2 = PP2.Tangent();
4077 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4078 (D1.Z()+D2.Z())/2 ) );
4079 PP1.SetTangent(Dnew);
4080 fullList.push_back(PP1);
4082 for(; itPP!=firstList.end(); itPP++) {
4083 fullList.push_back( *itPP );
4085 PP1 = fullList.back();
4086 fullList.pop_back();
4088 // if wire not closed
4089 fullList.push_back(PP1);
4093 return EXTR_BAD_PATH_SHAPE;
4096 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4097 theHasRefPoint, theRefPoint, theMakeGroups);
4101 //=======================================================================
4102 //function : ExtrusionAlongTrack
4104 //=======================================================================
4105 SMESH_MeshEditor::Extrusion_Error
4106 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4107 SMESH_Mesh* theTrack,
4108 const SMDS_MeshNode* theN1,
4109 const bool theHasAngles,
4110 list<double>& theAngles,
4111 const bool theLinearVariation,
4112 const bool theHasRefPoint,
4113 const gp_Pnt& theRefPoint,
4114 const bool theMakeGroups)
4116 myLastCreatedElems.Clear();
4117 myLastCreatedNodes.Clear();
4120 std::list<double> aPrms;
4121 TIDSortedElemSet::iterator itElem;
4124 TopoDS_Edge aTrackEdge;
4125 TopoDS_Vertex aV1, aV2;
4127 SMDS_ElemIteratorPtr aItE;
4128 SMDS_NodeIteratorPtr aItN;
4129 SMDSAbs_ElementType aTypeE;
4131 TNodeOfNodeListMap mapNewNodes;
4134 aNbE = theElements.size();
4137 return EXTR_NO_ELEMENTS;
4139 // 1.1 Track Pattern
4142 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4144 aItE = pMeshDS->elementsIterator();
4145 while ( aItE->more() ) {
4146 const SMDS_MeshElement* pE = aItE->next();
4147 aTypeE = pE->GetType();
4148 // Pattern must contain links only
4149 if ( aTypeE != SMDSAbs_Edge )
4150 return EXTR_PATH_NOT_EDGE;
4153 list<SMESH_MeshEditor_PathPoint> fullList;
4155 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4156 // Sub shape for the Pattern must be an Edge or Wire
4157 if( aS.ShapeType() == TopAbs_EDGE ) {
4158 aTrackEdge = TopoDS::Edge( aS );
4159 // the Edge must not be degenerated
4160 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4161 return EXTR_BAD_PATH_SHAPE;
4162 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4163 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4164 const SMDS_MeshNode* aN1 = aItN->next();
4165 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4166 const SMDS_MeshNode* aN2 = aItN->next();
4167 // starting node must be aN1 or aN2
4168 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4169 return EXTR_BAD_STARTING_NODE;
4170 aItN = pMeshDS->nodesIterator();
4171 while ( aItN->more() ) {
4172 const SMDS_MeshNode* pNode = aItN->next();
4173 if( pNode==aN1 || pNode==aN2 ) continue;
4174 const SMDS_EdgePosition* pEPos =
4175 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4176 double aT = pEPos->GetUParameter();
4177 aPrms.push_back( aT );
4179 //Extrusion_Error err =
4180 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4182 else if( aS.ShapeType() == TopAbs_WIRE ) {
4183 list< SMESH_subMesh* > LSM;
4184 TopTools_SequenceOfShape Edges;
4185 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4186 for(; eExp.More(); eExp.Next()) {
4187 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4188 if( BRep_Tool::Degenerated(E) ) continue;
4189 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4195 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4196 int startNid = theN1->GetID();
4197 TColStd_MapOfInteger UsedNums;
4198 int NbEdges = Edges.Length();
4200 for(; i<=NbEdges; i++) {
4202 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4203 for(; itLSM!=LSM.end(); itLSM++) {
4205 if(UsedNums.Contains(k)) continue;
4206 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4207 SMESH_subMesh* locTrack = *itLSM;
4208 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4209 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4210 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4211 const SMDS_MeshNode* aN1 = aItN->next();
4212 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4213 const SMDS_MeshNode* aN2 = aItN->next();
4214 // starting node must be aN1 or aN2
4215 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4216 // 2. Collect parameters on the track edge
4218 aItN = locMeshDS->GetNodes();
4219 while ( aItN->more() ) {
4220 const SMDS_MeshNode* pNode = aItN->next();
4221 const SMDS_EdgePosition* pEPos =
4222 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4223 double aT = pEPos->GetUParameter();
4224 aPrms.push_back( aT );
4226 list<SMESH_MeshEditor_PathPoint> LPP;
4227 //Extrusion_Error err =
4228 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4229 LLPPs.push_back(LPP);
4231 // update startN for search following egde
4232 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4233 else startNid = aN1->GetID();
4237 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4238 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4239 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4240 for(; itPP!=firstList.end(); itPP++) {
4241 fullList.push_back( *itPP );
4243 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4244 fullList.pop_back();
4246 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4247 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4248 itPP = currList.begin();
4249 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4250 gp_Pnt P1 = PP1.Pnt();
4251 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4252 gp_Pnt P2 = PP2.Pnt();
4253 gp_Dir D1 = PP1.Tangent();
4254 gp_Dir D2 = PP2.Tangent();
4255 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4256 (D1.Z()+D2.Z())/2 ) );
4257 PP1.SetTangent(Dnew);
4258 fullList.push_back(PP1);
4260 for(; itPP!=currList.end(); itPP++) {
4261 fullList.push_back( *itPP );
4263 PP1 = fullList.back();
4264 fullList.pop_back();
4266 // if wire not closed
4267 fullList.push_back(PP1);
4271 return EXTR_BAD_PATH_SHAPE;
4274 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4275 theHasRefPoint, theRefPoint, theMakeGroups);
4279 //=======================================================================
4280 //function : MakeEdgePathPoints
4281 //purpose : auxilary for ExtrusionAlongTrack
4282 //=======================================================================
4283 SMESH_MeshEditor::Extrusion_Error
4284 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4285 const TopoDS_Edge& aTrackEdge,
4287 list<SMESH_MeshEditor_PathPoint>& LPP)
4289 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4291 aTolVec2=aTolVec*aTolVec;
4293 TopoDS_Vertex aV1, aV2;
4294 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4295 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4296 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4297 // 2. Collect parameters on the track edge
4298 aPrms.push_front( aT1 );
4299 aPrms.push_back( aT2 );
4302 if( FirstIsStart ) {
4313 SMESH_MeshEditor_PathPoint aPP;
4314 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4315 std::list<double>::iterator aItD = aPrms.begin();
4316 for(; aItD != aPrms.end(); ++aItD) {
4320 aC3D->D1( aT, aP3D, aVec );
4321 aL2 = aVec.SquareMagnitude();
4322 if ( aL2 < aTolVec2 )
4323 return EXTR_CANT_GET_TANGENT;
4324 gp_Dir aTgt( aVec );
4326 aPP.SetTangent( aTgt );
4327 aPP.SetParameter( aT );
4334 //=======================================================================
4335 //function : MakeExtrElements
4336 //purpose : auxilary for ExtrusionAlongTrack
4337 //=======================================================================
4338 SMESH_MeshEditor::Extrusion_Error
4339 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4340 list<SMESH_MeshEditor_PathPoint>& fullList,
4341 const bool theHasAngles,
4342 list<double>& theAngles,
4343 const bool theLinearVariation,
4344 const bool theHasRefPoint,
4345 const gp_Pnt& theRefPoint,
4346 const bool theMakeGroups)
4348 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4349 int aNbTP = fullList.size();
4350 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4352 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4353 LinearAngleVariation(aNbTP-1, theAngles);
4355 vector<double> aAngles( aNbTP );
4357 for(; j<aNbTP; ++j) {
4360 if ( theHasAngles ) {
4362 std::list<double>::iterator aItD = theAngles.begin();
4363 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4365 aAngles[j] = anAngle;
4368 // fill vector of path points with angles
4369 //aPPs.resize(fullList.size());
4371 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4372 for(; itPP!=fullList.end(); itPP++) {
4374 SMESH_MeshEditor_PathPoint PP = *itPP;
4375 PP.SetAngle(aAngles[j]);
4379 TNodeOfNodeListMap mapNewNodes;
4380 TElemOfVecOfNnlmiMap mapElemNewNodes;
4381 TElemOfElemListMap newElemsMap;
4382 TIDSortedElemSet::iterator itElem;
4385 SMDSAbs_ElementType aTypeE;
4386 // source elements for each generated one
4387 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4389 // 3. Center of rotation aV0
4390 gp_Pnt aV0 = theRefPoint;
4392 if ( !theHasRefPoint ) {
4394 aGC.SetCoord( 0.,0.,0. );
4396 itElem = theElements.begin();
4397 for ( ; itElem != theElements.end(); itElem++ ) {
4398 const SMDS_MeshElement* elem = *itElem;
4400 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4401 while ( itN->more() ) {
4402 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4407 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4408 list<const SMDS_MeshNode*> aLNx;
4409 mapNewNodes[node] = aLNx;
4411 gp_XYZ aXYZ( aX, aY, aZ );
4419 } // if (!theHasRefPoint) {
4420 mapNewNodes.clear();
4422 // 4. Processing the elements
4423 SMESHDS_Mesh* aMesh = GetMeshDS();
4425 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4426 // check element type
4427 const SMDS_MeshElement* elem = *itElem;
4428 aTypeE = elem->GetType();
4429 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4432 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4433 newNodesItVec.reserve( elem->NbNodes() );
4435 // loop on elem nodes
4437 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4438 while ( itN->more() )
4441 // check if a node has been already processed
4442 const SMDS_MeshNode* node =
4443 static_cast<const SMDS_MeshNode*>( itN->next() );
4444 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4445 if ( nIt == mapNewNodes.end() ) {
4446 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4447 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4450 aX = node->X(); aY = node->Y(); aZ = node->Z();
4452 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4453 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4454 gp_Ax1 anAx1, anAxT1T0;
4455 gp_Dir aDT1x, aDT0x, aDT1T0;
4460 aPN0.SetCoord(aX, aY, aZ);
4462 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4464 aDT0x= aPP0.Tangent();
4465 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4467 for ( j = 1; j < aNbTP; ++j ) {
4468 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4470 aDT1x = aPP1.Tangent();
4471 aAngle1x = aPP1.Angle();
4473 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4475 gp_Vec aV01x( aP0x, aP1x );
4476 aTrsf.SetTranslation( aV01x );
4479 aV1x = aV0x.Transformed( aTrsf );
4480 aPN1 = aPN0.Transformed( aTrsf );
4482 // rotation 1 [ T1,T0 ]
4483 aAngleT1T0=-aDT1x.Angle( aDT0x );
4484 if (fabs(aAngleT1T0) > aTolAng) {
4486 anAxT1T0.SetLocation( aV1x );
4487 anAxT1T0.SetDirection( aDT1T0 );
4488 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4490 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4494 if ( theHasAngles ) {
4495 anAx1.SetLocation( aV1x );
4496 anAx1.SetDirection( aDT1x );
4497 aTrsfRot.SetRotation( anAx1, aAngle1x );
4499 aPN1 = aPN1.Transformed( aTrsfRot );
4503 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4504 // create additional node
4505 double x = ( aPN1.X() + aPN0.X() )/2.;
4506 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4507 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4508 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4509 myLastCreatedNodes.Append(newNode);
4510 srcNodes.Append( node );
4511 listNewNodes.push_back( newNode );
4516 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4517 myLastCreatedNodes.Append(newNode);
4518 srcNodes.Append( node );
4519 listNewNodes.push_back( newNode );
4529 // if current elem is quadratic and current node is not medium
4530 // we have to check - may be it is needed to insert additional nodes
4531 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4532 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4533 if(listNewNodes.size()==aNbTP-1) {
4534 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4535 gp_XYZ P(node->X(), node->Y(), node->Z());
4536 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4538 for(i=0; i<aNbTP-1; i++) {
4539 const SMDS_MeshNode* N = *it;
4540 double x = ( N->X() + P.X() )/2.;
4541 double y = ( N->Y() + P.Y() )/2.;
4542 double z = ( N->Z() + P.Z() )/2.;
4543 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4544 srcNodes.Append( node );
4545 myLastCreatedNodes.Append(newN);
4548 P = gp_XYZ(N->X(),N->Y(),N->Z());
4550 listNewNodes.clear();
4551 for(i=0; i<2*(aNbTP-1); i++) {
4552 listNewNodes.push_back(aNodes[i]);
4558 newNodesItVec.push_back( nIt );
4560 // make new elements
4561 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4562 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4563 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4566 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4568 if ( theMakeGroups )
4569 generateGroups( srcNodes, srcElems, "extruded");
4575 //=======================================================================
4576 //function : LinearAngleVariation
4577 //purpose : auxilary for ExtrusionAlongTrack
4578 //=======================================================================
4579 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4580 list<double>& Angles)
4582 int nbAngles = Angles.size();
4583 if( nbSteps > nbAngles ) {
4584 vector<double> theAngles(nbAngles);
4585 list<double>::iterator it = Angles.begin();
4587 for(; it!=Angles.end(); it++) {
4589 theAngles[i] = (*it);
4592 double rAn2St = double( nbAngles ) / double( nbSteps );
4593 double angPrev = 0, angle;
4594 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4595 double angCur = rAn2St * ( iSt+1 );
4596 double angCurFloor = floor( angCur );
4597 double angPrevFloor = floor( angPrev );
4598 if ( angPrevFloor == angCurFloor )
4599 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4601 int iP = int( angPrevFloor );
4602 double angPrevCeil = ceil(angPrev);
4603 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4605 int iC = int( angCurFloor );
4606 if ( iC < nbAngles )
4607 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4609 iP = int( angPrevCeil );
4611 angle += theAngles[ iC ];
4613 res.push_back(angle);
4618 for(; it!=res.end(); it++)
4619 Angles.push_back( *it );
4624 //=======================================================================
4625 //function : Transform
4627 //=======================================================================
4629 SMESH_MeshEditor::PGroupIDs
4630 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4631 const gp_Trsf& theTrsf,
4633 const bool theMakeGroups,
4634 SMESH_Mesh* theTargetMesh)
4636 myLastCreatedElems.Clear();
4637 myLastCreatedNodes.Clear();
4639 bool needReverse = false;
4640 string groupPostfix;
4641 switch ( theTrsf.Form() ) {
4646 groupPostfix = "mirrored";
4649 groupPostfix = "rotated";
4651 case gp_Translation:
4652 groupPostfix = "translated";
4655 groupPostfix = "scaled";
4658 needReverse = false;
4659 groupPostfix = "transformed";
4662 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4663 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4664 SMESHDS_Mesh* aMesh = GetMeshDS();
4667 // map old node to new one
4668 TNodeNodeMap nodeMap;
4670 // elements sharing moved nodes; those of them which have all
4671 // nodes mirrored but are not in theElems are to be reversed
4672 TIDSortedElemSet inverseElemSet;
4674 // source elements for each generated one
4675 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4678 TIDSortedElemSet::iterator itElem;
4679 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4680 const SMDS_MeshElement* elem = *itElem;
4684 // loop on elem nodes
4685 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4686 while ( itN->more() ) {
4688 // check if a node has been already transformed
4689 const SMDS_MeshNode* node = cast2Node( itN->next() );
4690 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4691 nodeMap.insert( make_pair ( node, node ));
4692 if ( !n2n_isnew.second )
4696 coord[0] = node->X();
4697 coord[1] = node->Y();
4698 coord[2] = node->Z();
4699 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4700 if ( theTargetMesh ) {
4701 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4702 n2n_isnew.first->second = newNode;
4703 myLastCreatedNodes.Append(newNode);
4704 srcNodes.Append( node );
4706 else if ( theCopy ) {
4707 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4708 n2n_isnew.first->second = newNode;
4709 myLastCreatedNodes.Append(newNode);
4710 srcNodes.Append( node );
4713 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4714 // node position on shape becomes invalid
4715 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4716 ( SMDS_SpacePosition::originSpacePosition() );
4719 // keep inverse elements
4720 if ( !theCopy && !theTargetMesh && needReverse ) {
4721 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4722 while ( invElemIt->more() ) {
4723 const SMDS_MeshElement* iel = invElemIt->next();
4724 inverseElemSet.insert( iel );
4730 // either create new elements or reverse mirrored ones
4731 if ( !theCopy && !needReverse && !theTargetMesh )
4734 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4735 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4736 theElems.insert( *invElemIt );
4738 // replicate or reverse elements
4741 REV_TETRA = 0, // = nbNodes - 4
4742 REV_PYRAMID = 1, // = nbNodes - 4
4743 REV_PENTA = 2, // = nbNodes - 4
4745 REV_HEXA = 4, // = nbNodes - 4
4749 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4750 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4751 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4752 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4753 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4754 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4757 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4759 const SMDS_MeshElement* elem = *itElem;
4760 if ( !elem || elem->GetType() == SMDSAbs_Node )
4763 int nbNodes = elem->NbNodes();
4764 int elemType = elem->GetType();
4766 if (elem->IsPoly()) {
4767 // Polygon or Polyhedral Volume
4768 switch ( elemType ) {
4771 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4773 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4774 while (itN->more()) {
4775 const SMDS_MeshNode* node =
4776 static_cast<const SMDS_MeshNode*>(itN->next());
4777 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4778 if (nodeMapIt == nodeMap.end())
4779 break; // not all nodes transformed
4781 // reverse mirrored faces and volumes
4782 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4784 poly_nodes[iNode] = (*nodeMapIt).second;
4788 if ( iNode != nbNodes )
4789 continue; // not all nodes transformed
4791 if ( theTargetMesh ) {
4792 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4793 srcElems.Append( elem );
4795 else if ( theCopy ) {
4796 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4797 srcElems.Append( elem );
4800 aMesh->ChangePolygonNodes(elem, poly_nodes);
4804 case SMDSAbs_Volume:
4806 // ATTENTION: Reversing is not yet done!!!
4807 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4808 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4810 MESSAGE("Warning: bad volumic element");
4814 vector<const SMDS_MeshNode*> poly_nodes;
4815 vector<int> quantities;
4817 bool allTransformed = true;
4818 int nbFaces = aPolyedre->NbFaces();
4819 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4820 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4821 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4822 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4823 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4824 if (nodeMapIt == nodeMap.end()) {
4825 allTransformed = false; // not all nodes transformed
4827 poly_nodes.push_back((*nodeMapIt).second);
4830 quantities.push_back(nbFaceNodes);
4832 if ( !allTransformed )
4833 continue; // not all nodes transformed
4835 if ( theTargetMesh ) {
4836 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4837 srcElems.Append( elem );
4839 else if ( theCopy ) {
4840 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4841 srcElems.Append( elem );
4844 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4854 int* i = index[ FORWARD ];
4855 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4856 if ( elemType == SMDSAbs_Face )
4857 i = index[ REV_FACE ];
4859 i = index[ nbNodes - 4 ];
4861 if(elem->IsQuadratic()) {
4862 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4865 if(nbNodes==3) { // quadratic edge
4866 static int anIds[] = {1,0,2};
4869 else if(nbNodes==6) { // quadratic triangle
4870 static int anIds[] = {0,2,1,5,4,3};
4873 else if(nbNodes==8) { // quadratic quadrangle
4874 static int anIds[] = {0,3,2,1,7,6,5,4};
4877 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4878 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4881 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4882 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4885 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4886 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4889 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4890 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4896 // find transformed nodes
4897 vector<const SMDS_MeshNode*> nodes(nbNodes);
4899 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4900 while ( itN->more() ) {
4901 const SMDS_MeshNode* node =
4902 static_cast<const SMDS_MeshNode*>( itN->next() );
4903 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4904 if ( nodeMapIt == nodeMap.end() )
4905 break; // not all nodes transformed
4906 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4908 if ( iNode != nbNodes )
4909 continue; // not all nodes transformed
4911 if ( theTargetMesh ) {
4912 if ( SMDS_MeshElement* copy =
4913 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4914 myLastCreatedElems.Append( copy );
4915 srcElems.Append( elem );
4918 else if ( theCopy ) {
4919 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4920 myLastCreatedElems.Append( copy );
4921 srcElems.Append( elem );
4925 // reverse element as it was reversed by transformation
4927 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4931 PGroupIDs newGroupIDs;
4933 if ( theMakeGroups && theCopy ||
4934 theMakeGroups && theTargetMesh )
4935 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4940 //=======================================================================
4942 * \brief Create groups of elements made during transformation
4943 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4944 * \param elemGens - elements making corresponding myLastCreatedElems
4945 * \param postfix - to append to names of new groups
4947 //=======================================================================
4949 SMESH_MeshEditor::PGroupIDs
4950 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4951 const SMESH_SequenceOfElemPtr& elemGens,
4952 const std::string& postfix,
4953 SMESH_Mesh* targetMesh)
4955 PGroupIDs newGroupIDs( new list<int> );
4956 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4958 // Sort existing groups by types and collect their names
4960 // to store an old group and a generated new one
4961 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4962 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4964 set< string > groupNames;
4966 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4967 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4968 while ( groupIt->more() ) {
4969 SMESH_Group * group = groupIt->next();
4970 if ( !group ) continue;
4971 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4972 if ( !groupDS || groupDS->IsEmpty() ) continue;
4973 groupNames.insert( group->GetName() );
4974 groupDS->SetStoreName( group->GetName() );
4975 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4980 // loop on nodes and elements
4981 for ( int isNodes = 0; isNodes < 2; ++isNodes )
4983 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
4984 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4985 if ( gens.Length() != elems.Length() )
4986 throw SALOME_Exception(LOCALIZED("invalid args"));
4988 // loop on created elements
4989 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4991 const SMDS_MeshElement* sourceElem = gens( iElem );
4992 if ( !sourceElem ) {
4993 MESSAGE("generateGroups(): NULL source element");
4996 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
4997 if ( groupsOldNew.empty() ) {
4998 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4999 ++iElem; // skip all elements made by sourceElem
5002 // collect all elements made by sourceElem
5003 list< const SMDS_MeshElement* > resultElems;
5004 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5005 if ( resElem != sourceElem )
5006 resultElems.push_back( resElem );
5007 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5008 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5009 if ( resElem != sourceElem )
5010 resultElems.push_back( resElem );
5011 // do not generate element groups from node ones
5012 if ( sourceElem->GetType() == SMDSAbs_Node &&
5013 elems( iElem )->GetType() != SMDSAbs_Node )
5016 // add resultElems to groups made by ones the sourceElem belongs to
5017 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5018 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5020 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5021 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5023 SMDS_MeshGroup* & newGroup = gOldNew->second;
5024 if ( !newGroup )// create a new group
5027 string name = oldGroup->GetStoreName();
5028 if ( !targetMesh ) {
5032 while ( !groupNames.insert( name ).second ) // name exists
5038 TCollection_AsciiString nbStr(nb+1);
5039 name.resize( name.rfind('_')+1 );
5040 name += nbStr.ToCString();
5047 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5049 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5050 newGroup = & groupDS->SMDSGroup();
5051 newGroupIDs->push_back( id );
5054 // fill in a new group
5055 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5056 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5057 newGroup->Add( *resElemIt );
5060 } // loop on created elements
5061 }// loop on nodes and elements
5066 //=======================================================================
5067 //function : FindCoincidentNodes
5068 //purpose : Return list of group of nodes close to each other within theTolerance
5069 // Search among theNodes or in the whole mesh if theNodes is empty using
5070 // an Octree algorithm
5071 //=======================================================================
5073 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5074 const double theTolerance,
5075 TListOfListOfNodes & theGroupsOfNodes)
5077 myLastCreatedElems.Clear();
5078 myLastCreatedNodes.Clear();
5080 set<const SMDS_MeshNode*> nodes;
5081 if ( theNodes.empty() )
5082 { // get all nodes in the mesh
5083 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5084 while ( nIt->more() )
5085 nodes.insert( nodes.end(),nIt->next());
5089 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5093 //=======================================================================
5095 * \brief Implementation of search for the node closest to point
5097 //=======================================================================
5099 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5102 * \brief Constructor
5104 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5106 set<const SMDS_MeshNode*> nodes;
5108 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5109 while ( nIt->more() )
5110 nodes.insert( nodes.end(), nIt->next() );
5112 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5115 * \brief Do it's job
5117 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5119 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5120 list<const SMDS_MeshNode*> nodes;
5121 const double precision = 1e-6;
5122 //myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
5124 double minSqDist = DBL_MAX;
5126 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5128 // sort leafs by their distance from thePnt
5129 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5130 TDistTreeMap treeMap;
5131 list< SMESH_OctreeNode* > treeList;
5132 list< SMESH_OctreeNode* >::iterator trIt;
5133 treeList.push_back( myOctreeNode );
5134 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5136 SMESH_OctreeNode* tree = *trIt;
5137 if ( !tree->isLeaf() ) { // put children to the queue
5138 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5139 while ( cIt->more() )
5140 treeList.push_back( cIt->next() );
5142 else if ( tree->NbNodes() ) { // put tree to treeMap
5143 tree->getBox( box );
5144 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5145 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5146 if ( !it_in.second ) // not unique distance to box center
5147 treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
5150 // find distance after which there is no sense to check tree's
5151 double sqLimit = DBL_MAX;
5152 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5153 if ( treeMap.size() > 5 ) {
5154 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5155 closestTree->getBox( box );
5156 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5157 sqLimit = limit * limit;
5159 // get all nodes from trees
5160 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5161 if ( sqDist_tree->first > sqLimit )
5163 SMESH_OctreeNode* tree = sqDist_tree->second;
5164 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5167 // find closest among nodes
5168 minSqDist = DBL_MAX;
5169 const SMDS_MeshNode* closestNode = 0;
5170 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5171 for ( ; nIt != nodes.end(); ++nIt ) {
5172 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5173 if ( minSqDist > sqDist ) {
5183 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5185 SMESH_OctreeNode* myOctreeNode;
5188 //=======================================================================
5190 * \brief Return SMESH_NodeSearcher
5192 //=======================================================================
5194 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5196 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5199 //=======================================================================
5200 //function : SimplifyFace
5202 //=======================================================================
5203 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5204 vector<const SMDS_MeshNode *>& poly_nodes,
5205 vector<int>& quantities) const
5207 int nbNodes = faceNodes.size();
5212 set<const SMDS_MeshNode*> nodeSet;
5214 // get simple seq of nodes
5215 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5216 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5217 int iSimple = 0, nbUnique = 0;
5219 simpleNodes[iSimple++] = faceNodes[0];
5221 for (int iCur = 1; iCur < nbNodes; iCur++) {
5222 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5223 simpleNodes[iSimple++] = faceNodes[iCur];
5224 if (nodeSet.insert( faceNodes[iCur] ).second)
5228 int nbSimple = iSimple;
5229 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5239 bool foundLoop = (nbSimple > nbUnique);
5242 set<const SMDS_MeshNode*> loopSet;
5243 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5244 const SMDS_MeshNode* n = simpleNodes[iSimple];
5245 if (!loopSet.insert( n ).second) {
5249 int iC = 0, curLast = iSimple;
5250 for (; iC < curLast; iC++) {
5251 if (simpleNodes[iC] == n) break;
5253 int loopLen = curLast - iC;
5255 // create sub-element
5257 quantities.push_back(loopLen);
5258 for (; iC < curLast; iC++) {
5259 poly_nodes.push_back(simpleNodes[iC]);
5262 // shift the rest nodes (place from the first loop position)
5263 for (iC = curLast + 1; iC < nbSimple; iC++) {
5264 simpleNodes[iC - loopLen] = simpleNodes[iC];
5266 nbSimple -= loopLen;
5269 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5270 } // while (foundLoop)
5274 quantities.push_back(iSimple);
5275 for (int i = 0; i < iSimple; i++)
5276 poly_nodes.push_back(simpleNodes[i]);
5282 //=======================================================================
5283 //function : MergeNodes
5284 //purpose : In each group, the cdr of nodes are substituted by the first one
5286 //=======================================================================
5288 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5290 myLastCreatedElems.Clear();
5291 myLastCreatedNodes.Clear();
5293 SMESHDS_Mesh* aMesh = GetMeshDS();
5295 TNodeNodeMap nodeNodeMap; // node to replace - new node
5296 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5297 list< int > rmElemIds, rmNodeIds;
5299 // Fill nodeNodeMap and elems
5301 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5302 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5303 list<const SMDS_MeshNode*>& nodes = *grIt;
5304 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5305 const SMDS_MeshNode* nToKeep = *nIt;
5306 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5307 const SMDS_MeshNode* nToRemove = *nIt;
5308 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5309 if ( nToRemove != nToKeep ) {
5310 rmNodeIds.push_back( nToRemove->GetID() );
5311 AddToSameGroups( nToKeep, nToRemove, aMesh );
5314 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5315 while ( invElemIt->more() ) {
5316 const SMDS_MeshElement* elem = invElemIt->next();
5321 // Change element nodes or remove an element
5323 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5324 for ( ; eIt != elems.end(); eIt++ ) {
5325 const SMDS_MeshElement* elem = *eIt;
5326 int nbNodes = elem->NbNodes();
5327 int aShapeId = FindShape( elem );
5329 set<const SMDS_MeshNode*> nodeSet;
5330 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5331 int iUnique = 0, iCur = 0, nbRepl = 0;
5332 vector<int> iRepl( nbNodes );
5334 // get new seq of nodes
5335 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5336 while ( itN->more() ) {
5337 const SMDS_MeshNode* n =
5338 static_cast<const SMDS_MeshNode*>( itN->next() );
5340 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5341 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5343 // BUG 0020185: begin
5345 bool stopRecur = false;
5346 set<const SMDS_MeshNode*> nodesRecur;
5347 nodesRecur.insert(n);
5348 while (!stopRecur) {
5349 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5350 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5351 n = (*nnIt_i).second;
5352 if (!nodesRecur.insert(n).second) {
5353 // error: recursive dependancy
5362 iRepl[ nbRepl++ ] = iCur;
5364 curNodes[ iCur ] = n;
5365 bool isUnique = nodeSet.insert( n ).second;
5367 uniqueNodes[ iUnique++ ] = n;
5371 // Analyse element topology after replacement
5374 int nbUniqueNodes = nodeSet.size();
5375 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5376 // Polygons and Polyhedral volumes
5377 if (elem->IsPoly()) {
5379 if (elem->GetType() == SMDSAbs_Face) {
5381 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5383 for (; inode < nbNodes; inode++) {
5384 face_nodes[inode] = curNodes[inode];
5387 vector<const SMDS_MeshNode *> polygons_nodes;
5388 vector<int> quantities;
5389 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5393 for (int iface = 0; iface < nbNew - 1; iface++) {
5394 int nbNodes = quantities[iface];
5395 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5396 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5397 poly_nodes[ii] = polygons_nodes[inode];
5399 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5400 myLastCreatedElems.Append(newElem);
5402 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5404 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5407 rmElemIds.push_back(elem->GetID());
5411 else if (elem->GetType() == SMDSAbs_Volume) {
5412 // Polyhedral volume
5413 if (nbUniqueNodes < 4) {
5414 rmElemIds.push_back(elem->GetID());
5417 // each face has to be analized in order to check volume validity
5418 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5419 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5421 int nbFaces = aPolyedre->NbFaces();
5423 vector<const SMDS_MeshNode *> poly_nodes;
5424 vector<int> quantities;
5426 for (int iface = 1; iface <= nbFaces; iface++) {
5427 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5428 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5430 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5431 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5432 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5433 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5434 faceNode = (*nnIt).second;
5436 faceNodes[inode - 1] = faceNode;
5439 SimplifyFace(faceNodes, poly_nodes, quantities);
5442 if (quantities.size() > 3) {
5443 // to be done: remove coincident faces
5446 if (quantities.size() > 3)
5447 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5449 rmElemIds.push_back(elem->GetID());
5453 rmElemIds.push_back(elem->GetID());
5464 switch ( nbNodes ) {
5465 case 2: ///////////////////////////////////// EDGE
5466 isOk = false; break;
5467 case 3: ///////////////////////////////////// TRIANGLE
5468 isOk = false; break;
5470 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5472 else { //////////////////////////////////// QUADRANGLE
5473 if ( nbUniqueNodes < 3 )
5475 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5476 isOk = false; // opposite nodes stick
5479 case 6: ///////////////////////////////////// PENTAHEDRON
5480 if ( nbUniqueNodes == 4 ) {
5481 // ---------------------------------> tetrahedron
5483 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5484 // all top nodes stick: reverse a bottom
5485 uniqueNodes[ 0 ] = curNodes [ 1 ];
5486 uniqueNodes[ 1 ] = curNodes [ 0 ];
5488 else if (nbRepl == 3 &&
5489 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5490 // all bottom nodes stick: set a top before
5491 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5492 uniqueNodes[ 0 ] = curNodes [ 3 ];
5493 uniqueNodes[ 1 ] = curNodes [ 4 ];
5494 uniqueNodes[ 2 ] = curNodes [ 5 ];
5496 else if (nbRepl == 4 &&
5497 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5498 // a lateral face turns into a line: reverse a bottom
5499 uniqueNodes[ 0 ] = curNodes [ 1 ];
5500 uniqueNodes[ 1 ] = curNodes [ 0 ];
5505 else if ( nbUniqueNodes == 5 ) {
5506 // PENTAHEDRON --------------------> 2 tetrahedrons
5507 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5508 // a bottom node sticks with a linked top one
5510 SMDS_MeshElement* newElem =
5511 aMesh->AddVolume(curNodes[ 3 ],
5514 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5515 myLastCreatedElems.Append(newElem);
5517 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5518 // 2. : reverse a bottom
5519 uniqueNodes[ 0 ] = curNodes [ 1 ];
5520 uniqueNodes[ 1 ] = curNodes [ 0 ];
5530 if(elem->IsQuadratic()) { // Quadratic quadrangle
5543 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
5544 uniqueNodes[0] = curNodes[0];
5545 uniqueNodes[1] = curNodes[2];
5546 uniqueNodes[2] = curNodes[3];
5547 uniqueNodes[3] = curNodes[5];
5548 uniqueNodes[4] = curNodes[6];
5549 uniqueNodes[5] = curNodes[7];
5552 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
5553 uniqueNodes[0] = curNodes[0];
5554 uniqueNodes[1] = curNodes[1];
5555 uniqueNodes[2] = curNodes[2];
5556 uniqueNodes[3] = curNodes[4];
5557 uniqueNodes[4] = curNodes[5];
5558 uniqueNodes[5] = curNodes[6];
5561 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
5562 uniqueNodes[0] = curNodes[1];
5563 uniqueNodes[1] = curNodes[2];
5564 uniqueNodes[2] = curNodes[3];
5565 uniqueNodes[3] = curNodes[5];
5566 uniqueNodes[4] = curNodes[6];
5567 uniqueNodes[5] = curNodes[0];
5570 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
5571 uniqueNodes[0] = curNodes[0];
5572 uniqueNodes[1] = curNodes[1];
5573 uniqueNodes[2] = curNodes[3];
5574 uniqueNodes[3] = curNodes[4];
5575 uniqueNodes[4] = curNodes[6];
5576 uniqueNodes[5] = curNodes[7];
5579 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
5580 uniqueNodes[0] = curNodes[0];
5581 uniqueNodes[1] = curNodes[2];
5582 uniqueNodes[2] = curNodes[3];
5583 uniqueNodes[3] = curNodes[1];
5584 uniqueNodes[4] = curNodes[6];
5585 uniqueNodes[5] = curNodes[7];
5588 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
5589 uniqueNodes[0] = curNodes[0];
5590 uniqueNodes[1] = curNodes[1];
5591 uniqueNodes[2] = curNodes[2];
5592 uniqueNodes[3] = curNodes[4];
5593 uniqueNodes[4] = curNodes[5];
5594 uniqueNodes[5] = curNodes[7];
5597 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
5598 uniqueNodes[0] = curNodes[0];
5599 uniqueNodes[1] = curNodes[1];
5600 uniqueNodes[2] = curNodes[3];
5601 uniqueNodes[3] = curNodes[4];
5602 uniqueNodes[4] = curNodes[2];
5603 uniqueNodes[5] = curNodes[7];
5606 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
5607 uniqueNodes[0] = curNodes[0];
5608 uniqueNodes[1] = curNodes[1];
5609 uniqueNodes[2] = curNodes[2];
5610 uniqueNodes[3] = curNodes[4];
5611 uniqueNodes[4] = curNodes[5];
5612 uniqueNodes[5] = curNodes[3];
5618 //////////////////////////////////// HEXAHEDRON
5620 SMDS_VolumeTool hexa (elem);
5621 hexa.SetExternalNormal();
5622 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
5623 //////////////////////// ---> tetrahedron
5624 for ( int iFace = 0; iFace < 6; iFace++ ) {
5625 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5626 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5627 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5628 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5629 // one face turns into a point ...
5630 int iOppFace = hexa.GetOppFaceIndex( iFace );
5631 ind = hexa.GetFaceNodesIndices( iOppFace );
5633 iUnique = 2; // reverse a tetrahedron bottom
5634 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
5635 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5637 else if ( iUnique >= 0 )
5638 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5640 if ( nbStick == 1 ) {
5641 // ... and the opposite one - into a triangle.
5643 ind = hexa.GetFaceNodesIndices( iFace );
5644 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
5651 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
5652 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
5653 for ( int iFace = 0; iFace < 6; iFace++ ) {
5654 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5655 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5656 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5657 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5658 // one face turns into a point ...
5659 int iOppFace = hexa.GetOppFaceIndex( iFace );
5660 ind = hexa.GetFaceNodesIndices( iOppFace );
5662 iUnique = 2; // reverse a tetrahedron 1 bottom
5663 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
5664 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5666 else if ( iUnique >= 0 )
5667 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5669 if ( nbStick == 0 ) {
5670 // ... and the opposite one is a quadrangle
5672 const int* indTop = hexa.GetFaceNodesIndices( iFace );
5673 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
5676 SMDS_MeshElement* newElem =
5677 aMesh->AddVolume(curNodes[ind[ 0 ]],
5680 curNodes[indTop[ 0 ]]);
5681 myLastCreatedElems.Append(newElem);
5683 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5690 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
5691 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
5692 // find indices of quad and tri faces
5693 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
5694 for ( iFace = 0; iFace < 6; iFace++ ) {
5695 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5697 for ( iCur = 0; iCur < 4; iCur++ )
5698 nodeSet.insert( curNodes[ind[ iCur ]] );
5699 nbUniqueNodes = nodeSet.size();
5700 if ( nbUniqueNodes == 3 )
5701 iTriFace[ nbTri++ ] = iFace;
5702 else if ( nbUniqueNodes == 4 )
5703 iQuadFace[ nbQuad++ ] = iFace;
5705 if (nbQuad == 2 && nbTri == 4 &&
5706 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
5707 // 2 opposite quadrangles stuck with a diagonal;
5708 // sample groups of merged indices: (0-4)(2-6)
5709 // --------------------------------------------> 2 tetrahedrons
5710 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
5711 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
5712 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
5713 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
5714 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
5715 // stuck with 0-2 diagonal
5723 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
5724 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
5725 // stuck with 1-3 diagonal
5737 uniqueNodes[ 0 ] = curNodes [ i0 ];
5738 uniqueNodes[ 1 ] = curNodes [ i1d ];
5739 uniqueNodes[ 2 ] = curNodes [ i3d ];
5740 uniqueNodes[ 3 ] = curNodes [ i0t ];
5743 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
5747 myLastCreatedElems.Append(newElem);
5749 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5752 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
5753 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
5754 // --------------------------------------------> prism
5755 // find 2 opposite triangles
5757 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
5758 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
5759 // find indices of kept and replaced nodes
5760 // and fill unique nodes of 2 opposite triangles
5761 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
5762 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
5763 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
5764 // fill unique nodes
5767 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
5768 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
5769 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
5771 // iCur of a linked node of the opposite face (make normals co-directed):
5772 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
5773 // check that correspondent corners of triangles are linked
5774 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
5777 uniqueNodes[ iUnique ] = n;
5778 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
5787 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
5793 } // switch ( nbNodes )
5795 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
5798 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
5799 // Change nodes of polyedre
5800 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5801 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5803 int nbFaces = aPolyedre->NbFaces();
5805 vector<const SMDS_MeshNode *> poly_nodes;
5806 vector<int> quantities (nbFaces);
5808 for (int iface = 1; iface <= nbFaces; iface++) {
5809 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5810 quantities[iface - 1] = nbFaceNodes;
5812 for (inode = 1; inode <= nbFaceNodes; inode++) {
5813 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
5815 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
5816 if (nnIt != nodeNodeMap.end()) { // curNode sticks
5817 curNode = (*nnIt).second;
5819 poly_nodes.push_back(curNode);
5822 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
5826 // Change regular element or polygon
5827 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
5831 // Remove invalid regular element or invalid polygon
5832 rmElemIds.push_back( elem->GetID() );
5835 } // loop on elements
5837 // Remove equal nodes and bad elements
5839 Remove( rmNodeIds, true );
5840 Remove( rmElemIds, false );
5845 // ========================================================
5846 // class : SortableElement
5847 // purpose : allow sorting elements basing on their nodes
5848 // ========================================================
5849 class SortableElement : public set <const SMDS_MeshElement*>
5853 SortableElement( const SMDS_MeshElement* theElem )
5856 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
5857 while ( nodeIt->more() )
5858 this->insert( nodeIt->next() );
5861 const SMDS_MeshElement* Get() const
5864 void Set(const SMDS_MeshElement* e) const
5869 mutable const SMDS_MeshElement* myElem;
5872 //=======================================================================
5873 //function : FindEqualElements
5874 //purpose : Return list of group of elements built on the same nodes.
5875 // Search among theElements or in the whole mesh if theElements is empty
5876 //=======================================================================
5877 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
5878 TListOfListOfElementsID & theGroupsOfElementsID)
5880 myLastCreatedElems.Clear();
5881 myLastCreatedNodes.Clear();
5883 typedef set<const SMDS_MeshElement*> TElemsSet;
5884 typedef map< SortableElement, int > TMapOfNodeSet;
5885 typedef list<int> TGroupOfElems;
5888 if ( theElements.empty() )
5889 { // get all elements in the mesh
5890 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
5891 while ( eIt->more() )
5892 elems.insert( elems.end(), eIt->next());
5895 elems = theElements;
5897 vector< TGroupOfElems > arrayOfGroups;
5898 TGroupOfElems groupOfElems;
5899 TMapOfNodeSet mapOfNodeSet;
5901 TElemsSet::iterator elemIt = elems.begin();
5902 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
5903 const SMDS_MeshElement* curElem = *elemIt;
5904 SortableElement SE(curElem);
5907 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
5908 if( !(pp.second) ) {
5909 TMapOfNodeSet::iterator& itSE = pp.first;
5910 ind = (*itSE).second;
5911 arrayOfGroups[ind].push_back(curElem->GetID());
5914 groupOfElems.clear();
5915 groupOfElems.push_back(curElem->GetID());
5916 arrayOfGroups.push_back(groupOfElems);
5921 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
5922 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
5923 groupOfElems = *groupIt;
5924 if ( groupOfElems.size() > 1 ) {
5925 groupOfElems.sort();
5926 theGroupsOfElementsID.push_back(groupOfElems);
5931 //=======================================================================
5932 //function : MergeElements
5933 //purpose : In each given group, substitute all elements by the first one.
5934 //=======================================================================
5936 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
5938 myLastCreatedElems.Clear();
5939 myLastCreatedNodes.Clear();
5941 typedef list<int> TListOfIDs;
5942 TListOfIDs rmElemIds; // IDs of elems to remove
5944 SMESHDS_Mesh* aMesh = GetMeshDS();
5946 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
5947 while ( groupsIt != theGroupsOfElementsID.end() ) {
5948 TListOfIDs& aGroupOfElemID = *groupsIt;
5949 aGroupOfElemID.sort();
5950 int elemIDToKeep = aGroupOfElemID.front();
5951 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
5952 aGroupOfElemID.pop_front();
5953 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
5954 while ( idIt != aGroupOfElemID.end() ) {
5955 int elemIDToRemove = *idIt;
5956 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
5957 // add the kept element in groups of removed one (PAL15188)
5958 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
5959 rmElemIds.push_back( elemIDToRemove );
5965 Remove( rmElemIds, false );
5968 //=======================================================================
5969 //function : MergeEqualElements
5970 //purpose : Remove all but one of elements built on the same nodes.
5971 //=======================================================================
5973 void SMESH_MeshEditor::MergeEqualElements()
5975 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
5976 to merge equal elements in the whole mesh */
5977 TListOfListOfElementsID aGroupsOfElementsID;
5978 FindEqualElements(aMeshElements, aGroupsOfElementsID);
5979 MergeElements(aGroupsOfElementsID);
5982 //=======================================================================
5983 //function : FindFaceInSet
5984 //purpose : Return a face having linked nodes n1 and n2 and which is
5985 // - not in avoidSet,
5986 // - in elemSet provided that !elemSet.empty()
5987 //=======================================================================
5989 const SMDS_MeshElement*
5990 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
5991 const SMDS_MeshNode* n2,
5992 const TIDSortedElemSet& elemSet,
5993 const TIDSortedElemSet& avoidSet)
5996 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
5997 while ( invElemIt->more() ) { // loop on inverse elements of n1
5998 const SMDS_MeshElement* elem = invElemIt->next();
5999 if (avoidSet.find( elem ) != avoidSet.end() )
6001 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
6003 // get face nodes and find index of n1
6004 int i1, nbN = elem->NbNodes(), iNode = 0;
6005 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
6006 vector<const SMDS_MeshNode*> faceNodes( nbN );
6007 const SMDS_MeshNode* n;
6008 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6009 while ( nIt->more() ) {
6010 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6011 if ( faceNodes[ iNode++ ] == n1 )
6014 // find a n2 linked to n1
6015 if(!elem->IsQuadratic()) {
6016 for ( iNode = 0; iNode < 2; iNode++ ) {
6017 if ( iNode ) // node before n1
6018 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6019 else // node after n1
6020 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6025 else { // analysis for quadratic elements
6026 bool IsFind = false;
6027 // check using only corner nodes
6028 for ( iNode = 0; iNode < 2; iNode++ ) {
6029 if ( iNode ) // node before n1
6030 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
6031 else // node after n1
6032 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
6040 // check using all nodes
6041 const SMDS_QuadraticFaceOfNodes* F =
6042 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6043 // use special nodes iterator
6045 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6046 while ( anIter->more() ) {
6047 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
6048 if ( faceNodes[ iNode++ ] == n1 )
6051 for ( iNode = 0; iNode < 2; iNode++ ) {
6052 if ( iNode ) // node before n1
6053 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6054 else // node after n1
6055 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6061 } // end analysis for quadratic elements
6066 //=======================================================================
6067 //function : findAdjacentFace
6069 //=======================================================================
6071 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6072 const SMDS_MeshNode* n2,
6073 const SMDS_MeshElement* elem)
6075 TIDSortedElemSet elemSet, avoidSet;
6077 avoidSet.insert ( elem );
6078 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6081 //=======================================================================
6082 //function : FindFreeBorder
6084 //=======================================================================
6086 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6088 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6089 const SMDS_MeshNode* theSecondNode,
6090 const SMDS_MeshNode* theLastNode,
6091 list< const SMDS_MeshNode* > & theNodes,
6092 list< const SMDS_MeshElement* >& theFaces)
6094 if ( !theFirstNode || !theSecondNode )
6096 // find border face between theFirstNode and theSecondNode
6097 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6101 theFaces.push_back( curElem );
6102 theNodes.push_back( theFirstNode );
6103 theNodes.push_back( theSecondNode );
6105 //vector<const SMDS_MeshNode*> nodes;
6106 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6107 set < const SMDS_MeshElement* > foundElems;
6108 bool needTheLast = ( theLastNode != 0 );
6110 while ( nStart != theLastNode ) {
6111 if ( nStart == theFirstNode )
6112 return !needTheLast;
6114 // find all free border faces sharing form nStart
6116 list< const SMDS_MeshElement* > curElemList;
6117 list< const SMDS_MeshNode* > nStartList;
6118 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6119 while ( invElemIt->more() ) {
6120 const SMDS_MeshElement* e = invElemIt->next();
6121 if ( e == curElem || foundElems.insert( e ).second ) {
6123 int iNode = 0, nbNodes = e->NbNodes();
6124 //const SMDS_MeshNode* nodes[nbNodes+1];
6125 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6127 if(e->IsQuadratic()) {
6128 const SMDS_QuadraticFaceOfNodes* F =
6129 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6130 // use special nodes iterator
6131 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6132 while( anIter->more() ) {
6133 nodes[ iNode++ ] = anIter->next();
6137 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6138 while ( nIt->more() )
6139 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6141 nodes[ iNode ] = nodes[ 0 ];
6143 for ( iNode = 0; iNode < nbNodes; iNode++ )
6144 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6145 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6146 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6148 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6149 curElemList.push_back( e );
6153 // analyse the found
6155 int nbNewBorders = curElemList.size();
6156 if ( nbNewBorders == 0 ) {
6157 // no free border furthermore
6158 return !needTheLast;
6160 else if ( nbNewBorders == 1 ) {
6161 // one more element found
6163 nStart = nStartList.front();
6164 curElem = curElemList.front();
6165 theFaces.push_back( curElem );
6166 theNodes.push_back( nStart );
6169 // several continuations found
6170 list< const SMDS_MeshElement* >::iterator curElemIt;
6171 list< const SMDS_MeshNode* >::iterator nStartIt;
6172 // check if one of them reached the last node
6173 if ( needTheLast ) {
6174 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6175 curElemIt!= curElemList.end();
6176 curElemIt++, nStartIt++ )
6177 if ( *nStartIt == theLastNode ) {
6178 theFaces.push_back( *curElemIt );
6179 theNodes.push_back( *nStartIt );
6183 // find the best free border by the continuations
6184 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6185 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6186 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6187 curElemIt!= curElemList.end();
6188 curElemIt++, nStartIt++ )
6190 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6191 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6192 // find one more free border
6193 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6197 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6198 // choice: clear a worse one
6199 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6200 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6201 contNodes[ iWorse ].clear();
6202 contFaces[ iWorse ].clear();
6205 if ( contNodes[0].empty() && contNodes[1].empty() )
6208 // append the best free border
6209 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6210 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6211 theNodes.pop_back(); // remove nIgnore
6212 theNodes.pop_back(); // remove nStart
6213 theFaces.pop_back(); // remove curElem
6214 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6215 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6216 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6217 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6220 } // several continuations found
6221 } // while ( nStart != theLastNode )
6226 //=======================================================================
6227 //function : CheckFreeBorderNodes
6228 //purpose : Return true if the tree nodes are on a free border
6229 //=======================================================================
6231 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6232 const SMDS_MeshNode* theNode2,
6233 const SMDS_MeshNode* theNode3)
6235 list< const SMDS_MeshNode* > nodes;
6236 list< const SMDS_MeshElement* > faces;
6237 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6240 //=======================================================================
6241 //function : SewFreeBorder
6243 //=======================================================================
6245 SMESH_MeshEditor::Sew_Error
6246 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6247 const SMDS_MeshNode* theBordSecondNode,
6248 const SMDS_MeshNode* theBordLastNode,
6249 const SMDS_MeshNode* theSideFirstNode,
6250 const SMDS_MeshNode* theSideSecondNode,
6251 const SMDS_MeshNode* theSideThirdNode,
6252 const bool theSideIsFreeBorder,
6253 const bool toCreatePolygons,
6254 const bool toCreatePolyedrs)
6256 myLastCreatedElems.Clear();
6257 myLastCreatedNodes.Clear();
6259 MESSAGE("::SewFreeBorder()");
6260 Sew_Error aResult = SEW_OK;
6262 // ====================================
6263 // find side nodes and elements
6264 // ====================================
6266 list< const SMDS_MeshNode* > nSide[ 2 ];
6267 list< const SMDS_MeshElement* > eSide[ 2 ];
6268 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6269 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6273 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6274 nSide[0], eSide[0])) {
6275 MESSAGE(" Free Border 1 not found " );
6276 aResult = SEW_BORDER1_NOT_FOUND;
6278 if (theSideIsFreeBorder) {
6281 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6282 nSide[1], eSide[1])) {
6283 MESSAGE(" Free Border 2 not found " );
6284 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6287 if ( aResult != SEW_OK )
6290 if (!theSideIsFreeBorder) {
6294 // -------------------------------------------------------------------------
6296 // 1. If nodes to merge are not coincident, move nodes of the free border
6297 // from the coord sys defined by the direction from the first to last
6298 // nodes of the border to the correspondent sys of the side 2
6299 // 2. On the side 2, find the links most co-directed with the correspondent
6300 // links of the free border
6301 // -------------------------------------------------------------------------
6303 // 1. Since sewing may brake if there are volumes to split on the side 2,
6304 // we wont move nodes but just compute new coordinates for them
6305 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6306 TNodeXYZMap nBordXYZ;
6307 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6308 list< const SMDS_MeshNode* >::iterator nBordIt;
6310 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6311 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6312 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6313 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6314 double tol2 = 1.e-8;
6315 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6316 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6317 // Need node movement.
6319 // find X and Z axes to create trsf
6320 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6322 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6324 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6327 gp_Ax3 toBordAx( Pb1, Zb, X );
6328 gp_Ax3 fromSideAx( Ps1, Zs, X );
6329 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6331 gp_Trsf toBordSys, fromSide2Sys;
6332 toBordSys.SetTransformation( toBordAx );
6333 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6334 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6337 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6338 const SMDS_MeshNode* n = *nBordIt;
6339 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6340 toBordSys.Transforms( xyz );
6341 fromSide2Sys.Transforms( xyz );
6342 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6346 // just insert nodes XYZ in the nBordXYZ map
6347 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6348 const SMDS_MeshNode* n = *nBordIt;
6349 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6353 // 2. On the side 2, find the links most co-directed with the correspondent
6354 // links of the free border
6356 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6357 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6358 sideNodes.push_back( theSideFirstNode );
6360 bool hasVolumes = false;
6361 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6362 set<long> foundSideLinkIDs, checkedLinkIDs;
6363 SMDS_VolumeTool volume;
6364 //const SMDS_MeshNode* faceNodes[ 4 ];
6366 const SMDS_MeshNode* sideNode;
6367 const SMDS_MeshElement* sideElem;
6368 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6369 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6370 nBordIt = bordNodes.begin();
6372 // border node position and border link direction to compare with
6373 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6374 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6375 // choose next side node by link direction or by closeness to
6376 // the current border node:
6377 bool searchByDir = ( *nBordIt != theBordLastNode );
6379 // find the next node on the Side 2
6381 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6383 checkedLinkIDs.clear();
6384 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6386 // loop on inverse elements of current node (prevSideNode) on the Side 2
6387 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6388 while ( invElemIt->more() )
6390 const SMDS_MeshElement* elem = invElemIt->next();
6391 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6392 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6393 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6394 bool isVolume = volume.Set( elem );
6395 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6396 if ( isVolume ) // --volume
6398 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6399 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6400 if(elem->IsQuadratic()) {
6401 const SMDS_QuadraticFaceOfNodes* F =
6402 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6403 // use special nodes iterator
6404 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6405 while( anIter->more() ) {
6406 nodes[ iNode ] = anIter->next();
6407 if ( nodes[ iNode++ ] == prevSideNode )
6408 iPrevNode = iNode - 1;
6412 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6413 while ( nIt->more() ) {
6414 nodes[ iNode ] = cast2Node( nIt->next() );
6415 if ( nodes[ iNode++ ] == prevSideNode )
6416 iPrevNode = iNode - 1;
6419 // there are 2 links to check
6424 // loop on links, to be precise, on the second node of links
6425 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6426 const SMDS_MeshNode* n = nodes[ iNode ];
6428 if ( !volume.IsLinked( n, prevSideNode ))
6432 if ( iNode ) // a node before prevSideNode
6433 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6434 else // a node after prevSideNode
6435 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6437 // check if this link was already used
6438 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6439 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6440 if (!isJustChecked &&
6441 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6443 // test a link geometrically
6444 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6445 bool linkIsBetter = false;
6446 double dot = 0.0, dist = 0.0;
6447 if ( searchByDir ) { // choose most co-directed link
6448 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6449 linkIsBetter = ( dot > maxDot );
6451 else { // choose link with the node closest to bordPos
6452 dist = ( nextXYZ - bordPos ).SquareModulus();
6453 linkIsBetter = ( dist < minDist );
6455 if ( linkIsBetter ) {
6464 } // loop on inverse elements of prevSideNode
6467 MESSAGE(" Cant find path by links of the Side 2 ");
6468 return SEW_BAD_SIDE_NODES;
6470 sideNodes.push_back( sideNode );
6471 sideElems.push_back( sideElem );
6472 foundSideLinkIDs.insert ( linkID );
6473 prevSideNode = sideNode;
6475 if ( *nBordIt == theBordLastNode )
6476 searchByDir = false;
6478 // find the next border link to compare with
6479 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6480 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6481 // move to next border node if sideNode is before forward border node (bordPos)
6482 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6483 prevBordNode = *nBordIt;
6485 bordPos = nBordXYZ[ *nBordIt ];
6486 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6487 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6491 while ( sideNode != theSideSecondNode );
6493 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6494 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6495 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6497 } // end nodes search on the side 2
6499 // ============================
6500 // sew the border to the side 2
6501 // ============================
6503 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6504 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6506 TListOfListOfNodes nodeGroupsToMerge;
6507 if ( nbNodes[0] == nbNodes[1] ||
6508 ( theSideIsFreeBorder && !theSideThirdNode)) {
6510 // all nodes are to be merged
6512 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6513 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6514 nIt[0]++, nIt[1]++ )
6516 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6517 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6518 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6523 // insert new nodes into the border and the side to get equal nb of segments
6525 // get normalized parameters of nodes on the borders
6526 //double param[ 2 ][ maxNbNodes ];
6528 param[0] = new double [ maxNbNodes ];
6529 param[1] = new double [ maxNbNodes ];
6531 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6532 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6533 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6534 const SMDS_MeshNode* nPrev = *nIt;
6535 double bordLength = 0;
6536 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
6537 const SMDS_MeshNode* nCur = *nIt;
6538 gp_XYZ segment (nCur->X() - nPrev->X(),
6539 nCur->Y() - nPrev->Y(),
6540 nCur->Z() - nPrev->Z());
6541 double segmentLen = segment.Modulus();
6542 bordLength += segmentLen;
6543 param[ iBord ][ iNode ] = bordLength;
6546 // normalize within [0,1]
6547 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
6548 param[ iBord ][ iNode ] /= bordLength;
6552 // loop on border segments
6553 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
6554 int i[ 2 ] = { 0, 0 };
6555 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
6556 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
6558 TElemOfNodeListMap insertMap;
6559 TElemOfNodeListMap::iterator insertMapIt;
6561 // key: elem to insert nodes into
6562 // value: 2 nodes to insert between + nodes to be inserted
6564 bool next[ 2 ] = { false, false };
6566 // find min adjacent segment length after sewing
6567 double nextParam = 10., prevParam = 0;
6568 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6569 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
6570 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
6571 if ( i[ iBord ] > 0 )
6572 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
6574 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6575 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6576 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
6578 // choose to insert or to merge nodes
6579 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
6580 if ( Abs( du ) <= minSegLen * 0.2 ) {
6583 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6584 const SMDS_MeshNode* n0 = *nIt[0];
6585 const SMDS_MeshNode* n1 = *nIt[1];
6586 nodeGroupsToMerge.back().push_back( n1 );
6587 nodeGroupsToMerge.back().push_back( n0 );
6588 // position of node of the border changes due to merge
6589 param[ 0 ][ i[0] ] += du;
6590 // move n1 for the sake of elem shape evaluation during insertion.
6591 // n1 will be removed by MergeNodes() anyway
6592 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
6593 next[0] = next[1] = true;
6598 int intoBord = ( du < 0 ) ? 0 : 1;
6599 const SMDS_MeshElement* elem = *eIt[ intoBord ];
6600 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
6601 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
6602 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
6603 if ( intoBord == 1 ) {
6604 // move node of the border to be on a link of elem of the side
6605 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
6606 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
6607 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
6608 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
6609 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
6611 insertMapIt = insertMap.find( elem );
6612 bool notFound = ( insertMapIt == insertMap.end() );
6613 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
6615 // insert into another link of the same element:
6616 // 1. perform insertion into the other link of the elem
6617 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6618 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
6619 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
6620 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
6621 // 2. perform insertion into the link of adjacent faces
6623 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
6625 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
6629 if (toCreatePolyedrs) {
6630 // perform insertion into the links of adjacent volumes
6631 UpdateVolumes(n12, n22, nodeList);
6633 // 3. find an element appeared on n1 and n2 after the insertion
6634 insertMap.erase( elem );
6635 elem = findAdjacentFace( n1, n2, 0 );
6637 if ( notFound || otherLink ) {
6638 // add element and nodes of the side into the insertMap
6639 insertMapIt = insertMap.insert
6640 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
6641 (*insertMapIt).second.push_back( n1 );
6642 (*insertMapIt).second.push_back( n2 );
6644 // add node to be inserted into elem
6645 (*insertMapIt).second.push_back( nIns );
6646 next[ 1 - intoBord ] = true;
6649 // go to the next segment
6650 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6651 if ( next[ iBord ] ) {
6652 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
6654 nPrev[ iBord ] = *nIt[ iBord ];
6655 nIt[ iBord ]++; i[ iBord ]++;
6659 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
6661 // perform insertion of nodes into elements
6663 for (insertMapIt = insertMap.begin();
6664 insertMapIt != insertMap.end();
6667 const SMDS_MeshElement* elem = (*insertMapIt).first;
6668 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6669 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
6670 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
6672 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
6674 if ( !theSideIsFreeBorder ) {
6675 // look for and insert nodes into the faces adjacent to elem
6677 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
6679 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
6684 if (toCreatePolyedrs) {
6685 // perform insertion into the links of adjacent volumes
6686 UpdateVolumes(n1, n2, nodeList);
6692 } // end: insert new nodes
6694 MergeNodes ( nodeGroupsToMerge );
6699 //=======================================================================
6700 //function : InsertNodesIntoLink
6701 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
6702 // and theBetweenNode2 and split theElement
6703 //=======================================================================
6705 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
6706 const SMDS_MeshNode* theBetweenNode1,
6707 const SMDS_MeshNode* theBetweenNode2,
6708 list<const SMDS_MeshNode*>& theNodesToInsert,
6709 const bool toCreatePoly)
6711 if ( theFace->GetType() != SMDSAbs_Face ) return;
6713 // find indices of 2 link nodes and of the rest nodes
6714 int iNode = 0, il1, il2, i3, i4;
6715 il1 = il2 = i3 = i4 = -1;
6716 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
6717 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
6719 if(theFace->IsQuadratic()) {
6720 const SMDS_QuadraticFaceOfNodes* F =
6721 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6722 // use special nodes iterator
6723 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6724 while( anIter->more() ) {
6725 const SMDS_MeshNode* n = anIter->next();
6726 if ( n == theBetweenNode1 )
6728 else if ( n == theBetweenNode2 )
6734 nodes[ iNode++ ] = n;
6738 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6739 while ( nodeIt->more() ) {
6740 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6741 if ( n == theBetweenNode1 )
6743 else if ( n == theBetweenNode2 )
6749 nodes[ iNode++ ] = n;
6752 if ( il1 < 0 || il2 < 0 || i3 < 0 )
6755 // arrange link nodes to go one after another regarding the face orientation
6756 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
6757 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
6762 aNodesToInsert.reverse();
6764 // check that not link nodes of a quadrangles are in good order
6765 int nbFaceNodes = theFace->NbNodes();
6766 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
6772 if (toCreatePoly || theFace->IsPoly()) {
6775 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
6777 // add nodes of face up to first node of link
6780 if(theFace->IsQuadratic()) {
6781 const SMDS_QuadraticFaceOfNodes* F =
6782 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6783 // use special nodes iterator
6784 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6785 while( anIter->more() && !isFLN ) {
6786 const SMDS_MeshNode* n = anIter->next();
6787 poly_nodes[iNode++] = n;
6788 if (n == nodes[il1]) {
6792 // add nodes to insert
6793 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6794 for (; nIt != aNodesToInsert.end(); nIt++) {
6795 poly_nodes[iNode++] = *nIt;
6797 // add nodes of face starting from last node of link
6798 while ( anIter->more() ) {
6799 poly_nodes[iNode++] = anIter->next();
6803 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6804 while ( nodeIt->more() && !isFLN ) {
6805 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6806 poly_nodes[iNode++] = n;
6807 if (n == nodes[il1]) {
6811 // add nodes to insert
6812 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6813 for (; nIt != aNodesToInsert.end(); nIt++) {
6814 poly_nodes[iNode++] = *nIt;
6816 // add nodes of face starting from last node of link
6817 while ( nodeIt->more() ) {
6818 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6819 poly_nodes[iNode++] = n;
6823 // edit or replace the face
6824 SMESHDS_Mesh *aMesh = GetMeshDS();
6826 if (theFace->IsPoly()) {
6827 aMesh->ChangePolygonNodes(theFace, poly_nodes);
6830 int aShapeId = FindShape( theFace );
6832 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6833 myLastCreatedElems.Append(newElem);
6834 if ( aShapeId && newElem )
6835 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6837 aMesh->RemoveElement(theFace);
6842 if( !theFace->IsQuadratic() ) {
6844 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
6845 int nbLinkNodes = 2 + aNodesToInsert.size();
6846 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
6847 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
6848 linkNodes[ 0 ] = nodes[ il1 ];
6849 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
6850 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6851 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6852 linkNodes[ iNode++ ] = *nIt;
6854 // decide how to split a quadrangle: compare possible variants
6855 // and choose which of splits to be a quadrangle
6856 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
6857 if ( nbFaceNodes == 3 ) {
6858 iBestQuad = nbSplits;
6861 else if ( nbFaceNodes == 4 ) {
6862 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
6863 double aBestRate = DBL_MAX;
6864 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
6866 double aBadRate = 0;
6867 // evaluate elements quality
6868 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
6869 if ( iSplit == iQuad ) {
6870 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
6874 aBadRate += getBadRate( &quad, aCrit );
6877 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
6879 nodes[ iSplit < iQuad ? i4 : i3 ]);
6880 aBadRate += getBadRate( &tria, aCrit );
6884 if ( aBadRate < aBestRate ) {
6886 aBestRate = aBadRate;
6891 // create new elements
6892 SMESHDS_Mesh *aMesh = GetMeshDS();
6893 int aShapeId = FindShape( theFace );
6896 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
6897 SMDS_MeshElement* newElem = 0;
6898 if ( iSplit == iBestQuad )
6899 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6904 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6906 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
6907 myLastCreatedElems.Append(newElem);
6908 if ( aShapeId && newElem )
6909 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6912 // change nodes of theFace
6913 const SMDS_MeshNode* newNodes[ 4 ];
6914 newNodes[ 0 ] = linkNodes[ i1 ];
6915 newNodes[ 1 ] = linkNodes[ i2 ];
6916 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
6917 newNodes[ 3 ] = nodes[ i4 ];
6918 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
6919 } // end if(!theFace->IsQuadratic())
6920 else { // theFace is quadratic
6921 // we have to split theFace on simple triangles and one simple quadrangle
6923 int nbshift = tmp*2;
6924 // shift nodes in nodes[] by nbshift
6926 for(i=0; i<nbshift; i++) {
6927 const SMDS_MeshNode* n = nodes[0];
6928 for(j=0; j<nbFaceNodes-1; j++) {
6929 nodes[j] = nodes[j+1];
6931 nodes[nbFaceNodes-1] = n;
6933 il1 = il1 - nbshift;
6934 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
6935 // n0 n1 n2 n0 n1 n2
6936 // +-----+-----+ +-----+-----+
6945 // create new elements
6946 SMESHDS_Mesh *aMesh = GetMeshDS();
6947 int aShapeId = FindShape( theFace );
6950 if(nbFaceNodes==6) { // quadratic triangle
6951 SMDS_MeshElement* newElem =
6952 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6953 myLastCreatedElems.Append(newElem);
6954 if ( aShapeId && newElem )
6955 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6956 if(theFace->IsMediumNode(nodes[il1])) {
6957 // create quadrangle
6958 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
6959 myLastCreatedElems.Append(newElem);
6960 if ( aShapeId && newElem )
6961 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6967 // create quadrangle
6968 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
6969 myLastCreatedElems.Append(newElem);
6970 if ( aShapeId && newElem )
6971 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6977 else { // nbFaceNodes==8 - quadratic quadrangle
6978 SMDS_MeshElement* newElem =
6979 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6980 myLastCreatedElems.Append(newElem);
6981 if ( aShapeId && newElem )
6982 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6983 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
6984 myLastCreatedElems.Append(newElem);
6985 if ( aShapeId && newElem )
6986 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6987 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
6988 myLastCreatedElems.Append(newElem);
6989 if ( aShapeId && newElem )
6990 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6991 if(theFace->IsMediumNode(nodes[il1])) {
6992 // create quadrangle
6993 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
6994 myLastCreatedElems.Append(newElem);
6995 if ( aShapeId && newElem )
6996 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7002 // create quadrangle
7003 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7004 myLastCreatedElems.Append(newElem);
7005 if ( aShapeId && newElem )
7006 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7012 // create needed triangles using n1,n2,n3 and inserted nodes
7013 int nbn = 2 + aNodesToInsert.size();
7014 //const SMDS_MeshNode* aNodes[nbn];
7015 vector<const SMDS_MeshNode*> aNodes(nbn);
7016 aNodes[0] = nodes[n1];
7017 aNodes[nbn-1] = nodes[n2];
7018 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7019 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7020 aNodes[iNode++] = *nIt;
7022 for(i=1; i<nbn; i++) {
7023 SMDS_MeshElement* newElem =
7024 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7025 myLastCreatedElems.Append(newElem);
7026 if ( aShapeId && newElem )
7027 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7029 // remove old quadratic face
7030 aMesh->RemoveElement(theFace);
7034 //=======================================================================
7035 //function : UpdateVolumes
7037 //=======================================================================
7038 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7039 const SMDS_MeshNode* theBetweenNode2,
7040 list<const SMDS_MeshNode*>& theNodesToInsert)
7042 myLastCreatedElems.Clear();
7043 myLastCreatedNodes.Clear();
7045 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7046 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7047 const SMDS_MeshElement* elem = invElemIt->next();
7049 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7050 SMDS_VolumeTool aVolume (elem);
7051 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7054 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7055 int iface, nbFaces = aVolume.NbFaces();
7056 vector<const SMDS_MeshNode *> poly_nodes;
7057 vector<int> quantities (nbFaces);
7059 for (iface = 0; iface < nbFaces; iface++) {
7060 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7061 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7062 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7064 for (int inode = 0; inode < nbFaceNodes; inode++) {
7065 poly_nodes.push_back(faceNodes[inode]);
7067 if (nbInserted == 0) {
7068 if (faceNodes[inode] == theBetweenNode1) {
7069 if (faceNodes[inode + 1] == theBetweenNode2) {
7070 nbInserted = theNodesToInsert.size();
7072 // add nodes to insert
7073 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7074 for (; nIt != theNodesToInsert.end(); nIt++) {
7075 poly_nodes.push_back(*nIt);
7079 else if (faceNodes[inode] == theBetweenNode2) {
7080 if (faceNodes[inode + 1] == theBetweenNode1) {
7081 nbInserted = theNodesToInsert.size();
7083 // add nodes to insert in reversed order
7084 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7086 for (; nIt != theNodesToInsert.begin(); nIt--) {
7087 poly_nodes.push_back(*nIt);
7089 poly_nodes.push_back(*nIt);
7096 quantities[iface] = nbFaceNodes + nbInserted;
7099 // Replace or update the volume
7100 SMESHDS_Mesh *aMesh = GetMeshDS();
7102 if (elem->IsPoly()) {
7103 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7107 int aShapeId = FindShape( elem );
7109 SMDS_MeshElement* newElem =
7110 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7111 myLastCreatedElems.Append(newElem);
7112 if (aShapeId && newElem)
7113 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7115 aMesh->RemoveElement(elem);
7120 //=======================================================================
7122 * \brief Convert elements contained in a submesh to quadratic
7123 * \retval int - nb of checked elements
7125 //=======================================================================
7127 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7128 SMESH_MesherHelper& theHelper,
7129 const bool theForce3d)
7132 if( !theSm ) return nbElem;
7134 const bool notFromGroups = false;
7135 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7136 while(ElemItr->more())
7139 const SMDS_MeshElement* elem = ElemItr->next();
7140 if( !elem || elem->IsQuadratic() ) continue;
7142 int id = elem->GetID();
7143 int nbNodes = elem->NbNodes();
7144 vector<const SMDS_MeshNode *> aNds (nbNodes);
7146 for(int i = 0; i < nbNodes; i++)
7148 aNds[i] = elem->GetNode(i);
7150 SMDSAbs_ElementType aType = elem->GetType();
7152 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7154 const SMDS_MeshElement* NewElem = 0;
7160 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7168 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7171 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7178 case SMDSAbs_Volume :
7183 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7186 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7189 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7190 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7200 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7202 theSm->AddElement( NewElem );
7207 //=======================================================================
7208 //function : ConvertToQuadratic
7210 //=======================================================================
7211 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7213 SMESHDS_Mesh* meshDS = GetMeshDS();
7215 SMESH_MesherHelper aHelper(*myMesh);
7216 aHelper.SetIsQuadratic( true );
7217 const bool notFromGroups = false;
7219 int nbCheckedElems = 0;
7220 if ( myMesh->HasShapeToMesh() )
7222 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7224 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7225 while ( smIt->more() ) {
7226 SMESH_subMesh* sm = smIt->next();
7227 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7228 aHelper.SetSubShape( sm->GetSubShape() );
7229 if ( !theForce3d) aHelper.SetCheckNodePosition(true);
7230 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7235 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7236 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7238 SMESHDS_SubMesh *smDS = 0;
7239 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7240 while(aEdgeItr->more())
7242 const SMDS_MeshEdge* edge = aEdgeItr->next();
7243 if(edge && !edge->IsQuadratic())
7245 int id = edge->GetID();
7246 const SMDS_MeshNode* n1 = edge->GetNode(0);
7247 const SMDS_MeshNode* n2 = edge->GetNode(1);
7249 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7251 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7252 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7255 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7256 while(aFaceItr->more())
7258 const SMDS_MeshFace* face = aFaceItr->next();
7259 if(!face || face->IsQuadratic() ) continue;
7261 int id = face->GetID();
7262 int nbNodes = face->NbNodes();
7263 vector<const SMDS_MeshNode *> aNds (nbNodes);
7265 for(int i = 0; i < nbNodes; i++)
7267 aNds[i] = face->GetNode(i);
7270 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7272 SMDS_MeshFace * NewFace = 0;
7276 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7279 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7284 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7286 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7287 while(aVolumeItr->more())
7289 const SMDS_MeshVolume* volume = aVolumeItr->next();
7290 if(!volume || volume->IsQuadratic() ) continue;
7292 int id = volume->GetID();
7293 int nbNodes = volume->NbNodes();
7294 vector<const SMDS_MeshNode *> aNds (nbNodes);
7296 for(int i = 0; i < nbNodes; i++)
7298 aNds[i] = volume->GetNode(i);
7301 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7303 SMDS_MeshVolume * NewVolume = 0;
7307 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7308 aNds[3], id, theForce3d );
7311 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7312 aNds[3], aNds[4], aNds[5], id, theForce3d);
7315 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7316 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7321 ReplaceElemInGroups(volume, NewVolume, meshDS);
7324 if ( !theForce3d ) {
7325 aHelper.SetSubShape(0); // apply to the whole mesh
7326 aHelper.FixQuadraticElements();
7330 //=======================================================================
7332 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7333 * \retval int - nb of checked elements
7335 //=======================================================================
7337 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7338 SMDS_ElemIteratorPtr theItr,
7339 const int theShapeID)
7342 SMESHDS_Mesh* meshDS = GetMeshDS();
7343 const bool notFromGroups = false;
7345 while( theItr->more() )
7347 const SMDS_MeshElement* elem = theItr->next();
7349 if( elem && elem->IsQuadratic())
7351 int id = elem->GetID();
7352 int nbNodes = elem->NbNodes();
7353 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7354 aNds.reserve( nbNodes );
7355 mediumNodes.reserve( nbNodes );
7357 for(int i = 0; i < nbNodes; i++)
7359 const SMDS_MeshNode* n = elem->GetNode(i);
7361 if( elem->IsMediumNode( n ) )
7362 mediumNodes.push_back( n );
7364 aNds.push_back( n );
7366 if( aNds.empty() ) continue;
7367 SMDSAbs_ElementType aType = elem->GetType();
7369 //remove old quadratic element
7370 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7372 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7373 ReplaceElemInGroups(elem, NewElem, meshDS);
7374 if( theSm && NewElem )
7375 theSm->AddElement( NewElem );
7377 // remove medium nodes
7378 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7379 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7380 const SMDS_MeshNode* n = *nIt;
7381 if ( n->NbInverseElements() == 0 ) {
7382 if ( n->GetPosition()->GetShapeId() != theShapeID )
7383 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7384 ( n->GetPosition()->GetShapeId() ));
7386 meshDS->RemoveFreeNode( n, theSm );
7394 //=======================================================================
7395 //function : ConvertFromQuadratic
7397 //=======================================================================
7398 bool SMESH_MeshEditor::ConvertFromQuadratic()
7400 int nbCheckedElems = 0;
7401 if ( myMesh->HasShapeToMesh() )
7403 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7405 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7406 while ( smIt->more() ) {
7407 SMESH_subMesh* sm = smIt->next();
7408 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7409 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7415 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7416 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7418 SMESHDS_SubMesh *aSM = 0;
7419 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7425 //=======================================================================
7426 //function : SewSideElements
7428 //=======================================================================
7430 SMESH_MeshEditor::Sew_Error
7431 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7432 TIDSortedElemSet& theSide2,
7433 const SMDS_MeshNode* theFirstNode1,
7434 const SMDS_MeshNode* theFirstNode2,
7435 const SMDS_MeshNode* theSecondNode1,
7436 const SMDS_MeshNode* theSecondNode2)
7438 myLastCreatedElems.Clear();
7439 myLastCreatedNodes.Clear();
7441 MESSAGE ("::::SewSideElements()");
7442 if ( theSide1.size() != theSide2.size() )
7443 return SEW_DIFF_NB_OF_ELEMENTS;
7445 Sew_Error aResult = SEW_OK;
7447 // 1. Build set of faces representing each side
7448 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7449 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7451 // =======================================================================
7452 // 1. Build set of faces representing each side:
7453 // =======================================================================
7454 // a. build set of nodes belonging to faces
7455 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7456 // c. create temporary faces representing side of volumes if correspondent
7457 // face does not exist
7459 SMESHDS_Mesh* aMesh = GetMeshDS();
7460 SMDS_Mesh aTmpFacesMesh;
7461 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7462 set<const SMDS_MeshElement*> volSet1, volSet2;
7463 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7464 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7465 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7466 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7467 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7468 int iSide, iFace, iNode;
7470 for ( iSide = 0; iSide < 2; iSide++ ) {
7471 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7472 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7473 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7474 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7475 set<const SMDS_MeshElement*>::iterator vIt;
7476 TIDSortedElemSet::iterator eIt;
7477 set<const SMDS_MeshNode*>::iterator nIt;
7479 // check that given nodes belong to given elements
7480 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7481 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7482 int firstIndex = -1, secondIndex = -1;
7483 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7484 const SMDS_MeshElement* elem = *eIt;
7485 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7486 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7487 if ( firstIndex > -1 && secondIndex > -1 ) break;
7489 if ( firstIndex < 0 || secondIndex < 0 ) {
7490 // we can simply return until temporary faces created
7491 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7494 // -----------------------------------------------------------
7495 // 1a. Collect nodes of existing faces
7496 // and build set of face nodes in order to detect missing
7497 // faces corresponing to sides of volumes
7498 // -----------------------------------------------------------
7500 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7502 // loop on the given element of a side
7503 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7504 //const SMDS_MeshElement* elem = *eIt;
7505 const SMDS_MeshElement* elem = *eIt;
7506 if ( elem->GetType() == SMDSAbs_Face ) {
7507 faceSet->insert( elem );
7508 set <const SMDS_MeshNode*> faceNodeSet;
7509 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7510 while ( nodeIt->more() ) {
7511 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7512 nodeSet->insert( n );
7513 faceNodeSet.insert( n );
7515 setOfFaceNodeSet.insert( faceNodeSet );
7517 else if ( elem->GetType() == SMDSAbs_Volume )
7518 volSet->insert( elem );
7520 // ------------------------------------------------------------------------------
7521 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7522 // ------------------------------------------------------------------------------
7524 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7525 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7526 while ( fIt->more() ) { // loop on faces sharing a node
7527 const SMDS_MeshElement* f = fIt->next();
7528 if ( faceSet->find( f ) == faceSet->end() ) {
7529 // check if all nodes are in nodeSet and
7530 // complete setOfFaceNodeSet if they are
7531 set <const SMDS_MeshNode*> faceNodeSet;
7532 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7533 bool allInSet = true;
7534 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7535 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7536 if ( nodeSet->find( n ) == nodeSet->end() )
7539 faceNodeSet.insert( n );
7542 faceSet->insert( f );
7543 setOfFaceNodeSet.insert( faceNodeSet );
7549 // -------------------------------------------------------------------------
7550 // 1c. Create temporary faces representing sides of volumes if correspondent
7551 // face does not exist
7552 // -------------------------------------------------------------------------
7554 if ( !volSet->empty() ) {
7555 //int nodeSetSize = nodeSet->size();
7557 // loop on given volumes
7558 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
7559 SMDS_VolumeTool vol (*vIt);
7560 // loop on volume faces: find free faces
7561 // --------------------------------------
7562 list<const SMDS_MeshElement* > freeFaceList;
7563 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
7564 if ( !vol.IsFreeFace( iFace ))
7566 // check if there is already a face with same nodes in a face set
7567 const SMDS_MeshElement* aFreeFace = 0;
7568 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
7569 int nbNodes = vol.NbFaceNodes( iFace );
7570 set <const SMDS_MeshNode*> faceNodeSet;
7571 vol.GetFaceNodes( iFace, faceNodeSet );
7572 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
7574 // no such a face is given but it still can exist, check it
7575 if ( nbNodes == 3 ) {
7576 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
7578 else if ( nbNodes == 4 ) {
7579 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7582 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7583 aFreeFace = aMesh->FindFace(poly_nodes);
7587 // create a temporary face
7588 if ( nbNodes == 3 ) {
7589 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
7591 else if ( nbNodes == 4 ) {
7592 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7595 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7596 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
7600 freeFaceList.push_back( aFreeFace );
7602 } // loop on faces of a volume
7604 // choose one of several free faces
7605 // --------------------------------------
7606 if ( freeFaceList.size() > 1 ) {
7607 // choose a face having max nb of nodes shared by other elems of a side
7608 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
7609 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
7610 while ( fIt != freeFaceList.end() ) { // loop on free faces
7611 int nbSharedNodes = 0;
7612 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7613 while ( nodeIt->more() ) { // loop on free face nodes
7614 const SMDS_MeshNode* n =
7615 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7616 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
7617 while ( invElemIt->more() ) {
7618 const SMDS_MeshElement* e = invElemIt->next();
7619 if ( faceSet->find( e ) != faceSet->end() )
7621 if ( elemSet->find( e ) != elemSet->end() )
7625 if ( nbSharedNodes >= maxNbNodes ) {
7626 maxNbNodes = nbSharedNodes;
7630 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
7632 if ( freeFaceList.size() > 1 )
7634 // could not choose one face, use another way
7635 // choose a face most close to the bary center of the opposite side
7636 gp_XYZ aBC( 0., 0., 0. );
7637 set <const SMDS_MeshNode*> addedNodes;
7638 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
7639 eIt = elemSet2->begin();
7640 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
7641 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
7642 while ( nodeIt->more() ) { // loop on free face nodes
7643 const SMDS_MeshNode* n =
7644 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7645 if ( addedNodes.insert( n ).second )
7646 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
7649 aBC /= addedNodes.size();
7650 double minDist = DBL_MAX;
7651 fIt = freeFaceList.begin();
7652 while ( fIt != freeFaceList.end() ) { // loop on free faces
7654 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7655 while ( nodeIt->more() ) { // loop on free face nodes
7656 const SMDS_MeshNode* n =
7657 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7658 gp_XYZ p( n->X(),n->Y(),n->Z() );
7659 dist += ( aBC - p ).SquareModulus();
7661 if ( dist < minDist ) {
7663 freeFaceList.erase( freeFaceList.begin(), fIt++ );
7666 fIt = freeFaceList.erase( fIt++ );
7669 } // choose one of several free faces of a volume
7671 if ( freeFaceList.size() == 1 ) {
7672 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
7673 faceSet->insert( aFreeFace );
7674 // complete a node set with nodes of a found free face
7675 // for ( iNode = 0; iNode < ; iNode++ )
7676 // nodeSet->insert( fNodes[ iNode ] );
7679 } // loop on volumes of a side
7681 // // complete a set of faces if new nodes in a nodeSet appeared
7682 // // ----------------------------------------------------------
7683 // if ( nodeSetSize != nodeSet->size() ) {
7684 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7685 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7686 // while ( fIt->more() ) { // loop on faces sharing a node
7687 // const SMDS_MeshElement* f = fIt->next();
7688 // if ( faceSet->find( f ) == faceSet->end() ) {
7689 // // check if all nodes are in nodeSet and
7690 // // complete setOfFaceNodeSet if they are
7691 // set <const SMDS_MeshNode*> faceNodeSet;
7692 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7693 // bool allInSet = true;
7694 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7695 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7696 // if ( nodeSet->find( n ) == nodeSet->end() )
7697 // allInSet = false;
7699 // faceNodeSet.insert( n );
7701 // if ( allInSet ) {
7702 // faceSet->insert( f );
7703 // setOfFaceNodeSet.insert( faceNodeSet );
7709 } // Create temporary faces, if there are volumes given
7712 if ( faceSet1.size() != faceSet2.size() ) {
7713 // delete temporary faces: they are in reverseElements of actual nodes
7714 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7715 while ( tmpFaceIt->more() )
7716 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7717 MESSAGE("Diff nb of faces");
7718 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7721 // ============================================================
7722 // 2. Find nodes to merge:
7723 // bind a node to remove to a node to put instead
7724 // ============================================================
7726 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
7727 if ( theFirstNode1 != theFirstNode2 )
7728 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
7729 if ( theSecondNode1 != theSecondNode2 )
7730 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
7732 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7733 set< long > linkIdSet; // links to process
7734 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
7736 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
7737 list< NLink > linkList[2];
7738 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7739 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7740 // loop on links in linkList; find faces by links and append links
7741 // of the found faces to linkList
7742 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7743 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7744 NLink link[] = { *linkIt[0], *linkIt[1] };
7745 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
7746 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
7749 // by links, find faces in the face sets,
7750 // and find indices of link nodes in the found faces;
7751 // in a face set, there is only one or no face sharing a link
7752 // ---------------------------------------------------------------
7754 const SMDS_MeshElement* face[] = { 0, 0 };
7755 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
7756 vector<const SMDS_MeshNode*> fnodes1(9);
7757 vector<const SMDS_MeshNode*> fnodes2(9);
7758 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
7759 vector<const SMDS_MeshNode*> notLinkNodes1(6);
7760 vector<const SMDS_MeshNode*> notLinkNodes2(6);
7761 int iLinkNode[2][2];
7762 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7763 const SMDS_MeshNode* n1 = link[iSide].first;
7764 const SMDS_MeshNode* n2 = link[iSide].second;
7765 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7766 set< const SMDS_MeshElement* > fMap;
7767 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
7768 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
7769 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7770 while ( fIt->more() ) { // loop on faces sharing a node
7771 const SMDS_MeshElement* f = fIt->next();
7772 if (faceSet->find( f ) != faceSet->end() && // f is in face set
7773 ! fMap.insert( f ).second ) // f encounters twice
7775 if ( face[ iSide ] ) {
7776 MESSAGE( "2 faces per link " );
7777 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
7781 faceSet->erase( f );
7782 // get face nodes and find ones of a link
7787 fnodes1.resize(f->NbNodes()+1);
7788 notLinkNodes1.resize(f->NbNodes()-2);
7791 fnodes2.resize(f->NbNodes()+1);
7792 notLinkNodes2.resize(f->NbNodes()-2);
7795 if(!f->IsQuadratic()) {
7796 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
7797 while ( nIt->more() ) {
7798 const SMDS_MeshNode* n =
7799 static_cast<const SMDS_MeshNode*>( nIt->next() );
7801 iLinkNode[ iSide ][ 0 ] = iNode;
7803 else if ( n == n2 ) {
7804 iLinkNode[ iSide ][ 1 ] = iNode;
7806 //else if ( notLinkNodes[ iSide ][ 0 ] )
7807 // notLinkNodes[ iSide ][ 1 ] = n;
7809 // notLinkNodes[ iSide ][ 0 ] = n;
7813 notLinkNodes1[nbl] = n;
7814 //notLinkNodes1.push_back(n);
7816 notLinkNodes2[nbl] = n;
7817 //notLinkNodes2.push_back(n);
7819 //faceNodes[ iSide ][ iNode++ ] = n;
7821 fnodes1[iNode++] = n;
7824 fnodes2[iNode++] = n;
7828 else { // f->IsQuadratic()
7829 const SMDS_QuadraticFaceOfNodes* F =
7830 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
7831 // use special nodes iterator
7832 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7833 while ( anIter->more() ) {
7834 const SMDS_MeshNode* n =
7835 static_cast<const SMDS_MeshNode*>( anIter->next() );
7837 iLinkNode[ iSide ][ 0 ] = iNode;
7839 else if ( n == n2 ) {
7840 iLinkNode[ iSide ][ 1 ] = iNode;
7845 notLinkNodes1[nbl] = n;
7848 notLinkNodes2[nbl] = n;
7852 fnodes1[iNode++] = n;
7855 fnodes2[iNode++] = n;
7859 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
7861 fnodes1[iNode] = fnodes1[0];
7864 fnodes2[iNode] = fnodes1[0];
7871 // check similarity of elements of the sides
7872 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7873 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7874 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7875 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7878 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7880 break; // do not return because it s necessary to remove tmp faces
7883 // set nodes to merge
7884 // -------------------
7886 if ( face[0] && face[1] ) {
7887 int nbNodes = face[0]->NbNodes();
7888 if ( nbNodes != face[1]->NbNodes() ) {
7889 MESSAGE("Diff nb of face nodes");
7890 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7891 break; // do not return because it s necessary to remove tmp faces
7893 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
7894 if ( nbNodes == 3 ) {
7895 //nReplaceMap.insert( TNodeNodeMap::value_type
7896 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7897 nReplaceMap.insert( TNodeNodeMap::value_type
7898 ( notLinkNodes1[0], notLinkNodes2[0] ));
7901 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7902 // analyse link orientation in faces
7903 int i1 = iLinkNode[ iSide ][ 0 ];
7904 int i2 = iLinkNode[ iSide ][ 1 ];
7905 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
7906 // if notLinkNodes are the first and the last ones, then
7907 // their order does not correspond to the link orientation
7908 if (( i1 == 1 && i2 == 2 ) ||
7909 ( i1 == 2 && i2 == 1 ))
7910 reverse[ iSide ] = !reverse[ iSide ];
7912 if ( reverse[0] == reverse[1] ) {
7913 //nReplaceMap.insert( TNodeNodeMap::value_type
7914 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7915 //nReplaceMap.insert( TNodeNodeMap::value_type
7916 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
7917 for(int nn=0; nn<nbNodes-2; nn++) {
7918 nReplaceMap.insert( TNodeNodeMap::value_type
7919 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
7923 //nReplaceMap.insert( TNodeNodeMap::value_type
7924 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
7925 //nReplaceMap.insert( TNodeNodeMap::value_type
7926 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
7927 for(int nn=0; nn<nbNodes-2; nn++) {
7928 nReplaceMap.insert( TNodeNodeMap::value_type
7929 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
7934 // add other links of the faces to linkList
7935 // -----------------------------------------
7937 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
7938 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7939 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
7940 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
7941 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
7942 if ( !iter_isnew.second ) { // already in a set: no need to process
7943 linkIdSet.erase( iter_isnew.first );
7945 else // new in set == encountered for the first time: add
7947 //const SMDS_MeshNode* n1 = nodes[ iNode ];
7948 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
7949 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
7950 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
7951 linkList[0].push_back ( NLink( n1, n2 ));
7952 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7956 } // loop on link lists
7958 if ( aResult == SEW_OK &&
7959 ( linkIt[0] != linkList[0].end() ||
7960 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
7961 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
7962 " " << (faceSetPtr[1]->empty()));
7963 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7966 // ====================================================================
7967 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7968 // ====================================================================
7970 // delete temporary faces: they are in reverseElements of actual nodes
7971 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7972 while ( tmpFaceIt->more() )
7973 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7975 if ( aResult != SEW_OK)
7978 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
7979 // loop on nodes replacement map
7980 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
7981 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
7982 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
7983 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
7984 nodeIDsToRemove.push_back( nToRemove->GetID() );
7985 // loop on elements sharing nToRemove
7986 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7987 while ( invElemIt->more() ) {
7988 const SMDS_MeshElement* e = invElemIt->next();
7989 // get a new suite of nodes: make replacement
7990 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
7991 vector< const SMDS_MeshNode*> nodes( nbNodes );
7992 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7993 while ( nIt->more() ) {
7994 const SMDS_MeshNode* n =
7995 static_cast<const SMDS_MeshNode*>( nIt->next() );
7996 nnIt = nReplaceMap.find( n );
7997 if ( nnIt != nReplaceMap.end() ) {
8003 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8004 // elemIDsToRemove.push_back( e->GetID() );
8007 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8011 Remove( nodeIDsToRemove, true );
8016 //================================================================================
8018 * \brief Find corresponding nodes in two sets of faces
8019 * \param theSide1 - first face set
8020 * \param theSide2 - second first face
8021 * \param theFirstNode1 - a boundary node of set 1
8022 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8023 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8024 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8025 * \param nReplaceMap - output map of corresponding nodes
8026 * \retval bool - is a success or not
8028 //================================================================================
8031 //#define DEBUG_MATCHING_NODES
8034 SMESH_MeshEditor::Sew_Error
8035 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8036 set<const SMDS_MeshElement*>& theSide2,
8037 const SMDS_MeshNode* theFirstNode1,
8038 const SMDS_MeshNode* theFirstNode2,
8039 const SMDS_MeshNode* theSecondNode1,
8040 const SMDS_MeshNode* theSecondNode2,
8041 TNodeNodeMap & nReplaceMap)
8043 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8045 nReplaceMap.clear();
8046 if ( theFirstNode1 != theFirstNode2 )
8047 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8048 if ( theSecondNode1 != theSecondNode2 )
8049 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8051 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8052 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8054 list< NLink > linkList[2];
8055 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8056 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8058 // loop on links in linkList; find faces by links and append links
8059 // of the found faces to linkList
8060 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8061 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8062 NLink link[] = { *linkIt[0], *linkIt[1] };
8063 if ( linkSet.find( link[0] ) == linkSet.end() )
8066 // by links, find faces in the face sets,
8067 // and find indices of link nodes in the found faces;
8068 // in a face set, there is only one or no face sharing a link
8069 // ---------------------------------------------------------------
8071 const SMDS_MeshElement* face[] = { 0, 0 };
8072 list<const SMDS_MeshNode*> notLinkNodes[2];
8073 //bool reverse[] = { false, false }; // order of notLinkNodes
8075 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8077 const SMDS_MeshNode* n1 = link[iSide].first;
8078 const SMDS_MeshNode* n2 = link[iSide].second;
8079 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8080 set< const SMDS_MeshElement* > facesOfNode1;
8081 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8083 // during a loop of the first node, we find all faces around n1,
8084 // during a loop of the second node, we find one face sharing both n1 and n2
8085 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8086 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8087 while ( fIt->more() ) { // loop on faces sharing a node
8088 const SMDS_MeshElement* f = fIt->next();
8089 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8090 ! facesOfNode1.insert( f ).second ) // f encounters twice
8092 if ( face[ iSide ] ) {
8093 MESSAGE( "2 faces per link " );
8094 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8097 faceSet->erase( f );
8099 // get not link nodes
8100 int nbN = f->NbNodes();
8101 if ( f->IsQuadratic() )
8103 nbNodes[ iSide ] = nbN;
8104 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8105 int i1 = f->GetNodeIndex( n1 );
8106 int i2 = f->GetNodeIndex( n2 );
8107 int iEnd = nbN, iBeg = -1, iDelta = 1;
8108 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8110 std::swap( iEnd, iBeg ); iDelta = -1;
8115 if ( i == iEnd ) i = iBeg + iDelta;
8116 if ( i == i1 ) break;
8117 nodes.push_back ( f->GetNode( i ) );
8123 // check similarity of elements of the sides
8124 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8125 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8126 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8127 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8130 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8134 // set nodes to merge
8135 // -------------------
8137 if ( face[0] && face[1] ) {
8138 if ( nbNodes[0] != nbNodes[1] ) {
8139 MESSAGE("Diff nb of face nodes");
8140 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8142 #ifdef DEBUG_MATCHING_NODES
8143 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8144 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8145 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8147 int nbN = nbNodes[0];
8149 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8150 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8151 for ( int i = 0 ; i < nbN - 2; ++i ) {
8152 #ifdef DEBUG_MATCHING_NODES
8153 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8155 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8159 // add other links of the face 1 to linkList
8160 // -----------------------------------------
8162 const SMDS_MeshElement* f0 = face[0];
8163 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8164 for ( int i = 0; i < nbN; i++ )
8166 const SMDS_MeshNode* n2 = f0->GetNode( i );
8167 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8168 linkSet.insert( SMESH_TLink( n1, n2 ));
8169 if ( !iter_isnew.second ) { // already in a set: no need to process
8170 linkSet.erase( iter_isnew.first );
8172 else // new in set == encountered for the first time: add
8174 #ifdef DEBUG_MATCHING_NODES
8175 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8176 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8178 linkList[0].push_back ( NLink( n1, n2 ));
8179 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8184 } // loop on link lists
8190 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8191 \param theNodes - identifiers of nodes to be doubled
8192 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
8193 nodes. If list of element identifiers is empty then nodes are doubled but
8194 they not assigned to elements
8195 \return TRUE if operation has been completed successfully, FALSE otherwise
8197 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
8198 const std::list< int >& theListOfModifiedElems )
8200 myLastCreatedElems.Clear();
8201 myLastCreatedNodes.Clear();
8203 if ( theListOfNodes.size() == 0 )
8206 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8210 // iterate through nodes and duplicate them
8212 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8214 std::list< int >::const_iterator aNodeIter;
8215 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8217 int aCurr = *aNodeIter;
8218 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8224 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8227 anOldNodeToNewNode[ aNode ] = aNewNode;
8228 myLastCreatedNodes.Append( aNewNode );
8232 // Create map of new nodes for modified elements
8234 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8236 std::list< int >::const_iterator anElemIter;
8237 for ( anElemIter = theListOfModifiedElems.begin();
8238 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8240 int aCurr = *anElemIter;
8241 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8245 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8247 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8249 while ( anIter->more() )
8251 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8252 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8254 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8255 aNodeArr[ ind++ ] = aNewNode;
8258 aNodeArr[ ind++ ] = aCurrNode;
8260 anElemToNodes[ anElem ] = aNodeArr;
8263 // Change nodes of elements
8265 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8266 anElemToNodesIter = anElemToNodes.begin();
8267 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8269 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8270 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8272 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );