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() )
2787 issimple[iNode] = (listNewNodes.size()==nbSteps);
2789 itNN[ iNode ] = listNewNodes.begin();
2790 prevNod[ iNode ] = node;
2791 nextNod[ iNode ] = listNewNodes.front();
2792 //cout<<"iNode="<<iNode<<endl;
2793 //cout<<" prevNod[iNode]="<< prevNod[iNode]<<" nextNod[iNode]="<< nextNod[iNode]<<endl;
2794 if ( prevNod[ iNode ] != nextNod [ iNode ])
2795 iNotSameNode = iNode;
2799 sames[nbSame++] = iNode;
2802 //cout<<"1 nbSame="<<nbSame<<endl;
2803 if ( nbSame == nbNodes || nbSame > 2) {
2804 MESSAGE( " Too many same nodes of element " << elem->GetID() );
2808 // if( elem->IsQuadratic() && nbSame>0 ) {
2809 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2813 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2815 iBeforeSame = ( iSameNode == 0 ? nbNodes - 1 : iSameNode - 1 );
2816 iAfterSame = ( iSameNode + 1 == nbNodes ? 0 : iSameNode + 1 );
2817 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2821 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2822 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2823 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2824 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2826 // check element orientation
2828 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2829 //MESSAGE("Reversed elem " << elem );
2833 std::swap( iBeforeSame, iAfterSame );
2836 // make new elements
2837 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2839 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2840 if(issimple[iNode]) {
2841 nextNod[ iNode ] = *itNN[ iNode ];
2845 if( elem->GetType()==SMDSAbs_Node ) {
2846 // we have to use two nodes
2847 midlNod[ iNode ] = *itNN[ iNode ];
2849 nextNod[ iNode ] = *itNN[ iNode ];
2852 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2853 // we have to use each second node
2855 nextNod[ iNode ] = *itNN[ iNode ];
2859 // we have to use two nodes
2860 midlNod[ iNode ] = *itNN[ iNode ];
2862 nextNod[ iNode ] = *itNN[ iNode ];
2867 SMDS_MeshElement* aNewElem = 0;
2868 if(!elem->IsPoly()) {
2869 switch ( nbNodes ) {
2873 if ( nbSame == 0 ) {
2875 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2877 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2883 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2884 nextNod[ 1 ], nextNod[ 0 ] );
2886 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2887 nextNod[ iNotSameNode ] );
2891 case 3: { // TRIANGLE or quadratic edge
2892 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2894 if ( nbSame == 0 ) // --- pentahedron
2895 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2896 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2898 else if ( nbSame == 1 ) // --- pyramid
2899 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2900 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2901 nextNod[ iSameNode ]);
2903 else // 2 same nodes: --- tetrahedron
2904 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2905 nextNod[ iNotSameNode ]);
2907 else { // quadratic edge
2908 if(nbSame==0) { // quadratic quadrangle
2909 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2910 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2912 else if(nbSame==1) { // quadratic triangle
2914 return; // medium node on axis
2915 else if(sames[0]==0) {
2916 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2917 nextNod[2], midlNod[1], prevNod[2]);
2919 else { // sames[0]==1
2920 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2921 midlNod[0], nextNod[2], prevNod[2]);
2929 case 4: { // QUADRANGLE
2931 if ( nbSame == 0 ) // --- hexahedron
2932 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2933 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2935 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2936 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2937 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2938 nextNod[ iSameNode ]);
2939 newElems.push_back( aNewElem );
2940 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2941 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2942 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2944 else if ( nbSame == 2 ) { // pentahedron
2945 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2946 // iBeforeSame is same too
2947 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2948 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2949 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2951 // iAfterSame is same too
2952 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2953 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2954 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2958 case 6: { // quadratic triangle
2959 // create pentahedron with 15 nodes
2960 if(i0>0) { // reversed case
2961 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2962 nextNod[0], nextNod[2], nextNod[1],
2963 prevNod[5], prevNod[4], prevNod[3],
2964 nextNod[5], nextNod[4], nextNod[3],
2965 midlNod[0], midlNod[2], midlNod[1]);
2967 else { // not reversed case
2968 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2969 nextNod[0], nextNod[1], nextNod[2],
2970 prevNod[3], prevNod[4], prevNod[5],
2971 nextNod[3], nextNod[4], nextNod[5],
2972 midlNod[0], midlNod[1], midlNod[2]);
2976 case 8: { // quadratic quadrangle
2977 // create hexahedron with 20 nodes
2978 if(i0>0) { // reversed case
2979 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
2980 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
2981 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
2982 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
2983 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
2985 else { // not reversed case
2986 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
2987 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
2988 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
2989 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
2990 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
2995 // realized for extrusion only
2996 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
2997 //vector<int> quantities (nbNodes + 2);
2999 //quantities[0] = nbNodes; // bottom of prism
3000 //for (int inode = 0; inode < nbNodes; inode++) {
3001 // polyedre_nodes[inode] = prevNod[inode];
3004 //quantities[1] = nbNodes; // top of prism
3005 //for (int inode = 0; inode < nbNodes; inode++) {
3006 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3009 //for (int iface = 0; iface < nbNodes; iface++) {
3010 // quantities[iface + 2] = 4;
3011 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3012 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3013 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3014 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3015 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3017 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3024 // realized for extrusion only
3025 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3026 vector<int> quantities (nbNodes + 2);
3028 quantities[0] = nbNodes; // bottom of prism
3029 for (int inode = 0; inode < nbNodes; inode++) {
3030 polyedre_nodes[inode] = prevNod[inode];
3033 quantities[1] = nbNodes; // top of prism
3034 for (int inode = 0; inode < nbNodes; inode++) {
3035 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3038 for (int iface = 0; iface < nbNodes; iface++) {
3039 quantities[iface + 2] = 4;
3040 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3041 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3042 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3043 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3044 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3046 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3050 newElems.push_back( aNewElem );
3051 myLastCreatedElems.Append(aNewElem);
3052 srcElements.Append( elem );
3055 // set new prev nodes
3056 for ( iNode = 0; iNode < nbNodes; iNode++ )
3057 prevNod[ iNode ] = nextNod[ iNode ];
3062 //=======================================================================
3064 * \brief Create 1D and 2D elements around swept elements
3065 * \param mapNewNodes - source nodes and ones generated from them
3066 * \param newElemsMap - source elements and ones generated from them
3067 * \param elemNewNodesMap - nodes generated from each node of each element
3068 * \param elemSet - all swept elements
3069 * \param nbSteps - number of sweeping steps
3070 * \param srcElements - to append elem for each generated element
3072 //=======================================================================
3074 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3075 TElemOfElemListMap & newElemsMap,
3076 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3077 TIDSortedElemSet& elemSet,
3079 SMESH_SequenceOfElemPtr& srcElements)
3081 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3082 SMESHDS_Mesh* aMesh = GetMeshDS();
3084 // Find nodes belonging to only one initial element - sweep them to get edges.
3086 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3087 for ( ; nList != mapNewNodes.end(); nList++ ) {
3088 const SMDS_MeshNode* node =
3089 static_cast<const SMDS_MeshNode*>( nList->first );
3090 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3091 int nbInitElems = 0;
3092 const SMDS_MeshElement* el = 0;
3093 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3094 while ( eIt->more() && nbInitElems < 2 ) {
3096 SMDSAbs_ElementType type = el->GetType();
3097 if ( type == SMDSAbs_Volume || type < highType ) continue;
3098 if ( type > highType ) {
3102 if ( elemSet.find(el) != elemSet.end() )
3105 if ( nbInitElems < 2 ) {
3106 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3107 if(!NotCreateEdge) {
3108 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3109 list<const SMDS_MeshElement*> newEdges;
3110 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3115 // Make a ceiling for each element ie an equal element of last new nodes.
3116 // Find free links of faces - make edges and sweep them into faces.
3118 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3119 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3120 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3121 const SMDS_MeshElement* elem = itElem->first;
3122 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3124 if ( elem->GetType() == SMDSAbs_Edge ) {
3125 // create a ceiling edge
3126 if (!elem->IsQuadratic()) {
3127 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3128 vecNewNodes[ 1 ]->second.back())) {
3129 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3130 vecNewNodes[ 1 ]->second.back()));
3131 srcElements.Append( myLastCreatedElems.Last() );
3135 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3136 vecNewNodes[ 1 ]->second.back(),
3137 vecNewNodes[ 2 ]->second.back())) {
3138 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3139 vecNewNodes[ 1 ]->second.back(),
3140 vecNewNodes[ 2 ]->second.back()));
3141 srcElements.Append( myLastCreatedElems.Last() );
3145 if ( elem->GetType() != SMDSAbs_Face )
3148 if(itElem->second.size()==0) continue;
3150 bool hasFreeLinks = false;
3152 TIDSortedElemSet avoidSet;
3153 avoidSet.insert( elem );
3155 set<const SMDS_MeshNode*> aFaceLastNodes;
3156 int iNode, nbNodes = vecNewNodes.size();
3157 if(!elem->IsQuadratic()) {
3158 // loop on the face nodes
3159 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3160 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3161 // look for free links of the face
3162 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3163 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3164 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3165 // check if a link is free
3166 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3167 hasFreeLinks = true;
3168 // make an edge and a ceiling for a new edge
3169 if ( !aMesh->FindEdge( n1, n2 )) {
3170 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3171 srcElements.Append( myLastCreatedElems.Last() );
3173 n1 = vecNewNodes[ iNode ]->second.back();
3174 n2 = vecNewNodes[ iNext ]->second.back();
3175 if ( !aMesh->FindEdge( n1, n2 )) {
3176 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3177 srcElements.Append( myLastCreatedElems.Last() );
3182 else { // elem is quadratic face
3183 int nbn = nbNodes/2;
3184 for ( iNode = 0; iNode < nbn; iNode++ ) {
3185 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3186 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3187 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3188 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3189 // check if a link is free
3190 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3191 hasFreeLinks = true;
3192 // make an edge and a ceiling for a new edge
3194 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3195 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3196 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3197 srcElements.Append( myLastCreatedElems.Last() );
3199 n1 = vecNewNodes[ iNode ]->second.back();
3200 n2 = vecNewNodes[ iNext ]->second.back();
3201 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3202 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3203 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3204 srcElements.Append( myLastCreatedElems.Last() );
3208 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3209 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3213 // sweep free links into faces
3215 if ( hasFreeLinks ) {
3216 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3217 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3219 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3220 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3221 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3222 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3224 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3225 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3227 while ( iVol++ < volNb ) v++;
3228 // find indices of free faces of a volume and their source edges
3229 list< int > freeInd;
3230 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3231 SMDS_VolumeTool vTool( *v );
3232 int iF, nbF = vTool.NbFaces();
3233 for ( iF = 0; iF < nbF; iF ++ ) {
3234 if (vTool.IsFreeFace( iF ) &&
3235 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3236 initNodeSet != faceNodeSet) // except an initial face
3238 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3240 freeInd.push_back( iF );
3241 // find source edge of a free face iF
3242 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3243 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3244 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3245 initNodeSet.begin(), initNodeSet.end(),
3246 commonNodes.begin());
3247 if ( (*v)->IsQuadratic() )
3248 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3250 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3252 if ( !srcEdges.back() )
3254 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3255 << iF << " of volume #" << vTool.ID() << endl;
3260 if ( freeInd.empty() )
3263 // create faces for all steps;
3264 // if such a face has been already created by sweep of edge,
3265 // assure that its orientation is OK
3266 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3268 vTool.SetExternalNormal();
3269 list< int >::iterator ind = freeInd.begin();
3270 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3271 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3273 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3274 int nbn = vTool.NbFaceNodes( *ind );
3276 case 3: { ///// triangle
3277 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3279 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3280 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3281 aMesh->ChangeElementNodes( f, nodes, nbn );
3284 case 4: { ///// quadrangle
3285 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3287 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3288 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3289 aMesh->ChangeElementNodes( f, nodes, nbn );
3293 if( (*v)->IsQuadratic() ) {
3294 if(nbn==6) { /////// quadratic triangle
3295 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3296 nodes[1], nodes[3], nodes[5] );
3298 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3299 nodes[1], nodes[3], nodes[5]));
3300 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3301 aMesh->ChangeElementNodes( f, nodes, nbn );
3303 else { /////// quadratic quadrangle
3304 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3305 nodes[1], nodes[3], nodes[5], nodes[7] );
3307 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3308 nodes[1], nodes[3], nodes[5], nodes[7]));
3309 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3310 aMesh->ChangeElementNodes( f, nodes, nbn );
3313 else { //////// polygon
3314 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3315 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3317 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3318 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3319 aMesh->ChangeElementNodes( f, nodes, nbn );
3322 while ( srcElements.Length() < myLastCreatedElems.Length() )
3323 srcElements.Append( *srcEdge );
3325 } // loop on free faces
3327 // go to the next volume
3329 while ( iVol++ < nbVolumesByStep ) v++;
3332 } // sweep free links into faces
3334 // Make a ceiling face with a normal external to a volume
3336 SMDS_VolumeTool lastVol( itElem->second.back() );
3338 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3340 lastVol.SetExternalNormal();
3341 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3342 int nbn = lastVol.NbFaceNodes( iF );
3345 if (!hasFreeLinks ||
3346 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3347 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3350 if (!hasFreeLinks ||
3351 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3352 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3355 if(itElem->second.back()->IsQuadratic()) {
3357 if (!hasFreeLinks ||
3358 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3359 nodes[1], nodes[3], nodes[5]) ) {
3360 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3361 nodes[1], nodes[3], nodes[5]));
3365 if (!hasFreeLinks ||
3366 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3367 nodes[1], nodes[3], nodes[5], nodes[7]) )
3368 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3369 nodes[1], nodes[3], nodes[5], nodes[7]));
3373 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3374 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3375 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3379 while ( srcElements.Length() < myLastCreatedElems.Length() )
3380 srcElements.Append( myLastCreatedElems.Last() );
3382 } // loop on swept elements
3385 //=======================================================================
3386 //function : RotationSweep
3388 //=======================================================================
3390 SMESH_MeshEditor::PGroupIDs
3391 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3392 const gp_Ax1& theAxis,
3393 const double theAngle,
3394 const int theNbSteps,
3395 const double theTol,
3396 const bool theMakeGroups,
3397 const bool theMakeWalls)
3399 myLastCreatedElems.Clear();
3400 myLastCreatedNodes.Clear();
3402 // source elements for each generated one
3403 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3405 MESSAGE( "RotationSweep()");
3407 aTrsf.SetRotation( theAxis, theAngle );
3409 aTrsf2.SetRotation( theAxis, theAngle/2. );
3411 gp_Lin aLine( theAxis );
3412 double aSqTol = theTol * theTol;
3414 SMESHDS_Mesh* aMesh = GetMeshDS();
3416 TNodeOfNodeListMap mapNewNodes;
3417 TElemOfVecOfNnlmiMap mapElemNewNodes;
3418 TElemOfElemListMap newElemsMap;
3421 TIDSortedElemSet::iterator itElem;
3422 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3423 const SMDS_MeshElement* elem = *itElem;
3424 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3426 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3427 newNodesItVec.reserve( elem->NbNodes() );
3429 // loop on elem nodes
3430 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3431 while ( itN->more() )
3433 // check if a node has been already sweeped
3434 const SMDS_MeshNode* node = cast2Node( itN->next() );
3435 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3436 if ( nIt == mapNewNodes.end() ) {
3437 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3438 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3441 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3443 aXYZ.Coord( coord[0], coord[1], coord[2] );
3444 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3445 const SMDS_MeshNode * newNode = node;
3446 for ( int i = 0; i < theNbSteps; i++ ) {
3448 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3450 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3451 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3452 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3453 myLastCreatedNodes.Append(newNode);
3454 srcNodes.Append( node );
3455 listNewNodes.push_back( newNode );
3456 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3457 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3460 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3462 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3463 myLastCreatedNodes.Append(newNode);
3464 srcNodes.Append( node );
3466 listNewNodes.push_back( newNode );
3470 // if current elem is quadratic and current node is not medium
3471 // we have to check - may be it is needed to insert additional nodes
3472 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3473 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3474 if(listNewNodes.size()==theNbSteps) {
3475 listNewNodes.clear();
3477 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3479 aXYZ.Coord( coord[0], coord[1], coord[2] );
3480 const SMDS_MeshNode * newNode = node;
3481 for(int i = 0; i<theNbSteps; i++) {
3482 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3483 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3484 myLastCreatedNodes.Append(newNode);
3485 listNewNodes.push_back( newNode );
3486 srcNodes.Append( node );
3487 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3488 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3489 myLastCreatedNodes.Append(newNode);
3490 srcNodes.Append( node );
3491 listNewNodes.push_back( newNode );
3496 newNodesItVec.push_back( nIt );
3498 // make new elements
3499 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3503 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3505 PGroupIDs newGroupIDs;
3506 if ( theMakeGroups )
3507 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3513 //=======================================================================
3514 //function : CreateNode
3516 //=======================================================================
3517 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3520 const double tolnode,
3521 SMESH_SequenceOfNode& aNodes)
3523 myLastCreatedElems.Clear();
3524 myLastCreatedNodes.Clear();
3527 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3529 // try to search in sequence of existing nodes
3530 // if aNodes.Length()>0 we 'nave to use given sequence
3531 // else - use all nodes of mesh
3532 if(aNodes.Length()>0) {
3534 for(i=1; i<=aNodes.Length(); i++) {
3535 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3536 if(P1.Distance(P2)<tolnode)
3537 return aNodes.Value(i);
3541 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3542 while(itn->more()) {
3543 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3544 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3545 if(P1.Distance(P2)<tolnode)
3550 // create new node and return it
3551 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3552 myLastCreatedNodes.Append(NewNode);
3557 //=======================================================================
3558 //function : ExtrusionSweep
3560 //=======================================================================
3562 SMESH_MeshEditor::PGroupIDs
3563 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3564 const gp_Vec& theStep,
3565 const int theNbSteps,
3566 TElemOfElemListMap& newElemsMap,
3567 const bool theMakeGroups,
3569 const double theTolerance)
3571 ExtrusParam aParams;
3572 aParams.myDir = gp_Dir(theStep);
3573 aParams.myNodes.Clear();
3574 aParams.mySteps = new TColStd_HSequenceOfReal;
3576 for(i=1; i<=theNbSteps; i++)
3577 aParams.mySteps->Append(theStep.Magnitude());
3580 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3584 //=======================================================================
3585 //function : ExtrusionSweep
3587 //=======================================================================
3589 SMESH_MeshEditor::PGroupIDs
3590 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3591 ExtrusParam& theParams,
3592 TElemOfElemListMap& newElemsMap,
3593 const bool theMakeGroups,
3595 const double theTolerance)
3597 myLastCreatedElems.Clear();
3598 myLastCreatedNodes.Clear();
3600 // source elements for each generated one
3601 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3603 SMESHDS_Mesh* aMesh = GetMeshDS();
3605 int nbsteps = theParams.mySteps->Length();
3607 TNodeOfNodeListMap mapNewNodes;
3608 //TNodeOfNodeVecMap mapNewNodes;
3609 TElemOfVecOfNnlmiMap mapElemNewNodes;
3610 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3613 TIDSortedElemSet::iterator itElem;
3614 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3615 // check element type
3616 const SMDS_MeshElement* elem = *itElem;
3617 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3620 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3621 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3622 newNodesItVec.reserve( elem->NbNodes() );
3624 // loop on elem nodes
3625 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3626 while ( itN->more() )
3628 // check if a node has been already sweeped
3629 const SMDS_MeshNode* node = cast2Node( itN->next() );
3630 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3631 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3632 if ( nIt == mapNewNodes.end() ) {
3633 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3634 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3635 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3636 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3637 //vecNewNodes.reserve(nbsteps);
3640 double coord[] = { node->X(), node->Y(), node->Z() };
3641 //int nbsteps = theParams.mySteps->Length();
3642 for ( int i = 0; i < nbsteps; i++ ) {
3643 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3644 // create additional node
3645 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3646 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3647 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3648 if( theFlags & EXTRUSION_FLAG_SEW ) {
3649 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3650 theTolerance, theParams.myNodes);
3651 listNewNodes.push_back( newNode );
3654 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3655 myLastCreatedNodes.Append(newNode);
3656 srcNodes.Append( node );
3657 listNewNodes.push_back( newNode );
3660 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3661 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3662 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3663 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3664 if( theFlags & EXTRUSION_FLAG_SEW ) {
3665 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3666 theTolerance, theParams.myNodes);
3667 listNewNodes.push_back( newNode );
3668 //vecNewNodes[i]=newNode;
3671 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3672 myLastCreatedNodes.Append(newNode);
3673 srcNodes.Append( node );
3674 listNewNodes.push_back( newNode );
3675 //vecNewNodes[i]=newNode;
3680 // if current elem is quadratic and current node is not medium
3681 // we have to check - may be it is needed to insert additional nodes
3682 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3683 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3684 if(listNewNodes.size()==nbsteps) {
3685 listNewNodes.clear();
3686 double coord[] = { node->X(), node->Y(), node->Z() };
3687 for ( int i = 0; i < nbsteps; i++ ) {
3688 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3689 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3690 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3691 if( theFlags & EXTRUSION_FLAG_SEW ) {
3692 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3693 theTolerance, theParams.myNodes);
3694 listNewNodes.push_back( newNode );
3697 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3698 myLastCreatedNodes.Append(newNode);
3699 srcNodes.Append( node );
3700 listNewNodes.push_back( newNode );
3702 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3703 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3704 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3705 if( theFlags & EXTRUSION_FLAG_SEW ) {
3706 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3707 theTolerance, theParams.myNodes);
3708 listNewNodes.push_back( newNode );
3711 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3712 myLastCreatedNodes.Append(newNode);
3713 srcNodes.Append( node );
3714 listNewNodes.push_back( newNode );
3720 newNodesItVec.push_back( nIt );
3722 // make new elements
3723 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3726 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3727 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3729 PGroupIDs newGroupIDs;
3730 if ( theMakeGroups )
3731 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3737 //=======================================================================
3738 //class : SMESH_MeshEditor_PathPoint
3739 //purpose : auxiliary class
3740 //=======================================================================
3741 class SMESH_MeshEditor_PathPoint {
3743 SMESH_MeshEditor_PathPoint() {
3744 myPnt.SetCoord(99., 99., 99.);
3745 myTgt.SetCoord(1.,0.,0.);
3749 void SetPnt(const gp_Pnt& aP3D){
3752 void SetTangent(const gp_Dir& aTgt){
3755 void SetAngle(const double& aBeta){
3758 void SetParameter(const double& aPrm){
3761 const gp_Pnt& Pnt()const{
3764 const gp_Dir& Tangent()const{
3767 double Angle()const{
3770 double Parameter()const{
3782 //=======================================================================
3783 //function : ExtrusionAlongTrack
3785 //=======================================================================
3786 SMESH_MeshEditor::Extrusion_Error
3787 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3788 SMESH_subMesh* theTrack,
3789 const SMDS_MeshNode* theN1,
3790 const bool theHasAngles,
3791 list<double>& theAngles,
3792 const bool theLinearVariation,
3793 const bool theHasRefPoint,
3794 const gp_Pnt& theRefPoint,
3795 const bool theMakeGroups)
3797 myLastCreatedElems.Clear();
3798 myLastCreatedNodes.Clear();
3801 std::list<double> aPrms;
3802 TIDSortedElemSet::iterator itElem;
3805 TopoDS_Edge aTrackEdge;
3806 TopoDS_Vertex aV1, aV2;
3808 SMDS_ElemIteratorPtr aItE;
3809 SMDS_NodeIteratorPtr aItN;
3810 SMDSAbs_ElementType aTypeE;
3812 TNodeOfNodeListMap mapNewNodes;
3815 aNbE = theElements.size();
3818 return EXTR_NO_ELEMENTS;
3820 // 1.1 Track Pattern
3823 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3825 aItE = pSubMeshDS->GetElements();
3826 while ( aItE->more() ) {
3827 const SMDS_MeshElement* pE = aItE->next();
3828 aTypeE = pE->GetType();
3829 // Pattern must contain links only
3830 if ( aTypeE != SMDSAbs_Edge )
3831 return EXTR_PATH_NOT_EDGE;
3834 list<SMESH_MeshEditor_PathPoint> fullList;
3836 const TopoDS_Shape& aS = theTrack->GetSubShape();
3837 // Sub shape for the Pattern must be an Edge or Wire
3838 if( aS.ShapeType() == TopAbs_EDGE ) {
3839 aTrackEdge = TopoDS::Edge( aS );
3840 // the Edge must not be degenerated
3841 if ( BRep_Tool::Degenerated( aTrackEdge ) )
3842 return EXTR_BAD_PATH_SHAPE;
3843 TopExp::Vertices( aTrackEdge, aV1, aV2 );
3844 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3845 const SMDS_MeshNode* aN1 = aItN->next();
3846 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3847 const SMDS_MeshNode* aN2 = aItN->next();
3848 // starting node must be aN1 or aN2
3849 if ( !( aN1 == theN1 || aN2 == theN1 ) )
3850 return EXTR_BAD_STARTING_NODE;
3851 aItN = pSubMeshDS->GetNodes();
3852 while ( aItN->more() ) {
3853 const SMDS_MeshNode* pNode = aItN->next();
3854 const SMDS_EdgePosition* pEPos =
3855 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
3856 double aT = pEPos->GetUParameter();
3857 aPrms.push_back( aT );
3859 //Extrusion_Error err =
3860 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
3862 else if( aS.ShapeType() == TopAbs_WIRE ) {
3863 list< SMESH_subMesh* > LSM;
3864 TopTools_SequenceOfShape Edges;
3865 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
3866 while(itSM->more()) {
3867 SMESH_subMesh* SM = itSM->next();
3869 const TopoDS_Shape& aS = SM->GetSubShape();
3872 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
3873 int startNid = theN1->GetID();
3874 TColStd_MapOfInteger UsedNums;
3875 int NbEdges = Edges.Length();
3877 for(; i<=NbEdges; i++) {
3879 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
3880 for(; itLSM!=LSM.end(); itLSM++) {
3882 if(UsedNums.Contains(k)) continue;
3883 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
3884 SMESH_subMesh* locTrack = *itLSM;
3885 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
3886 TopExp::Vertices( aTrackEdge, aV1, aV2 );
3887 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
3888 const SMDS_MeshNode* aN1 = aItN->next();
3889 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
3890 const SMDS_MeshNode* aN2 = aItN->next();
3891 // starting node must be aN1 or aN2
3892 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
3893 // 2. Collect parameters on the track edge
3895 aItN = locMeshDS->GetNodes();
3896 while ( aItN->more() ) {
3897 const SMDS_MeshNode* pNode = aItN->next();
3898 const SMDS_EdgePosition* pEPos =
3899 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
3900 double aT = pEPos->GetUParameter();
3901 aPrms.push_back( aT );
3903 list<SMESH_MeshEditor_PathPoint> LPP;
3904 //Extrusion_Error err =
3905 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
3906 LLPPs.push_back(LPP);
3908 // update startN for search following egde
3909 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
3910 else startNid = aN1->GetID();
3914 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
3915 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
3916 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
3917 for(; itPP!=firstList.end(); itPP++) {
3918 fullList.push_back( *itPP );
3920 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
3921 fullList.pop_back();
3923 for(; itLLPP!=LLPPs.end(); itLLPP++) {
3924 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
3925 itPP = currList.begin();
3926 SMESH_MeshEditor_PathPoint PP2 = currList.front();
3927 gp_Dir D1 = PP1.Tangent();
3928 gp_Dir D2 = PP2.Tangent();
3929 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
3930 (D1.Z()+D2.Z())/2 ) );
3931 PP1.SetTangent(Dnew);
3932 fullList.push_back(PP1);
3934 for(; itPP!=firstList.end(); itPP++) {
3935 fullList.push_back( *itPP );
3937 PP1 = fullList.back();
3938 fullList.pop_back();
3940 // if wire not closed
3941 fullList.push_back(PP1);
3945 return EXTR_BAD_PATH_SHAPE;
3948 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
3949 theHasRefPoint, theRefPoint, theMakeGroups);
3953 //=======================================================================
3954 //function : ExtrusionAlongTrack
3956 //=======================================================================
3957 SMESH_MeshEditor::Extrusion_Error
3958 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3959 SMESH_Mesh* theTrack,
3960 const SMDS_MeshNode* theN1,
3961 const bool theHasAngles,
3962 list<double>& theAngles,
3963 const bool theLinearVariation,
3964 const bool theHasRefPoint,
3965 const gp_Pnt& theRefPoint,
3966 const bool theMakeGroups)
3968 myLastCreatedElems.Clear();
3969 myLastCreatedNodes.Clear();
3972 std::list<double> aPrms;
3973 TIDSortedElemSet::iterator itElem;
3976 TopoDS_Edge aTrackEdge;
3977 TopoDS_Vertex aV1, aV2;
3979 SMDS_ElemIteratorPtr aItE;
3980 SMDS_NodeIteratorPtr aItN;
3981 SMDSAbs_ElementType aTypeE;
3983 TNodeOfNodeListMap mapNewNodes;
3986 aNbE = theElements.size();
3989 return EXTR_NO_ELEMENTS;
3991 // 1.1 Track Pattern
3994 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
3996 aItE = pMeshDS->elementsIterator();
3997 while ( aItE->more() ) {
3998 const SMDS_MeshElement* pE = aItE->next();
3999 aTypeE = pE->GetType();
4000 // Pattern must contain links only
4001 if ( aTypeE != SMDSAbs_Edge )
4002 return EXTR_PATH_NOT_EDGE;
4005 list<SMESH_MeshEditor_PathPoint> fullList;
4007 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4008 // Sub shape for the Pattern must be an Edge or Wire
4009 if( aS.ShapeType() == TopAbs_EDGE ) {
4010 aTrackEdge = TopoDS::Edge( aS );
4011 // the Edge must not be degenerated
4012 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4013 return EXTR_BAD_PATH_SHAPE;
4014 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4015 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4016 const SMDS_MeshNode* aN1 = aItN->next();
4017 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4018 const SMDS_MeshNode* aN2 = aItN->next();
4019 // starting node must be aN1 or aN2
4020 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4021 return EXTR_BAD_STARTING_NODE;
4022 aItN = pMeshDS->nodesIterator();
4023 while ( aItN->more() ) {
4024 const SMDS_MeshNode* pNode = aItN->next();
4025 if( pNode==aN1 || pNode==aN2 ) continue;
4026 const SMDS_EdgePosition* pEPos =
4027 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4028 double aT = pEPos->GetUParameter();
4029 aPrms.push_back( aT );
4031 //Extrusion_Error err =
4032 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4034 else if( aS.ShapeType() == TopAbs_WIRE ) {
4035 list< SMESH_subMesh* > LSM;
4036 TopTools_SequenceOfShape Edges;
4037 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4038 for(; eExp.More(); eExp.Next()) {
4039 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4040 if( BRep_Tool::Degenerated(E) ) continue;
4041 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4047 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4048 int startNid = theN1->GetID();
4049 TColStd_MapOfInteger UsedNums;
4050 int NbEdges = Edges.Length();
4052 for(; i<=NbEdges; i++) {
4054 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4055 for(; itLSM!=LSM.end(); itLSM++) {
4057 if(UsedNums.Contains(k)) continue;
4058 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4059 SMESH_subMesh* locTrack = *itLSM;
4060 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4061 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4062 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4063 const SMDS_MeshNode* aN1 = aItN->next();
4064 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4065 const SMDS_MeshNode* aN2 = aItN->next();
4066 // starting node must be aN1 or aN2
4067 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4068 // 2. Collect parameters on the track edge
4070 aItN = locMeshDS->GetNodes();
4071 while ( aItN->more() ) {
4072 const SMDS_MeshNode* pNode = aItN->next();
4073 const SMDS_EdgePosition* pEPos =
4074 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4075 double aT = pEPos->GetUParameter();
4076 aPrms.push_back( aT );
4078 list<SMESH_MeshEditor_PathPoint> LPP;
4079 //Extrusion_Error err =
4080 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4081 LLPPs.push_back(LPP);
4083 // update startN for search following egde
4084 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4085 else startNid = aN1->GetID();
4089 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4090 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4091 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4092 for(; itPP!=firstList.end(); itPP++) {
4093 fullList.push_back( *itPP );
4095 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4096 fullList.pop_back();
4098 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4099 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4100 itPP = currList.begin();
4101 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4102 gp_Pnt P1 = PP1.Pnt();
4103 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4104 gp_Pnt P2 = PP2.Pnt();
4105 gp_Dir D1 = PP1.Tangent();
4106 gp_Dir D2 = PP2.Tangent();
4107 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4108 (D1.Z()+D2.Z())/2 ) );
4109 PP1.SetTangent(Dnew);
4110 fullList.push_back(PP1);
4112 for(; itPP!=currList.end(); itPP++) {
4113 fullList.push_back( *itPP );
4115 PP1 = fullList.back();
4116 fullList.pop_back();
4118 // if wire not closed
4119 fullList.push_back(PP1);
4123 return EXTR_BAD_PATH_SHAPE;
4126 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4127 theHasRefPoint, theRefPoint, theMakeGroups);
4131 //=======================================================================
4132 //function : MakeEdgePathPoints
4133 //purpose : auxilary for ExtrusionAlongTrack
4134 //=======================================================================
4135 SMESH_MeshEditor::Extrusion_Error
4136 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4137 const TopoDS_Edge& aTrackEdge,
4139 list<SMESH_MeshEditor_PathPoint>& LPP)
4141 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4143 aTolVec2=aTolVec*aTolVec;
4145 TopoDS_Vertex aV1, aV2;
4146 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4147 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4148 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4149 // 2. Collect parameters on the track edge
4150 aPrms.push_front( aT1 );
4151 aPrms.push_back( aT2 );
4154 if( FirstIsStart ) {
4165 SMESH_MeshEditor_PathPoint aPP;
4166 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4167 std::list<double>::iterator aItD = aPrms.begin();
4168 for(; aItD != aPrms.end(); ++aItD) {
4172 aC3D->D1( aT, aP3D, aVec );
4173 aL2 = aVec.SquareMagnitude();
4174 if ( aL2 < aTolVec2 )
4175 return EXTR_CANT_GET_TANGENT;
4176 gp_Dir aTgt( aVec );
4178 aPP.SetTangent( aTgt );
4179 aPP.SetParameter( aT );
4186 //=======================================================================
4187 //function : MakeExtrElements
4188 //purpose : auxilary for ExtrusionAlongTrack
4189 //=======================================================================
4190 SMESH_MeshEditor::Extrusion_Error
4191 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4192 list<SMESH_MeshEditor_PathPoint>& fullList,
4193 const bool theHasAngles,
4194 list<double>& theAngles,
4195 const bool theLinearVariation,
4196 const bool theHasRefPoint,
4197 const gp_Pnt& theRefPoint,
4198 const bool theMakeGroups)
4200 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4201 int aNbTP = fullList.size();
4202 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4204 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4205 LinearAngleVariation(aNbTP-1, theAngles);
4207 vector<double> aAngles( aNbTP );
4209 for(; j<aNbTP; ++j) {
4212 if ( theHasAngles ) {
4214 std::list<double>::iterator aItD = theAngles.begin();
4215 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4217 aAngles[j] = anAngle;
4220 // fill vector of path points with angles
4221 //aPPs.resize(fullList.size());
4223 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4224 for(; itPP!=fullList.end(); itPP++) {
4226 SMESH_MeshEditor_PathPoint PP = *itPP;
4227 PP.SetAngle(aAngles[j]);
4231 TNodeOfNodeListMap mapNewNodes;
4232 TElemOfVecOfNnlmiMap mapElemNewNodes;
4233 TElemOfElemListMap newElemsMap;
4234 TIDSortedElemSet::iterator itElem;
4237 SMDSAbs_ElementType aTypeE;
4238 // source elements for each generated one
4239 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4241 // 3. Center of rotation aV0
4242 gp_Pnt aV0 = theRefPoint;
4244 if ( !theHasRefPoint ) {
4246 aGC.SetCoord( 0.,0.,0. );
4248 itElem = theElements.begin();
4249 for ( ; itElem != theElements.end(); itElem++ ) {
4250 const SMDS_MeshElement* elem = *itElem;
4252 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4253 while ( itN->more() ) {
4254 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4259 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4260 list<const SMDS_MeshNode*> aLNx;
4261 mapNewNodes[node] = aLNx;
4263 gp_XYZ aXYZ( aX, aY, aZ );
4271 } // if (!theHasRefPoint) {
4272 mapNewNodes.clear();
4274 // 4. Processing the elements
4275 SMESHDS_Mesh* aMesh = GetMeshDS();
4277 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4278 // check element type
4279 const SMDS_MeshElement* elem = *itElem;
4280 aTypeE = elem->GetType();
4281 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4284 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4285 newNodesItVec.reserve( elem->NbNodes() );
4287 // loop on elem nodes
4289 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4290 while ( itN->more() )
4293 // check if a node has been already processed
4294 const SMDS_MeshNode* node =
4295 static_cast<const SMDS_MeshNode*>( itN->next() );
4296 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4297 if ( nIt == mapNewNodes.end() ) {
4298 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4299 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4302 aX = node->X(); aY = node->Y(); aZ = node->Z();
4304 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4305 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4306 gp_Ax1 anAx1, anAxT1T0;
4307 gp_Dir aDT1x, aDT0x, aDT1T0;
4312 aPN0.SetCoord(aX, aY, aZ);
4314 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4316 aDT0x= aPP0.Tangent();
4317 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4319 for ( j = 1; j < aNbTP; ++j ) {
4320 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4322 aDT1x = aPP1.Tangent();
4323 aAngle1x = aPP1.Angle();
4325 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4327 gp_Vec aV01x( aP0x, aP1x );
4328 aTrsf.SetTranslation( aV01x );
4331 aV1x = aV0x.Transformed( aTrsf );
4332 aPN1 = aPN0.Transformed( aTrsf );
4334 // rotation 1 [ T1,T0 ]
4335 aAngleT1T0=-aDT1x.Angle( aDT0x );
4336 if (fabs(aAngleT1T0) > aTolAng) {
4338 anAxT1T0.SetLocation( aV1x );
4339 anAxT1T0.SetDirection( aDT1T0 );
4340 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4342 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4346 if ( theHasAngles ) {
4347 anAx1.SetLocation( aV1x );
4348 anAx1.SetDirection( aDT1x );
4349 aTrsfRot.SetRotation( anAx1, aAngle1x );
4351 aPN1 = aPN1.Transformed( aTrsfRot );
4355 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4356 // create additional node
4357 double x = ( aPN1.X() + aPN0.X() )/2.;
4358 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4359 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4360 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4361 myLastCreatedNodes.Append(newNode);
4362 srcNodes.Append( node );
4363 listNewNodes.push_back( newNode );
4368 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4369 myLastCreatedNodes.Append(newNode);
4370 srcNodes.Append( node );
4371 listNewNodes.push_back( newNode );
4381 // if current elem is quadratic and current node is not medium
4382 // we have to check - may be it is needed to insert additional nodes
4383 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4384 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4385 if(listNewNodes.size()==aNbTP-1) {
4386 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4387 gp_XYZ P(node->X(), node->Y(), node->Z());
4388 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4390 for(i=0; i<aNbTP-1; i++) {
4391 const SMDS_MeshNode* N = *it;
4392 double x = ( N->X() + P.X() )/2.;
4393 double y = ( N->Y() + P.Y() )/2.;
4394 double z = ( N->Z() + P.Z() )/2.;
4395 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4396 srcNodes.Append( node );
4397 myLastCreatedNodes.Append(newN);
4400 P = gp_XYZ(N->X(),N->Y(),N->Z());
4402 listNewNodes.clear();
4403 for(i=0; i<2*(aNbTP-1); i++) {
4404 listNewNodes.push_back(aNodes[i]);
4410 newNodesItVec.push_back( nIt );
4412 // make new elements
4413 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4414 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4415 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4418 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4420 if ( theMakeGroups )
4421 generateGroups( srcNodes, srcElems, "extruded");
4427 //=======================================================================
4428 //function : LinearAngleVariation
4429 //purpose : auxilary for ExtrusionAlongTrack
4430 //=======================================================================
4431 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4432 list<double>& Angles)
4434 int nbAngles = Angles.size();
4435 if( nbSteps > nbAngles ) {
4436 vector<double> theAngles(nbAngles);
4437 list<double>::iterator it = Angles.begin();
4439 for(; it!=Angles.end(); it++) {
4441 theAngles[i] = (*it);
4444 double rAn2St = double( nbAngles ) / double( nbSteps );
4445 double angPrev = 0, angle;
4446 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4447 double angCur = rAn2St * ( iSt+1 );
4448 double angCurFloor = floor( angCur );
4449 double angPrevFloor = floor( angPrev );
4450 if ( angPrevFloor == angCurFloor )
4451 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4453 int iP = int( angPrevFloor );
4454 double angPrevCeil = ceil(angPrev);
4455 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4457 int iC = int( angCurFloor );
4458 if ( iC < nbAngles )
4459 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4461 iP = int( angPrevCeil );
4463 angle += theAngles[ iC ];
4465 res.push_back(angle);
4470 for(; it!=res.end(); it++)
4471 Angles.push_back( *it );
4476 //=======================================================================
4477 //function : Transform
4479 //=======================================================================
4481 SMESH_MeshEditor::PGroupIDs
4482 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4483 const gp_Trsf& theTrsf,
4485 const bool theMakeGroups,
4486 SMESH_Mesh* theTargetMesh)
4488 myLastCreatedElems.Clear();
4489 myLastCreatedNodes.Clear();
4491 bool needReverse = false;
4492 string groupPostfix;
4493 switch ( theTrsf.Form() ) {
4498 groupPostfix = "mirrored";
4501 groupPostfix = "rotated";
4503 case gp_Translation:
4504 groupPostfix = "translated";
4507 groupPostfix = "scaled";
4510 needReverse = false;
4511 groupPostfix = "transformed";
4514 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4515 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4516 SMESHDS_Mesh* aMesh = GetMeshDS();
4519 // map old node to new one
4520 TNodeNodeMap nodeMap;
4522 // elements sharing moved nodes; those of them which have all
4523 // nodes mirrored but are not in theElems are to be reversed
4524 TIDSortedElemSet inverseElemSet;
4526 // source elements for each generated one
4527 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4530 TIDSortedElemSet::iterator itElem;
4531 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4532 const SMDS_MeshElement* elem = *itElem;
4536 // loop on elem nodes
4537 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4538 while ( itN->more() ) {
4540 // check if a node has been already transformed
4541 const SMDS_MeshNode* node = cast2Node( itN->next() );
4542 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4543 nodeMap.insert( make_pair ( node, node ));
4544 if ( !n2n_isnew.second )
4548 coord[0] = node->X();
4549 coord[1] = node->Y();
4550 coord[2] = node->Z();
4551 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4552 if ( theTargetMesh ) {
4553 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4554 n2n_isnew.first->second = newNode;
4555 myLastCreatedNodes.Append(newNode);
4556 srcNodes.Append( node );
4558 else if ( theCopy ) {
4559 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4560 n2n_isnew.first->second = newNode;
4561 myLastCreatedNodes.Append(newNode);
4562 srcNodes.Append( node );
4565 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4566 // node position on shape becomes invalid
4567 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4568 ( SMDS_SpacePosition::originSpacePosition() );
4571 // keep inverse elements
4572 if ( !theCopy && !theTargetMesh && needReverse ) {
4573 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4574 while ( invElemIt->more() ) {
4575 const SMDS_MeshElement* iel = invElemIt->next();
4576 inverseElemSet.insert( iel );
4582 // either create new elements or reverse mirrored ones
4583 if ( !theCopy && !needReverse && !theTargetMesh )
4586 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4587 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4588 theElems.insert( *invElemIt );
4590 // replicate or reverse elements
4593 REV_TETRA = 0, // = nbNodes - 4
4594 REV_PYRAMID = 1, // = nbNodes - 4
4595 REV_PENTA = 2, // = nbNodes - 4
4597 REV_HEXA = 4, // = nbNodes - 4
4601 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4602 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4603 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4604 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4605 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4606 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4609 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4611 const SMDS_MeshElement* elem = *itElem;
4612 if ( !elem || elem->GetType() == SMDSAbs_Node )
4615 int nbNodes = elem->NbNodes();
4616 int elemType = elem->GetType();
4618 if (elem->IsPoly()) {
4619 // Polygon or Polyhedral Volume
4620 switch ( elemType ) {
4623 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4625 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4626 while (itN->more()) {
4627 const SMDS_MeshNode* node =
4628 static_cast<const SMDS_MeshNode*>(itN->next());
4629 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4630 if (nodeMapIt == nodeMap.end())
4631 break; // not all nodes transformed
4633 // reverse mirrored faces and volumes
4634 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4636 poly_nodes[iNode] = (*nodeMapIt).second;
4640 if ( iNode != nbNodes )
4641 continue; // not all nodes transformed
4643 if ( theTargetMesh ) {
4644 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4645 srcElems.Append( elem );
4647 else if ( theCopy ) {
4648 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4649 srcElems.Append( elem );
4652 aMesh->ChangePolygonNodes(elem, poly_nodes);
4656 case SMDSAbs_Volume:
4658 // ATTENTION: Reversing is not yet done!!!
4659 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4660 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4662 MESSAGE("Warning: bad volumic element");
4666 vector<const SMDS_MeshNode*> poly_nodes;
4667 vector<int> quantities;
4669 bool allTransformed = true;
4670 int nbFaces = aPolyedre->NbFaces();
4671 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4672 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4673 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4674 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4675 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4676 if (nodeMapIt == nodeMap.end()) {
4677 allTransformed = false; // not all nodes transformed
4679 poly_nodes.push_back((*nodeMapIt).second);
4682 quantities.push_back(nbFaceNodes);
4684 if ( !allTransformed )
4685 continue; // not all nodes transformed
4687 if ( theTargetMesh ) {
4688 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4689 srcElems.Append( elem );
4691 else if ( theCopy ) {
4692 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4693 srcElems.Append( elem );
4696 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4706 int* i = index[ FORWARD ];
4707 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4708 if ( elemType == SMDSAbs_Face )
4709 i = index[ REV_FACE ];
4711 i = index[ nbNodes - 4 ];
4713 if(elem->IsQuadratic()) {
4714 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4717 if(nbNodes==3) { // quadratic edge
4718 static int anIds[] = {1,0,2};
4721 else if(nbNodes==6) { // quadratic triangle
4722 static int anIds[] = {0,2,1,5,4,3};
4725 else if(nbNodes==8) { // quadratic quadrangle
4726 static int anIds[] = {0,3,2,1,7,6,5,4};
4729 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4730 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4733 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4734 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4737 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4738 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4741 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4742 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4748 // find transformed nodes
4749 vector<const SMDS_MeshNode*> nodes(nbNodes);
4751 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4752 while ( itN->more() ) {
4753 const SMDS_MeshNode* node =
4754 static_cast<const SMDS_MeshNode*>( itN->next() );
4755 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4756 if ( nodeMapIt == nodeMap.end() )
4757 break; // not all nodes transformed
4758 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4760 if ( iNode != nbNodes )
4761 continue; // not all nodes transformed
4763 if ( theTargetMesh ) {
4764 if ( SMDS_MeshElement* copy =
4765 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4766 myLastCreatedElems.Append( copy );
4767 srcElems.Append( elem );
4770 else if ( theCopy ) {
4771 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4772 myLastCreatedElems.Append( copy );
4773 srcElems.Append( elem );
4777 // reverse element as it was reversed by transformation
4779 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4783 PGroupIDs newGroupIDs;
4785 if ( theMakeGroups && theCopy ||
4786 theMakeGroups && theTargetMesh )
4787 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4792 //=======================================================================
4794 * \brief Create groups of elements made during transformation
4795 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4796 * \param elemGens - elements making corresponding myLastCreatedElems
4797 * \param postfix - to append to names of new groups
4799 //=======================================================================
4801 SMESH_MeshEditor::PGroupIDs
4802 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4803 const SMESH_SequenceOfElemPtr& elemGens,
4804 const std::string& postfix,
4805 SMESH_Mesh* targetMesh)
4807 PGroupIDs newGroupIDs( new list<int> );
4808 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4810 // Sort existing groups by types and collect their names
4812 // to store an old group and a generated new one
4813 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4814 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4816 set< string > groupNames;
4818 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4819 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4820 while ( groupIt->more() ) {
4821 SMESH_Group * group = groupIt->next();
4822 if ( !group ) continue;
4823 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4824 if ( !groupDS || groupDS->IsEmpty() ) continue;
4825 groupNames.insert( group->GetName() );
4826 groupDS->SetStoreName( group->GetName() );
4827 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4832 // loop on nodes and elements
4833 for ( int isNodes = 0; isNodes < 2; ++isNodes )
4835 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
4836 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4837 if ( gens.Length() != elems.Length() )
4838 throw SALOME_Exception(LOCALIZED("invalid args"));
4840 // loop on created elements
4841 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4843 const SMDS_MeshElement* sourceElem = gens( iElem );
4844 if ( !sourceElem ) {
4845 MESSAGE("generateGroups(): NULL source element");
4848 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
4849 if ( groupsOldNew.empty() ) {
4850 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4851 ++iElem; // skip all elements made by sourceElem
4854 // collect all elements made by sourceElem
4855 list< const SMDS_MeshElement* > resultElems;
4856 if ( const SMDS_MeshElement* resElem = elems( iElem ))
4857 if ( resElem != sourceElem )
4858 resultElems.push_back( resElem );
4859 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4860 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
4861 if ( resElem != sourceElem )
4862 resultElems.push_back( resElem );
4863 // do not generate element groups from node ones
4864 if ( sourceElem->GetType() == SMDSAbs_Node &&
4865 elems( iElem )->GetType() != SMDSAbs_Node )
4868 // add resultElems to groups made by ones the sourceElem belongs to
4869 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
4870 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
4872 SMESHDS_GroupBase* oldGroup = gOldNew->first;
4873 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
4875 SMDS_MeshGroup* & newGroup = gOldNew->second;
4876 if ( !newGroup )// create a new group
4879 string name = oldGroup->GetStoreName();
4880 if ( !targetMesh ) {
4884 while ( !groupNames.insert( name ).second ) // name exists
4890 TCollection_AsciiString nbStr(nb+1);
4891 name.resize( name.rfind('_')+1 );
4892 name += nbStr.ToCString();
4899 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
4901 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
4902 newGroup = & groupDS->SMDSGroup();
4903 newGroupIDs->push_back( id );
4906 // fill in a new group
4907 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
4908 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
4909 newGroup->Add( *resElemIt );
4912 } // loop on created elements
4913 }// loop on nodes and elements
4918 //=======================================================================
4919 //function : FindCoincidentNodes
4920 //purpose : Return list of group of nodes close to each other within theTolerance
4921 // Search among theNodes or in the whole mesh if theNodes is empty using
4922 // an Octree algorithm
4923 //=======================================================================
4925 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
4926 const double theTolerance,
4927 TListOfListOfNodes & theGroupsOfNodes)
4929 myLastCreatedElems.Clear();
4930 myLastCreatedNodes.Clear();
4932 set<const SMDS_MeshNode*> nodes;
4933 if ( theNodes.empty() )
4934 { // get all nodes in the mesh
4935 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
4936 while ( nIt->more() )
4937 nodes.insert( nodes.end(),nIt->next());
4941 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
4945 //=======================================================================
4947 * \brief Implementation of search for the node closest to point
4949 //=======================================================================
4951 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
4954 * \brief Constructor
4956 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
4958 set<const SMDS_MeshNode*> nodes;
4960 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
4961 while ( nIt->more() )
4962 nodes.insert( nodes.end(), nIt->next() );
4964 myOctreeNode = new SMESH_OctreeNode(nodes) ;
4967 * \brief Do it's job
4969 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
4971 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
4972 list<const SMDS_MeshNode*> nodes;
4973 const double precision = 1e-6;
4974 myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
4976 double minSqDist = DBL_MAX;
4978 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
4980 // sort leafs by their distance from thePnt
4981 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
4982 TDistTreeMap treeMap;
4983 list< SMESH_OctreeNode* > treeList;
4984 list< SMESH_OctreeNode* >::iterator trIt;
4985 treeList.push_back( myOctreeNode );
4986 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
4988 SMESH_OctreeNode* tree = *trIt;
4989 if ( !tree->isLeaf() ) { // put children to the queue
4990 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
4991 while ( cIt->more() )
4992 treeList.push_back( cIt->next() );
4994 else if ( tree->NbNodes() ) { // put tree to treeMap
4995 tree->getBox( box );
4996 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
4997 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
4998 if ( !it_in.second ) // not unique distance to box center
4999 treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
5002 // find distance after which there is no sense to check tree's
5003 double sqLimit = DBL_MAX;
5004 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5005 if ( treeMap.size() > 5 ) {
5006 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5007 closestTree->getBox( box );
5008 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5009 sqLimit = limit * limit;
5011 // get all nodes from trees
5012 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5013 if ( sqDist_tree->first > sqLimit )
5015 SMESH_OctreeNode* tree = sqDist_tree->second;
5016 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5019 // find closest among nodes
5020 minSqDist = DBL_MAX;
5021 const SMDS_MeshNode* closestNode = 0;
5022 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5023 for ( ; nIt != nodes.end(); ++nIt ) {
5024 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5025 if ( minSqDist > sqDist ) {
5035 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5037 SMESH_OctreeNode* myOctreeNode;
5040 //=======================================================================
5042 * \brief Return SMESH_NodeSearcher
5044 //=======================================================================
5046 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5048 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5051 //=======================================================================
5052 //function : SimplifyFace
5054 //=======================================================================
5055 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5056 vector<const SMDS_MeshNode *>& poly_nodes,
5057 vector<int>& quantities) const
5059 int nbNodes = faceNodes.size();
5064 set<const SMDS_MeshNode*> nodeSet;
5066 // get simple seq of nodes
5067 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5068 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5069 int iSimple = 0, nbUnique = 0;
5071 simpleNodes[iSimple++] = faceNodes[0];
5073 for (int iCur = 1; iCur < nbNodes; iCur++) {
5074 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5075 simpleNodes[iSimple++] = faceNodes[iCur];
5076 if (nodeSet.insert( faceNodes[iCur] ).second)
5080 int nbSimple = iSimple;
5081 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5091 bool foundLoop = (nbSimple > nbUnique);
5094 set<const SMDS_MeshNode*> loopSet;
5095 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5096 const SMDS_MeshNode* n = simpleNodes[iSimple];
5097 if (!loopSet.insert( n ).second) {
5101 int iC = 0, curLast = iSimple;
5102 for (; iC < curLast; iC++) {
5103 if (simpleNodes[iC] == n) break;
5105 int loopLen = curLast - iC;
5107 // create sub-element
5109 quantities.push_back(loopLen);
5110 for (; iC < curLast; iC++) {
5111 poly_nodes.push_back(simpleNodes[iC]);
5114 // shift the rest nodes (place from the first loop position)
5115 for (iC = curLast + 1; iC < nbSimple; iC++) {
5116 simpleNodes[iC - loopLen] = simpleNodes[iC];
5118 nbSimple -= loopLen;
5121 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5122 } // while (foundLoop)
5126 quantities.push_back(iSimple);
5127 for (int i = 0; i < iSimple; i++)
5128 poly_nodes.push_back(simpleNodes[i]);
5134 //=======================================================================
5135 //function : MergeNodes
5136 //purpose : In each group, the cdr of nodes are substituted by the first one
5138 //=======================================================================
5140 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5142 myLastCreatedElems.Clear();
5143 myLastCreatedNodes.Clear();
5145 SMESHDS_Mesh* aMesh = GetMeshDS();
5147 TNodeNodeMap nodeNodeMap; // node to replace - new node
5148 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5149 list< int > rmElemIds, rmNodeIds;
5151 // Fill nodeNodeMap and elems
5153 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5154 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5155 list<const SMDS_MeshNode*>& nodes = *grIt;
5156 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5157 const SMDS_MeshNode* nToKeep = *nIt;
5158 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5159 const SMDS_MeshNode* nToRemove = *nIt;
5160 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5161 if ( nToRemove != nToKeep ) {
5162 rmNodeIds.push_back( nToRemove->GetID() );
5163 AddToSameGroups( nToKeep, nToRemove, aMesh );
5166 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5167 while ( invElemIt->more() ) {
5168 const SMDS_MeshElement* elem = invElemIt->next();
5173 // Change element nodes or remove an element
5175 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5176 for ( ; eIt != elems.end(); eIt++ ) {
5177 const SMDS_MeshElement* elem = *eIt;
5178 int nbNodes = elem->NbNodes();
5179 int aShapeId = FindShape( elem );
5181 set<const SMDS_MeshNode*> nodeSet;
5182 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5183 int iUnique = 0, iCur = 0, nbRepl = 0;
5184 vector<int> iRepl( nbNodes );
5186 // get new seq of nodes
5187 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5188 while ( itN->more() ) {
5189 const SMDS_MeshNode* n =
5190 static_cast<const SMDS_MeshNode*>( itN->next() );
5192 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5193 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5195 // BUG 0020185: begin
5197 bool stopRecur = false;
5198 set<const SMDS_MeshNode*> nodesRecur;
5199 nodesRecur.insert(n);
5200 while (!stopRecur) {
5201 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5202 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5203 n = (*nnIt_i).second;
5204 if (!nodesRecur.insert(n).second) {
5205 // error: recursive dependancy
5214 iRepl[ nbRepl++ ] = iCur;
5216 curNodes[ iCur ] = n;
5217 bool isUnique = nodeSet.insert( n ).second;
5219 uniqueNodes[ iUnique++ ] = n;
5223 // Analyse element topology after replacement
5226 int nbUniqueNodes = nodeSet.size();
5227 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5228 // Polygons and Polyhedral volumes
5229 if (elem->IsPoly()) {
5231 if (elem->GetType() == SMDSAbs_Face) {
5233 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5235 for (; inode < nbNodes; inode++) {
5236 face_nodes[inode] = curNodes[inode];
5239 vector<const SMDS_MeshNode *> polygons_nodes;
5240 vector<int> quantities;
5241 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5245 for (int iface = 0; iface < nbNew - 1; iface++) {
5246 int nbNodes = quantities[iface];
5247 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5248 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5249 poly_nodes[ii] = polygons_nodes[inode];
5251 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5252 myLastCreatedElems.Append(newElem);
5254 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5256 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5259 rmElemIds.push_back(elem->GetID());
5263 else if (elem->GetType() == SMDSAbs_Volume) {
5264 // Polyhedral volume
5265 if (nbUniqueNodes < 4) {
5266 rmElemIds.push_back(elem->GetID());
5269 // each face has to be analized in order to check volume validity
5270 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5271 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5273 int nbFaces = aPolyedre->NbFaces();
5275 vector<const SMDS_MeshNode *> poly_nodes;
5276 vector<int> quantities;
5278 for (int iface = 1; iface <= nbFaces; iface++) {
5279 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5280 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5282 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5283 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5284 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5285 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5286 faceNode = (*nnIt).second;
5288 faceNodes[inode - 1] = faceNode;
5291 SimplifyFace(faceNodes, poly_nodes, quantities);
5294 if (quantities.size() > 3) {
5295 // to be done: remove coincident faces
5298 if (quantities.size() > 3)
5299 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5301 rmElemIds.push_back(elem->GetID());
5305 rmElemIds.push_back(elem->GetID());
5316 switch ( nbNodes ) {
5317 case 2: ///////////////////////////////////// EDGE
5318 isOk = false; break;
5319 case 3: ///////////////////////////////////// TRIANGLE
5320 isOk = false; break;
5322 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5324 else { //////////////////////////////////// QUADRANGLE
5325 if ( nbUniqueNodes < 3 )
5327 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5328 isOk = false; // opposite nodes stick
5331 case 6: ///////////////////////////////////// PENTAHEDRON
5332 if ( nbUniqueNodes == 4 ) {
5333 // ---------------------------------> tetrahedron
5335 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5336 // all top nodes stick: reverse a bottom
5337 uniqueNodes[ 0 ] = curNodes [ 1 ];
5338 uniqueNodes[ 1 ] = curNodes [ 0 ];
5340 else if (nbRepl == 3 &&
5341 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5342 // all bottom nodes stick: set a top before
5343 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5344 uniqueNodes[ 0 ] = curNodes [ 3 ];
5345 uniqueNodes[ 1 ] = curNodes [ 4 ];
5346 uniqueNodes[ 2 ] = curNodes [ 5 ];
5348 else if (nbRepl == 4 &&
5349 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5350 // a lateral face turns into a line: reverse a bottom
5351 uniqueNodes[ 0 ] = curNodes [ 1 ];
5352 uniqueNodes[ 1 ] = curNodes [ 0 ];
5357 else if ( nbUniqueNodes == 5 ) {
5358 // PENTAHEDRON --------------------> 2 tetrahedrons
5359 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5360 // a bottom node sticks with a linked top one
5362 SMDS_MeshElement* newElem =
5363 aMesh->AddVolume(curNodes[ 3 ],
5366 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5367 myLastCreatedElems.Append(newElem);
5369 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5370 // 2. : reverse a bottom
5371 uniqueNodes[ 0 ] = curNodes [ 1 ];
5372 uniqueNodes[ 1 ] = curNodes [ 0 ];
5382 if(elem->IsQuadratic()) { // Quadratic quadrangle
5395 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
5396 uniqueNodes[0] = curNodes[0];
5397 uniqueNodes[1] = curNodes[2];
5398 uniqueNodes[2] = curNodes[3];
5399 uniqueNodes[3] = curNodes[5];
5400 uniqueNodes[4] = curNodes[6];
5401 uniqueNodes[5] = curNodes[7];
5404 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
5405 uniqueNodes[0] = curNodes[0];
5406 uniqueNodes[1] = curNodes[1];
5407 uniqueNodes[2] = curNodes[2];
5408 uniqueNodes[3] = curNodes[4];
5409 uniqueNodes[4] = curNodes[5];
5410 uniqueNodes[5] = curNodes[6];
5413 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
5414 uniqueNodes[0] = curNodes[1];
5415 uniqueNodes[1] = curNodes[2];
5416 uniqueNodes[2] = curNodes[3];
5417 uniqueNodes[3] = curNodes[5];
5418 uniqueNodes[4] = curNodes[6];
5419 uniqueNodes[5] = curNodes[0];
5422 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
5423 uniqueNodes[0] = curNodes[0];
5424 uniqueNodes[1] = curNodes[1];
5425 uniqueNodes[2] = curNodes[3];
5426 uniqueNodes[3] = curNodes[4];
5427 uniqueNodes[4] = curNodes[6];
5428 uniqueNodes[5] = curNodes[7];
5431 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
5432 uniqueNodes[0] = curNodes[0];
5433 uniqueNodes[1] = curNodes[2];
5434 uniqueNodes[2] = curNodes[3];
5435 uniqueNodes[3] = curNodes[1];
5436 uniqueNodes[4] = curNodes[6];
5437 uniqueNodes[5] = curNodes[7];
5440 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
5441 uniqueNodes[0] = curNodes[0];
5442 uniqueNodes[1] = curNodes[1];
5443 uniqueNodes[2] = curNodes[2];
5444 uniqueNodes[3] = curNodes[4];
5445 uniqueNodes[4] = curNodes[5];
5446 uniqueNodes[5] = curNodes[7];
5449 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
5450 uniqueNodes[0] = curNodes[0];
5451 uniqueNodes[1] = curNodes[1];
5452 uniqueNodes[2] = curNodes[3];
5453 uniqueNodes[3] = curNodes[4];
5454 uniqueNodes[4] = curNodes[2];
5455 uniqueNodes[5] = curNodes[7];
5458 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
5459 uniqueNodes[0] = curNodes[0];
5460 uniqueNodes[1] = curNodes[1];
5461 uniqueNodes[2] = curNodes[2];
5462 uniqueNodes[3] = curNodes[4];
5463 uniqueNodes[4] = curNodes[5];
5464 uniqueNodes[5] = curNodes[3];
5470 //////////////////////////////////// HEXAHEDRON
5472 SMDS_VolumeTool hexa (elem);
5473 hexa.SetExternalNormal();
5474 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
5475 //////////////////////// ---> tetrahedron
5476 for ( int iFace = 0; iFace < 6; iFace++ ) {
5477 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5478 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5479 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5480 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5481 // one face turns into a point ...
5482 int iOppFace = hexa.GetOppFaceIndex( iFace );
5483 ind = hexa.GetFaceNodesIndices( iOppFace );
5485 iUnique = 2; // reverse a tetrahedron bottom
5486 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
5487 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5489 else if ( iUnique >= 0 )
5490 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5492 if ( nbStick == 1 ) {
5493 // ... and the opposite one - into a triangle.
5495 ind = hexa.GetFaceNodesIndices( iFace );
5496 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
5503 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
5504 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
5505 for ( int iFace = 0; iFace < 6; iFace++ ) {
5506 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5507 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5508 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5509 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5510 // one face turns into a point ...
5511 int iOppFace = hexa.GetOppFaceIndex( iFace );
5512 ind = hexa.GetFaceNodesIndices( iOppFace );
5514 iUnique = 2; // reverse a tetrahedron 1 bottom
5515 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
5516 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5518 else if ( iUnique >= 0 )
5519 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5521 if ( nbStick == 0 ) {
5522 // ... and the opposite one is a quadrangle
5524 const int* indTop = hexa.GetFaceNodesIndices( iFace );
5525 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
5528 SMDS_MeshElement* newElem =
5529 aMesh->AddVolume(curNodes[ind[ 0 ]],
5532 curNodes[indTop[ 0 ]]);
5533 myLastCreatedElems.Append(newElem);
5535 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5542 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
5543 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
5544 // find indices of quad and tri faces
5545 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
5546 for ( iFace = 0; iFace < 6; iFace++ ) {
5547 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5549 for ( iCur = 0; iCur < 4; iCur++ )
5550 nodeSet.insert( curNodes[ind[ iCur ]] );
5551 nbUniqueNodes = nodeSet.size();
5552 if ( nbUniqueNodes == 3 )
5553 iTriFace[ nbTri++ ] = iFace;
5554 else if ( nbUniqueNodes == 4 )
5555 iQuadFace[ nbQuad++ ] = iFace;
5557 if (nbQuad == 2 && nbTri == 4 &&
5558 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
5559 // 2 opposite quadrangles stuck with a diagonal;
5560 // sample groups of merged indices: (0-4)(2-6)
5561 // --------------------------------------------> 2 tetrahedrons
5562 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
5563 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
5564 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
5565 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
5566 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
5567 // stuck with 0-2 diagonal
5575 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
5576 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
5577 // stuck with 1-3 diagonal
5589 uniqueNodes[ 0 ] = curNodes [ i0 ];
5590 uniqueNodes[ 1 ] = curNodes [ i1d ];
5591 uniqueNodes[ 2 ] = curNodes [ i3d ];
5592 uniqueNodes[ 3 ] = curNodes [ i0t ];
5595 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
5599 myLastCreatedElems.Append(newElem);
5601 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5604 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
5605 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
5606 // --------------------------------------------> prism
5607 // find 2 opposite triangles
5609 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
5610 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
5611 // find indices of kept and replaced nodes
5612 // and fill unique nodes of 2 opposite triangles
5613 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
5614 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
5615 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
5616 // fill unique nodes
5619 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
5620 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
5621 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
5623 // iCur of a linked node of the opposite face (make normals co-directed):
5624 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
5625 // check that correspondent corners of triangles are linked
5626 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
5629 uniqueNodes[ iUnique ] = n;
5630 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
5639 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
5645 } // switch ( nbNodes )
5647 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
5650 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
5651 // Change nodes of polyedre
5652 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5653 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5655 int nbFaces = aPolyedre->NbFaces();
5657 vector<const SMDS_MeshNode *> poly_nodes;
5658 vector<int> quantities (nbFaces);
5660 for (int iface = 1; iface <= nbFaces; iface++) {
5661 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5662 quantities[iface - 1] = nbFaceNodes;
5664 for (inode = 1; inode <= nbFaceNodes; inode++) {
5665 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
5667 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
5668 if (nnIt != nodeNodeMap.end()) { // curNode sticks
5669 curNode = (*nnIt).second;
5671 poly_nodes.push_back(curNode);
5674 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
5678 // Change regular element or polygon
5679 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
5683 // Remove invalid regular element or invalid polygon
5684 rmElemIds.push_back( elem->GetID() );
5687 } // loop on elements
5689 // Remove equal nodes and bad elements
5691 Remove( rmNodeIds, true );
5692 Remove( rmElemIds, false );
5697 // ========================================================
5698 // class : SortableElement
5699 // purpose : allow sorting elements basing on their nodes
5700 // ========================================================
5701 class SortableElement : public set <const SMDS_MeshElement*>
5705 SortableElement( const SMDS_MeshElement* theElem )
5708 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
5709 while ( nodeIt->more() )
5710 this->insert( nodeIt->next() );
5713 const SMDS_MeshElement* Get() const
5716 void Set(const SMDS_MeshElement* e) const
5721 mutable const SMDS_MeshElement* myElem;
5724 //=======================================================================
5725 //function : FindEqualElements
5726 //purpose : Return list of group of elements built on the same nodes.
5727 // Search among theElements or in the whole mesh if theElements is empty
5728 //=======================================================================
5729 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
5730 TListOfListOfElementsID & theGroupsOfElementsID)
5732 myLastCreatedElems.Clear();
5733 myLastCreatedNodes.Clear();
5735 typedef set<const SMDS_MeshElement*> TElemsSet;
5736 typedef map< SortableElement, int > TMapOfNodeSet;
5737 typedef list<int> TGroupOfElems;
5740 if ( theElements.empty() )
5741 { // get all elements in the mesh
5742 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
5743 while ( eIt->more() )
5744 elems.insert( elems.end(), eIt->next());
5747 elems = theElements;
5749 vector< TGroupOfElems > arrayOfGroups;
5750 TGroupOfElems groupOfElems;
5751 TMapOfNodeSet mapOfNodeSet;
5753 TElemsSet::iterator elemIt = elems.begin();
5754 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
5755 const SMDS_MeshElement* curElem = *elemIt;
5756 SortableElement SE(curElem);
5759 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
5760 if( !(pp.second) ) {
5761 TMapOfNodeSet::iterator& itSE = pp.first;
5762 ind = (*itSE).second;
5763 arrayOfGroups[ind].push_back(curElem->GetID());
5766 groupOfElems.clear();
5767 groupOfElems.push_back(curElem->GetID());
5768 arrayOfGroups.push_back(groupOfElems);
5773 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
5774 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
5775 groupOfElems = *groupIt;
5776 if ( groupOfElems.size() > 1 ) {
5777 groupOfElems.sort();
5778 theGroupsOfElementsID.push_back(groupOfElems);
5783 //=======================================================================
5784 //function : MergeElements
5785 //purpose : In each given group, substitute all elements by the first one.
5786 //=======================================================================
5788 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
5790 myLastCreatedElems.Clear();
5791 myLastCreatedNodes.Clear();
5793 typedef list<int> TListOfIDs;
5794 TListOfIDs rmElemIds; // IDs of elems to remove
5796 SMESHDS_Mesh* aMesh = GetMeshDS();
5798 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
5799 while ( groupsIt != theGroupsOfElementsID.end() ) {
5800 TListOfIDs& aGroupOfElemID = *groupsIt;
5801 aGroupOfElemID.sort();
5802 int elemIDToKeep = aGroupOfElemID.front();
5803 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
5804 aGroupOfElemID.pop_front();
5805 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
5806 while ( idIt != aGroupOfElemID.end() ) {
5807 int elemIDToRemove = *idIt;
5808 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
5809 // add the kept element in groups of removed one (PAL15188)
5810 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
5811 rmElemIds.push_back( elemIDToRemove );
5817 Remove( rmElemIds, false );
5820 //=======================================================================
5821 //function : MergeEqualElements
5822 //purpose : Remove all but one of elements built on the same nodes.
5823 //=======================================================================
5825 void SMESH_MeshEditor::MergeEqualElements()
5827 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
5828 to merge equal elements in the whole mesh */
5829 TListOfListOfElementsID aGroupsOfElementsID;
5830 FindEqualElements(aMeshElements, aGroupsOfElementsID);
5831 MergeElements(aGroupsOfElementsID);
5834 //=======================================================================
5835 //function : FindFaceInSet
5836 //purpose : Return a face having linked nodes n1 and n2 and which is
5837 // - not in avoidSet,
5838 // - in elemSet provided that !elemSet.empty()
5839 //=======================================================================
5841 const SMDS_MeshElement*
5842 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
5843 const SMDS_MeshNode* n2,
5844 const TIDSortedElemSet& elemSet,
5845 const TIDSortedElemSet& avoidSet)
5848 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
5849 while ( invElemIt->more() ) { // loop on inverse elements of n1
5850 const SMDS_MeshElement* elem = invElemIt->next();
5851 if (avoidSet.find( elem ) != avoidSet.end() )
5853 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
5855 // get face nodes and find index of n1
5856 int i1, nbN = elem->NbNodes(), iNode = 0;
5857 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
5858 vector<const SMDS_MeshNode*> faceNodes( nbN );
5859 const SMDS_MeshNode* n;
5860 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5861 while ( nIt->more() ) {
5862 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5863 if ( faceNodes[ iNode++ ] == n1 )
5866 // find a n2 linked to n1
5867 if(!elem->IsQuadratic()) {
5868 for ( iNode = 0; iNode < 2; iNode++ ) {
5869 if ( iNode ) // node before n1
5870 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5871 else // node after n1
5872 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5877 else { // analysis for quadratic elements
5878 bool IsFind = false;
5879 // check using only corner nodes
5880 for ( iNode = 0; iNode < 2; iNode++ ) {
5881 if ( iNode ) // node before n1
5882 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
5883 else // node after n1
5884 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
5892 // check using all nodes
5893 const SMDS_QuadraticFaceOfNodes* F =
5894 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
5895 // use special nodes iterator
5897 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5898 while ( anIter->more() ) {
5899 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
5900 if ( faceNodes[ iNode++ ] == n1 )
5903 for ( iNode = 0; iNode < 2; iNode++ ) {
5904 if ( iNode ) // node before n1
5905 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5906 else // node after n1
5907 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5913 } // end analysis for quadratic elements
5918 //=======================================================================
5919 //function : findAdjacentFace
5921 //=======================================================================
5923 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
5924 const SMDS_MeshNode* n2,
5925 const SMDS_MeshElement* elem)
5927 TIDSortedElemSet elemSet, avoidSet;
5929 avoidSet.insert ( elem );
5930 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
5933 //=======================================================================
5934 //function : FindFreeBorder
5936 //=======================================================================
5938 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
5940 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
5941 const SMDS_MeshNode* theSecondNode,
5942 const SMDS_MeshNode* theLastNode,
5943 list< const SMDS_MeshNode* > & theNodes,
5944 list< const SMDS_MeshElement* >& theFaces)
5946 if ( !theFirstNode || !theSecondNode )
5948 // find border face between theFirstNode and theSecondNode
5949 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
5953 theFaces.push_back( curElem );
5954 theNodes.push_back( theFirstNode );
5955 theNodes.push_back( theSecondNode );
5957 //vector<const SMDS_MeshNode*> nodes;
5958 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
5959 set < const SMDS_MeshElement* > foundElems;
5960 bool needTheLast = ( theLastNode != 0 );
5962 while ( nStart != theLastNode ) {
5963 if ( nStart == theFirstNode )
5964 return !needTheLast;
5966 // find all free border faces sharing form nStart
5968 list< const SMDS_MeshElement* > curElemList;
5969 list< const SMDS_MeshNode* > nStartList;
5970 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
5971 while ( invElemIt->more() ) {
5972 const SMDS_MeshElement* e = invElemIt->next();
5973 if ( e == curElem || foundElems.insert( e ).second ) {
5975 int iNode = 0, nbNodes = e->NbNodes();
5976 //const SMDS_MeshNode* nodes[nbNodes+1];
5977 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
5979 if(e->IsQuadratic()) {
5980 const SMDS_QuadraticFaceOfNodes* F =
5981 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
5982 // use special nodes iterator
5983 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5984 while( anIter->more() ) {
5985 nodes[ iNode++ ] = anIter->next();
5989 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
5990 while ( nIt->more() )
5991 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5993 nodes[ iNode ] = nodes[ 0 ];
5995 for ( iNode = 0; iNode < nbNodes; iNode++ )
5996 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
5997 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
5998 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6000 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6001 curElemList.push_back( e );
6005 // analyse the found
6007 int nbNewBorders = curElemList.size();
6008 if ( nbNewBorders == 0 ) {
6009 // no free border furthermore
6010 return !needTheLast;
6012 else if ( nbNewBorders == 1 ) {
6013 // one more element found
6015 nStart = nStartList.front();
6016 curElem = curElemList.front();
6017 theFaces.push_back( curElem );
6018 theNodes.push_back( nStart );
6021 // several continuations found
6022 list< const SMDS_MeshElement* >::iterator curElemIt;
6023 list< const SMDS_MeshNode* >::iterator nStartIt;
6024 // check if one of them reached the last node
6025 if ( needTheLast ) {
6026 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6027 curElemIt!= curElemList.end();
6028 curElemIt++, nStartIt++ )
6029 if ( *nStartIt == theLastNode ) {
6030 theFaces.push_back( *curElemIt );
6031 theNodes.push_back( *nStartIt );
6035 // find the best free border by the continuations
6036 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6037 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6038 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6039 curElemIt!= curElemList.end();
6040 curElemIt++, nStartIt++ )
6042 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6043 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6044 // find one more free border
6045 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6049 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6050 // choice: clear a worse one
6051 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6052 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6053 contNodes[ iWorse ].clear();
6054 contFaces[ iWorse ].clear();
6057 if ( contNodes[0].empty() && contNodes[1].empty() )
6060 // append the best free border
6061 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6062 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6063 theNodes.pop_back(); // remove nIgnore
6064 theNodes.pop_back(); // remove nStart
6065 theFaces.pop_back(); // remove curElem
6066 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6067 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6068 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6069 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6072 } // several continuations found
6073 } // while ( nStart != theLastNode )
6078 //=======================================================================
6079 //function : CheckFreeBorderNodes
6080 //purpose : Return true if the tree nodes are on a free border
6081 //=======================================================================
6083 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6084 const SMDS_MeshNode* theNode2,
6085 const SMDS_MeshNode* theNode3)
6087 list< const SMDS_MeshNode* > nodes;
6088 list< const SMDS_MeshElement* > faces;
6089 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6092 //=======================================================================
6093 //function : SewFreeBorder
6095 //=======================================================================
6097 SMESH_MeshEditor::Sew_Error
6098 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6099 const SMDS_MeshNode* theBordSecondNode,
6100 const SMDS_MeshNode* theBordLastNode,
6101 const SMDS_MeshNode* theSideFirstNode,
6102 const SMDS_MeshNode* theSideSecondNode,
6103 const SMDS_MeshNode* theSideThirdNode,
6104 const bool theSideIsFreeBorder,
6105 const bool toCreatePolygons,
6106 const bool toCreatePolyedrs)
6108 myLastCreatedElems.Clear();
6109 myLastCreatedNodes.Clear();
6111 MESSAGE("::SewFreeBorder()");
6112 Sew_Error aResult = SEW_OK;
6114 // ====================================
6115 // find side nodes and elements
6116 // ====================================
6118 list< const SMDS_MeshNode* > nSide[ 2 ];
6119 list< const SMDS_MeshElement* > eSide[ 2 ];
6120 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6121 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6125 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6126 nSide[0], eSide[0])) {
6127 MESSAGE(" Free Border 1 not found " );
6128 aResult = SEW_BORDER1_NOT_FOUND;
6130 if (theSideIsFreeBorder) {
6133 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6134 nSide[1], eSide[1])) {
6135 MESSAGE(" Free Border 2 not found " );
6136 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6139 if ( aResult != SEW_OK )
6142 if (!theSideIsFreeBorder) {
6146 // -------------------------------------------------------------------------
6148 // 1. If nodes to merge are not coincident, move nodes of the free border
6149 // from the coord sys defined by the direction from the first to last
6150 // nodes of the border to the correspondent sys of the side 2
6151 // 2. On the side 2, find the links most co-directed with the correspondent
6152 // links of the free border
6153 // -------------------------------------------------------------------------
6155 // 1. Since sewing may brake if there are volumes to split on the side 2,
6156 // we wont move nodes but just compute new coordinates for them
6157 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6158 TNodeXYZMap nBordXYZ;
6159 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6160 list< const SMDS_MeshNode* >::iterator nBordIt;
6162 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6163 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6164 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6165 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6166 double tol2 = 1.e-8;
6167 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6168 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6169 // Need node movement.
6171 // find X and Z axes to create trsf
6172 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6174 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6176 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6179 gp_Ax3 toBordAx( Pb1, Zb, X );
6180 gp_Ax3 fromSideAx( Ps1, Zs, X );
6181 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6183 gp_Trsf toBordSys, fromSide2Sys;
6184 toBordSys.SetTransformation( toBordAx );
6185 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6186 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6189 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6190 const SMDS_MeshNode* n = *nBordIt;
6191 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6192 toBordSys.Transforms( xyz );
6193 fromSide2Sys.Transforms( xyz );
6194 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6198 // just insert nodes XYZ in the nBordXYZ map
6199 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6200 const SMDS_MeshNode* n = *nBordIt;
6201 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6205 // 2. On the side 2, find the links most co-directed with the correspondent
6206 // links of the free border
6208 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6209 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6210 sideNodes.push_back( theSideFirstNode );
6212 bool hasVolumes = false;
6213 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6214 set<long> foundSideLinkIDs, checkedLinkIDs;
6215 SMDS_VolumeTool volume;
6216 //const SMDS_MeshNode* faceNodes[ 4 ];
6218 const SMDS_MeshNode* sideNode;
6219 const SMDS_MeshElement* sideElem;
6220 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6221 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6222 nBordIt = bordNodes.begin();
6224 // border node position and border link direction to compare with
6225 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6226 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6227 // choose next side node by link direction or by closeness to
6228 // the current border node:
6229 bool searchByDir = ( *nBordIt != theBordLastNode );
6231 // find the next node on the Side 2
6233 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6235 checkedLinkIDs.clear();
6236 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6238 // loop on inverse elements of current node (prevSideNode) on the Side 2
6239 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6240 while ( invElemIt->more() )
6242 const SMDS_MeshElement* elem = invElemIt->next();
6243 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6244 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6245 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6246 bool isVolume = volume.Set( elem );
6247 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6248 if ( isVolume ) // --volume
6250 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6251 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6252 if(elem->IsQuadratic()) {
6253 const SMDS_QuadraticFaceOfNodes* F =
6254 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6255 // use special nodes iterator
6256 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6257 while( anIter->more() ) {
6258 nodes[ iNode ] = anIter->next();
6259 if ( nodes[ iNode++ ] == prevSideNode )
6260 iPrevNode = iNode - 1;
6264 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6265 while ( nIt->more() ) {
6266 nodes[ iNode ] = cast2Node( nIt->next() );
6267 if ( nodes[ iNode++ ] == prevSideNode )
6268 iPrevNode = iNode - 1;
6271 // there are 2 links to check
6276 // loop on links, to be precise, on the second node of links
6277 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6278 const SMDS_MeshNode* n = nodes[ iNode ];
6280 if ( !volume.IsLinked( n, prevSideNode ))
6284 if ( iNode ) // a node before prevSideNode
6285 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6286 else // a node after prevSideNode
6287 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6289 // check if this link was already used
6290 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6291 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6292 if (!isJustChecked &&
6293 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6295 // test a link geometrically
6296 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6297 bool linkIsBetter = false;
6298 double dot = 0.0, dist = 0.0;
6299 if ( searchByDir ) { // choose most co-directed link
6300 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6301 linkIsBetter = ( dot > maxDot );
6303 else { // choose link with the node closest to bordPos
6304 dist = ( nextXYZ - bordPos ).SquareModulus();
6305 linkIsBetter = ( dist < minDist );
6307 if ( linkIsBetter ) {
6316 } // loop on inverse elements of prevSideNode
6319 MESSAGE(" Cant find path by links of the Side 2 ");
6320 return SEW_BAD_SIDE_NODES;
6322 sideNodes.push_back( sideNode );
6323 sideElems.push_back( sideElem );
6324 foundSideLinkIDs.insert ( linkID );
6325 prevSideNode = sideNode;
6327 if ( *nBordIt == theBordLastNode )
6328 searchByDir = false;
6330 // find the next border link to compare with
6331 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6332 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6333 // move to next border node if sideNode is before forward border node (bordPos)
6334 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6335 prevBordNode = *nBordIt;
6337 bordPos = nBordXYZ[ *nBordIt ];
6338 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6339 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6343 while ( sideNode != theSideSecondNode );
6345 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6346 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6347 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6349 } // end nodes search on the side 2
6351 // ============================
6352 // sew the border to the side 2
6353 // ============================
6355 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6356 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6358 TListOfListOfNodes nodeGroupsToMerge;
6359 if ( nbNodes[0] == nbNodes[1] ||
6360 ( theSideIsFreeBorder && !theSideThirdNode)) {
6362 // all nodes are to be merged
6364 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6365 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6366 nIt[0]++, nIt[1]++ )
6368 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6369 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6370 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6375 // insert new nodes into the border and the side to get equal nb of segments
6377 // get normalized parameters of nodes on the borders
6378 //double param[ 2 ][ maxNbNodes ];
6380 param[0] = new double [ maxNbNodes ];
6381 param[1] = new double [ maxNbNodes ];
6383 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6384 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6385 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6386 const SMDS_MeshNode* nPrev = *nIt;
6387 double bordLength = 0;
6388 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
6389 const SMDS_MeshNode* nCur = *nIt;
6390 gp_XYZ segment (nCur->X() - nPrev->X(),
6391 nCur->Y() - nPrev->Y(),
6392 nCur->Z() - nPrev->Z());
6393 double segmentLen = segment.Modulus();
6394 bordLength += segmentLen;
6395 param[ iBord ][ iNode ] = bordLength;
6398 // normalize within [0,1]
6399 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
6400 param[ iBord ][ iNode ] /= bordLength;
6404 // loop on border segments
6405 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
6406 int i[ 2 ] = { 0, 0 };
6407 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
6408 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
6410 TElemOfNodeListMap insertMap;
6411 TElemOfNodeListMap::iterator insertMapIt;
6413 // key: elem to insert nodes into
6414 // value: 2 nodes to insert between + nodes to be inserted
6416 bool next[ 2 ] = { false, false };
6418 // find min adjacent segment length after sewing
6419 double nextParam = 10., prevParam = 0;
6420 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6421 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
6422 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
6423 if ( i[ iBord ] > 0 )
6424 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
6426 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6427 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6428 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
6430 // choose to insert or to merge nodes
6431 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
6432 if ( Abs( du ) <= minSegLen * 0.2 ) {
6435 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6436 const SMDS_MeshNode* n0 = *nIt[0];
6437 const SMDS_MeshNode* n1 = *nIt[1];
6438 nodeGroupsToMerge.back().push_back( n1 );
6439 nodeGroupsToMerge.back().push_back( n0 );
6440 // position of node of the border changes due to merge
6441 param[ 0 ][ i[0] ] += du;
6442 // move n1 for the sake of elem shape evaluation during insertion.
6443 // n1 will be removed by MergeNodes() anyway
6444 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
6445 next[0] = next[1] = true;
6450 int intoBord = ( du < 0 ) ? 0 : 1;
6451 const SMDS_MeshElement* elem = *eIt[ intoBord ];
6452 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
6453 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
6454 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
6455 if ( intoBord == 1 ) {
6456 // move node of the border to be on a link of elem of the side
6457 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
6458 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
6459 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
6460 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
6461 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
6463 insertMapIt = insertMap.find( elem );
6464 bool notFound = ( insertMapIt == insertMap.end() );
6465 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
6467 // insert into another link of the same element:
6468 // 1. perform insertion into the other link of the elem
6469 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6470 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
6471 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
6472 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
6473 // 2. perform insertion into the link of adjacent faces
6475 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
6477 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
6481 if (toCreatePolyedrs) {
6482 // perform insertion into the links of adjacent volumes
6483 UpdateVolumes(n12, n22, nodeList);
6485 // 3. find an element appeared on n1 and n2 after the insertion
6486 insertMap.erase( elem );
6487 elem = findAdjacentFace( n1, n2, 0 );
6489 if ( notFound || otherLink ) {
6490 // add element and nodes of the side into the insertMap
6491 insertMapIt = insertMap.insert
6492 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
6493 (*insertMapIt).second.push_back( n1 );
6494 (*insertMapIt).second.push_back( n2 );
6496 // add node to be inserted into elem
6497 (*insertMapIt).second.push_back( nIns );
6498 next[ 1 - intoBord ] = true;
6501 // go to the next segment
6502 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6503 if ( next[ iBord ] ) {
6504 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
6506 nPrev[ iBord ] = *nIt[ iBord ];
6507 nIt[ iBord ]++; i[ iBord ]++;
6511 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
6513 // perform insertion of nodes into elements
6515 for (insertMapIt = insertMap.begin();
6516 insertMapIt != insertMap.end();
6519 const SMDS_MeshElement* elem = (*insertMapIt).first;
6520 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6521 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
6522 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
6524 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
6526 if ( !theSideIsFreeBorder ) {
6527 // look for and insert nodes into the faces adjacent to elem
6529 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
6531 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
6536 if (toCreatePolyedrs) {
6537 // perform insertion into the links of adjacent volumes
6538 UpdateVolumes(n1, n2, nodeList);
6544 } // end: insert new nodes
6546 MergeNodes ( nodeGroupsToMerge );
6551 //=======================================================================
6552 //function : InsertNodesIntoLink
6553 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
6554 // and theBetweenNode2 and split theElement
6555 //=======================================================================
6557 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
6558 const SMDS_MeshNode* theBetweenNode1,
6559 const SMDS_MeshNode* theBetweenNode2,
6560 list<const SMDS_MeshNode*>& theNodesToInsert,
6561 const bool toCreatePoly)
6563 if ( theFace->GetType() != SMDSAbs_Face ) return;
6565 // find indices of 2 link nodes and of the rest nodes
6566 int iNode = 0, il1, il2, i3, i4;
6567 il1 = il2 = i3 = i4 = -1;
6568 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
6569 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
6571 if(theFace->IsQuadratic()) {
6572 const SMDS_QuadraticFaceOfNodes* F =
6573 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6574 // use special nodes iterator
6575 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6576 while( anIter->more() ) {
6577 const SMDS_MeshNode* n = anIter->next();
6578 if ( n == theBetweenNode1 )
6580 else if ( n == theBetweenNode2 )
6586 nodes[ iNode++ ] = n;
6590 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6591 while ( nodeIt->more() ) {
6592 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6593 if ( n == theBetweenNode1 )
6595 else if ( n == theBetweenNode2 )
6601 nodes[ iNode++ ] = n;
6604 if ( il1 < 0 || il2 < 0 || i3 < 0 )
6607 // arrange link nodes to go one after another regarding the face orientation
6608 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
6609 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
6614 aNodesToInsert.reverse();
6616 // check that not link nodes of a quadrangles are in good order
6617 int nbFaceNodes = theFace->NbNodes();
6618 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
6624 if (toCreatePoly || theFace->IsPoly()) {
6627 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
6629 // add nodes of face up to first node of link
6632 if(theFace->IsQuadratic()) {
6633 const SMDS_QuadraticFaceOfNodes* F =
6634 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6635 // use special nodes iterator
6636 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6637 while( anIter->more() && !isFLN ) {
6638 const SMDS_MeshNode* n = anIter->next();
6639 poly_nodes[iNode++] = n;
6640 if (n == nodes[il1]) {
6644 // add nodes to insert
6645 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6646 for (; nIt != aNodesToInsert.end(); nIt++) {
6647 poly_nodes[iNode++] = *nIt;
6649 // add nodes of face starting from last node of link
6650 while ( anIter->more() ) {
6651 poly_nodes[iNode++] = anIter->next();
6655 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6656 while ( nodeIt->more() && !isFLN ) {
6657 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6658 poly_nodes[iNode++] = n;
6659 if (n == nodes[il1]) {
6663 // add nodes to insert
6664 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6665 for (; nIt != aNodesToInsert.end(); nIt++) {
6666 poly_nodes[iNode++] = *nIt;
6668 // add nodes of face starting from last node of link
6669 while ( nodeIt->more() ) {
6670 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6671 poly_nodes[iNode++] = n;
6675 // edit or replace the face
6676 SMESHDS_Mesh *aMesh = GetMeshDS();
6678 if (theFace->IsPoly()) {
6679 aMesh->ChangePolygonNodes(theFace, poly_nodes);
6682 int aShapeId = FindShape( theFace );
6684 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6685 myLastCreatedElems.Append(newElem);
6686 if ( aShapeId && newElem )
6687 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6689 aMesh->RemoveElement(theFace);
6694 if( !theFace->IsQuadratic() ) {
6696 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
6697 int nbLinkNodes = 2 + aNodesToInsert.size();
6698 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
6699 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
6700 linkNodes[ 0 ] = nodes[ il1 ];
6701 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
6702 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6703 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6704 linkNodes[ iNode++ ] = *nIt;
6706 // decide how to split a quadrangle: compare possible variants
6707 // and choose which of splits to be a quadrangle
6708 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
6709 if ( nbFaceNodes == 3 ) {
6710 iBestQuad = nbSplits;
6713 else if ( nbFaceNodes == 4 ) {
6714 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
6715 double aBestRate = DBL_MAX;
6716 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
6718 double aBadRate = 0;
6719 // evaluate elements quality
6720 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
6721 if ( iSplit == iQuad ) {
6722 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
6726 aBadRate += getBadRate( &quad, aCrit );
6729 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
6731 nodes[ iSplit < iQuad ? i4 : i3 ]);
6732 aBadRate += getBadRate( &tria, aCrit );
6736 if ( aBadRate < aBestRate ) {
6738 aBestRate = aBadRate;
6743 // create new elements
6744 SMESHDS_Mesh *aMesh = GetMeshDS();
6745 int aShapeId = FindShape( theFace );
6748 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
6749 SMDS_MeshElement* newElem = 0;
6750 if ( iSplit == iBestQuad )
6751 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6756 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6758 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
6759 myLastCreatedElems.Append(newElem);
6760 if ( aShapeId && newElem )
6761 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6764 // change nodes of theFace
6765 const SMDS_MeshNode* newNodes[ 4 ];
6766 newNodes[ 0 ] = linkNodes[ i1 ];
6767 newNodes[ 1 ] = linkNodes[ i2 ];
6768 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
6769 newNodes[ 3 ] = nodes[ i4 ];
6770 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
6771 } // end if(!theFace->IsQuadratic())
6772 else { // theFace is quadratic
6773 // we have to split theFace on simple triangles and one simple quadrangle
6775 int nbshift = tmp*2;
6776 // shift nodes in nodes[] by nbshift
6778 for(i=0; i<nbshift; i++) {
6779 const SMDS_MeshNode* n = nodes[0];
6780 for(j=0; j<nbFaceNodes-1; j++) {
6781 nodes[j] = nodes[j+1];
6783 nodes[nbFaceNodes-1] = n;
6785 il1 = il1 - nbshift;
6786 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
6787 // n0 n1 n2 n0 n1 n2
6788 // +-----+-----+ +-----+-----+
6797 // create new elements
6798 SMESHDS_Mesh *aMesh = GetMeshDS();
6799 int aShapeId = FindShape( theFace );
6802 if(nbFaceNodes==6) { // quadratic triangle
6803 SMDS_MeshElement* newElem =
6804 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6805 myLastCreatedElems.Append(newElem);
6806 if ( aShapeId && newElem )
6807 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6808 if(theFace->IsMediumNode(nodes[il1])) {
6809 // create quadrangle
6810 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
6811 myLastCreatedElems.Append(newElem);
6812 if ( aShapeId && newElem )
6813 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6819 // create quadrangle
6820 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
6821 myLastCreatedElems.Append(newElem);
6822 if ( aShapeId && newElem )
6823 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6829 else { // nbFaceNodes==8 - quadratic quadrangle
6830 SMDS_MeshElement* newElem =
6831 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6832 myLastCreatedElems.Append(newElem);
6833 if ( aShapeId && newElem )
6834 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6835 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
6836 myLastCreatedElems.Append(newElem);
6837 if ( aShapeId && newElem )
6838 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6839 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
6840 myLastCreatedElems.Append(newElem);
6841 if ( aShapeId && newElem )
6842 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6843 if(theFace->IsMediumNode(nodes[il1])) {
6844 // create quadrangle
6845 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
6846 myLastCreatedElems.Append(newElem);
6847 if ( aShapeId && newElem )
6848 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6854 // create quadrangle
6855 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
6856 myLastCreatedElems.Append(newElem);
6857 if ( aShapeId && newElem )
6858 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6864 // create needed triangles using n1,n2,n3 and inserted nodes
6865 int nbn = 2 + aNodesToInsert.size();
6866 //const SMDS_MeshNode* aNodes[nbn];
6867 vector<const SMDS_MeshNode*> aNodes(nbn);
6868 aNodes[0] = nodes[n1];
6869 aNodes[nbn-1] = nodes[n2];
6870 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6871 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6872 aNodes[iNode++] = *nIt;
6874 for(i=1; i<nbn; i++) {
6875 SMDS_MeshElement* newElem =
6876 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
6877 myLastCreatedElems.Append(newElem);
6878 if ( aShapeId && newElem )
6879 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6881 // remove old quadratic face
6882 aMesh->RemoveElement(theFace);
6886 //=======================================================================
6887 //function : UpdateVolumes
6889 //=======================================================================
6890 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
6891 const SMDS_MeshNode* theBetweenNode2,
6892 list<const SMDS_MeshNode*>& theNodesToInsert)
6894 myLastCreatedElems.Clear();
6895 myLastCreatedNodes.Clear();
6897 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
6898 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
6899 const SMDS_MeshElement* elem = invElemIt->next();
6901 // check, if current volume has link theBetweenNode1 - theBetweenNode2
6902 SMDS_VolumeTool aVolume (elem);
6903 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
6906 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
6907 int iface, nbFaces = aVolume.NbFaces();
6908 vector<const SMDS_MeshNode *> poly_nodes;
6909 vector<int> quantities (nbFaces);
6911 for (iface = 0; iface < nbFaces; iface++) {
6912 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
6913 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
6914 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
6916 for (int inode = 0; inode < nbFaceNodes; inode++) {
6917 poly_nodes.push_back(faceNodes[inode]);
6919 if (nbInserted == 0) {
6920 if (faceNodes[inode] == theBetweenNode1) {
6921 if (faceNodes[inode + 1] == theBetweenNode2) {
6922 nbInserted = theNodesToInsert.size();
6924 // add nodes to insert
6925 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
6926 for (; nIt != theNodesToInsert.end(); nIt++) {
6927 poly_nodes.push_back(*nIt);
6931 else if (faceNodes[inode] == theBetweenNode2) {
6932 if (faceNodes[inode + 1] == theBetweenNode1) {
6933 nbInserted = theNodesToInsert.size();
6935 // add nodes to insert in reversed order
6936 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
6938 for (; nIt != theNodesToInsert.begin(); nIt--) {
6939 poly_nodes.push_back(*nIt);
6941 poly_nodes.push_back(*nIt);
6948 quantities[iface] = nbFaceNodes + nbInserted;
6951 // Replace or update the volume
6952 SMESHDS_Mesh *aMesh = GetMeshDS();
6954 if (elem->IsPoly()) {
6955 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6959 int aShapeId = FindShape( elem );
6961 SMDS_MeshElement* newElem =
6962 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6963 myLastCreatedElems.Append(newElem);
6964 if (aShapeId && newElem)
6965 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6967 aMesh->RemoveElement(elem);
6972 //=======================================================================
6974 * \brief Convert elements contained in a submesh to quadratic
6975 * \retval int - nb of checked elements
6977 //=======================================================================
6979 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
6980 SMESH_MesherHelper& theHelper,
6981 const bool theForce3d)
6984 if( !theSm ) return nbElem;
6986 const bool notFromGroups = false;
6987 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
6988 while(ElemItr->more())
6991 const SMDS_MeshElement* elem = ElemItr->next();
6992 if( !elem || elem->IsQuadratic() ) continue;
6994 int id = elem->GetID();
6995 int nbNodes = elem->NbNodes();
6996 vector<const SMDS_MeshNode *> aNds (nbNodes);
6998 for(int i = 0; i < nbNodes; i++)
7000 aNds[i] = elem->GetNode(i);
7002 SMDSAbs_ElementType aType = elem->GetType();
7004 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7006 const SMDS_MeshElement* NewElem = 0;
7012 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7020 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7023 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7030 case SMDSAbs_Volume :
7035 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7038 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7041 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7042 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7052 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7054 theSm->AddElement( NewElem );
7059 //=======================================================================
7060 //function : ConvertToQuadratic
7062 //=======================================================================
7063 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7065 SMESHDS_Mesh* meshDS = GetMeshDS();
7067 SMESH_MesherHelper aHelper(*myMesh);
7068 aHelper.SetIsQuadratic( true );
7069 const bool notFromGroups = false;
7071 int nbCheckedElems = 0;
7072 if ( myMesh->HasShapeToMesh() )
7074 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7076 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7077 while ( smIt->more() ) {
7078 SMESH_subMesh* sm = smIt->next();
7079 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7080 aHelper.SetSubShape( sm->GetSubShape() );
7081 if ( !theForce3d) aHelper.SetCheckNodePosition(true);
7082 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7087 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7088 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7090 SMESHDS_SubMesh *smDS = 0;
7091 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7092 while(aEdgeItr->more())
7094 const SMDS_MeshEdge* edge = aEdgeItr->next();
7095 if(edge && !edge->IsQuadratic())
7097 int id = edge->GetID();
7098 const SMDS_MeshNode* n1 = edge->GetNode(0);
7099 const SMDS_MeshNode* n2 = edge->GetNode(1);
7101 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7103 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7104 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7107 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7108 while(aFaceItr->more())
7110 const SMDS_MeshFace* face = aFaceItr->next();
7111 if(!face || face->IsQuadratic() ) continue;
7113 int id = face->GetID();
7114 int nbNodes = face->NbNodes();
7115 vector<const SMDS_MeshNode *> aNds (nbNodes);
7117 for(int i = 0; i < nbNodes; i++)
7119 aNds[i] = face->GetNode(i);
7122 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7124 SMDS_MeshFace * NewFace = 0;
7128 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7131 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7136 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7138 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7139 while(aVolumeItr->more())
7141 const SMDS_MeshVolume* volume = aVolumeItr->next();
7142 if(!volume || volume->IsQuadratic() ) continue;
7144 int id = volume->GetID();
7145 int nbNodes = volume->NbNodes();
7146 vector<const SMDS_MeshNode *> aNds (nbNodes);
7148 for(int i = 0; i < nbNodes; i++)
7150 aNds[i] = volume->GetNode(i);
7153 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7155 SMDS_MeshVolume * NewVolume = 0;
7159 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7160 aNds[3], id, theForce3d );
7163 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7164 aNds[3], aNds[4], aNds[5], id, theForce3d);
7167 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7168 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7173 ReplaceElemInGroups(volume, NewVolume, meshDS);
7176 if ( !theForce3d ) {
7177 aHelper.SetSubShape(0); // apply to the whole mesh
7178 aHelper.FixQuadraticElements();
7182 //=======================================================================
7184 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7185 * \retval int - nb of checked elements
7187 //=======================================================================
7189 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7190 SMDS_ElemIteratorPtr theItr,
7191 const int theShapeID)
7194 SMESHDS_Mesh* meshDS = GetMeshDS();
7195 const bool notFromGroups = false;
7197 while( theItr->more() )
7199 const SMDS_MeshElement* elem = theItr->next();
7201 if( elem && elem->IsQuadratic())
7203 int id = elem->GetID();
7204 int nbNodes = elem->NbNodes();
7205 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7206 aNds.reserve( nbNodes );
7207 mediumNodes.reserve( nbNodes );
7209 for(int i = 0; i < nbNodes; i++)
7211 const SMDS_MeshNode* n = elem->GetNode(i);
7213 if( elem->IsMediumNode( n ) )
7214 mediumNodes.push_back( n );
7216 aNds.push_back( n );
7218 if( aNds.empty() ) continue;
7219 SMDSAbs_ElementType aType = elem->GetType();
7221 //remove old quadratic element
7222 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7224 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7225 ReplaceElemInGroups(elem, NewElem, meshDS);
7226 if( theSm && NewElem )
7227 theSm->AddElement( NewElem );
7229 // remove medium nodes
7230 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7231 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7232 const SMDS_MeshNode* n = *nIt;
7233 if ( n->NbInverseElements() == 0 ) {
7234 if ( n->GetPosition()->GetShapeId() != theShapeID )
7235 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7236 ( n->GetPosition()->GetShapeId() ));
7238 meshDS->RemoveFreeNode( n, theSm );
7246 //=======================================================================
7247 //function : ConvertFromQuadratic
7249 //=======================================================================
7250 bool SMESH_MeshEditor::ConvertFromQuadratic()
7252 int nbCheckedElems = 0;
7253 if ( myMesh->HasShapeToMesh() )
7255 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7257 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7258 while ( smIt->more() ) {
7259 SMESH_subMesh* sm = smIt->next();
7260 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7261 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7267 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7268 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7270 SMESHDS_SubMesh *aSM = 0;
7271 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7277 //=======================================================================
7278 //function : SewSideElements
7280 //=======================================================================
7282 SMESH_MeshEditor::Sew_Error
7283 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7284 TIDSortedElemSet& theSide2,
7285 const SMDS_MeshNode* theFirstNode1,
7286 const SMDS_MeshNode* theFirstNode2,
7287 const SMDS_MeshNode* theSecondNode1,
7288 const SMDS_MeshNode* theSecondNode2)
7290 myLastCreatedElems.Clear();
7291 myLastCreatedNodes.Clear();
7293 MESSAGE ("::::SewSideElements()");
7294 if ( theSide1.size() != theSide2.size() )
7295 return SEW_DIFF_NB_OF_ELEMENTS;
7297 Sew_Error aResult = SEW_OK;
7299 // 1. Build set of faces representing each side
7300 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7301 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7303 // =======================================================================
7304 // 1. Build set of faces representing each side:
7305 // =======================================================================
7306 // a. build set of nodes belonging to faces
7307 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7308 // c. create temporary faces representing side of volumes if correspondent
7309 // face does not exist
7311 SMESHDS_Mesh* aMesh = GetMeshDS();
7312 SMDS_Mesh aTmpFacesMesh;
7313 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7314 set<const SMDS_MeshElement*> volSet1, volSet2;
7315 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7316 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7317 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7318 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7319 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7320 int iSide, iFace, iNode;
7322 for ( iSide = 0; iSide < 2; iSide++ ) {
7323 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7324 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7325 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7326 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7327 set<const SMDS_MeshElement*>::iterator vIt;
7328 TIDSortedElemSet::iterator eIt;
7329 set<const SMDS_MeshNode*>::iterator nIt;
7331 // check that given nodes belong to given elements
7332 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7333 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7334 int firstIndex = -1, secondIndex = -1;
7335 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7336 const SMDS_MeshElement* elem = *eIt;
7337 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7338 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7339 if ( firstIndex > -1 && secondIndex > -1 ) break;
7341 if ( firstIndex < 0 || secondIndex < 0 ) {
7342 // we can simply return until temporary faces created
7343 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7346 // -----------------------------------------------------------
7347 // 1a. Collect nodes of existing faces
7348 // and build set of face nodes in order to detect missing
7349 // faces corresponing to sides of volumes
7350 // -----------------------------------------------------------
7352 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7354 // loop on the given element of a side
7355 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7356 //const SMDS_MeshElement* elem = *eIt;
7357 const SMDS_MeshElement* elem = *eIt;
7358 if ( elem->GetType() == SMDSAbs_Face ) {
7359 faceSet->insert( elem );
7360 set <const SMDS_MeshNode*> faceNodeSet;
7361 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7362 while ( nodeIt->more() ) {
7363 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7364 nodeSet->insert( n );
7365 faceNodeSet.insert( n );
7367 setOfFaceNodeSet.insert( faceNodeSet );
7369 else if ( elem->GetType() == SMDSAbs_Volume )
7370 volSet->insert( elem );
7372 // ------------------------------------------------------------------------------
7373 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7374 // ------------------------------------------------------------------------------
7376 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7377 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7378 while ( fIt->more() ) { // loop on faces sharing a node
7379 const SMDS_MeshElement* f = fIt->next();
7380 if ( faceSet->find( f ) == faceSet->end() ) {
7381 // check if all nodes are in nodeSet and
7382 // complete setOfFaceNodeSet if they are
7383 set <const SMDS_MeshNode*> faceNodeSet;
7384 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7385 bool allInSet = true;
7386 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7387 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7388 if ( nodeSet->find( n ) == nodeSet->end() )
7391 faceNodeSet.insert( n );
7394 faceSet->insert( f );
7395 setOfFaceNodeSet.insert( faceNodeSet );
7401 // -------------------------------------------------------------------------
7402 // 1c. Create temporary faces representing sides of volumes if correspondent
7403 // face does not exist
7404 // -------------------------------------------------------------------------
7406 if ( !volSet->empty() ) {
7407 //int nodeSetSize = nodeSet->size();
7409 // loop on given volumes
7410 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
7411 SMDS_VolumeTool vol (*vIt);
7412 // loop on volume faces: find free faces
7413 // --------------------------------------
7414 list<const SMDS_MeshElement* > freeFaceList;
7415 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
7416 if ( !vol.IsFreeFace( iFace ))
7418 // check if there is already a face with same nodes in a face set
7419 const SMDS_MeshElement* aFreeFace = 0;
7420 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
7421 int nbNodes = vol.NbFaceNodes( iFace );
7422 set <const SMDS_MeshNode*> faceNodeSet;
7423 vol.GetFaceNodes( iFace, faceNodeSet );
7424 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
7426 // no such a face is given but it still can exist, check it
7427 if ( nbNodes == 3 ) {
7428 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
7430 else if ( nbNodes == 4 ) {
7431 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7434 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7435 aFreeFace = aMesh->FindFace(poly_nodes);
7439 // create a temporary face
7440 if ( nbNodes == 3 ) {
7441 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
7443 else if ( nbNodes == 4 ) {
7444 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7447 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7448 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
7452 freeFaceList.push_back( aFreeFace );
7454 } // loop on faces of a volume
7456 // choose one of several free faces
7457 // --------------------------------------
7458 if ( freeFaceList.size() > 1 ) {
7459 // choose a face having max nb of nodes shared by other elems of a side
7460 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
7461 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
7462 while ( fIt != freeFaceList.end() ) { // loop on free faces
7463 int nbSharedNodes = 0;
7464 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7465 while ( nodeIt->more() ) { // loop on free face nodes
7466 const SMDS_MeshNode* n =
7467 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7468 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
7469 while ( invElemIt->more() ) {
7470 const SMDS_MeshElement* e = invElemIt->next();
7471 if ( faceSet->find( e ) != faceSet->end() )
7473 if ( elemSet->find( e ) != elemSet->end() )
7477 if ( nbSharedNodes >= maxNbNodes ) {
7478 maxNbNodes = nbSharedNodes;
7482 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
7484 if ( freeFaceList.size() > 1 )
7486 // could not choose one face, use another way
7487 // choose a face most close to the bary center of the opposite side
7488 gp_XYZ aBC( 0., 0., 0. );
7489 set <const SMDS_MeshNode*> addedNodes;
7490 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
7491 eIt = elemSet2->begin();
7492 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
7493 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
7494 while ( nodeIt->more() ) { // loop on free face nodes
7495 const SMDS_MeshNode* n =
7496 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7497 if ( addedNodes.insert( n ).second )
7498 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
7501 aBC /= addedNodes.size();
7502 double minDist = DBL_MAX;
7503 fIt = freeFaceList.begin();
7504 while ( fIt != freeFaceList.end() ) { // loop on free faces
7506 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7507 while ( nodeIt->more() ) { // loop on free face nodes
7508 const SMDS_MeshNode* n =
7509 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7510 gp_XYZ p( n->X(),n->Y(),n->Z() );
7511 dist += ( aBC - p ).SquareModulus();
7513 if ( dist < minDist ) {
7515 freeFaceList.erase( freeFaceList.begin(), fIt++ );
7518 fIt = freeFaceList.erase( fIt++ );
7521 } // choose one of several free faces of a volume
7523 if ( freeFaceList.size() == 1 ) {
7524 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
7525 faceSet->insert( aFreeFace );
7526 // complete a node set with nodes of a found free face
7527 // for ( iNode = 0; iNode < ; iNode++ )
7528 // nodeSet->insert( fNodes[ iNode ] );
7531 } // loop on volumes of a side
7533 // // complete a set of faces if new nodes in a nodeSet appeared
7534 // // ----------------------------------------------------------
7535 // if ( nodeSetSize != nodeSet->size() ) {
7536 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7537 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7538 // while ( fIt->more() ) { // loop on faces sharing a node
7539 // const SMDS_MeshElement* f = fIt->next();
7540 // if ( faceSet->find( f ) == faceSet->end() ) {
7541 // // check if all nodes are in nodeSet and
7542 // // complete setOfFaceNodeSet if they are
7543 // set <const SMDS_MeshNode*> faceNodeSet;
7544 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7545 // bool allInSet = true;
7546 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7547 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7548 // if ( nodeSet->find( n ) == nodeSet->end() )
7549 // allInSet = false;
7551 // faceNodeSet.insert( n );
7553 // if ( allInSet ) {
7554 // faceSet->insert( f );
7555 // setOfFaceNodeSet.insert( faceNodeSet );
7561 } // Create temporary faces, if there are volumes given
7564 if ( faceSet1.size() != faceSet2.size() ) {
7565 // delete temporary faces: they are in reverseElements of actual nodes
7566 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7567 while ( tmpFaceIt->more() )
7568 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7569 MESSAGE("Diff nb of faces");
7570 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7573 // ============================================================
7574 // 2. Find nodes to merge:
7575 // bind a node to remove to a node to put instead
7576 // ============================================================
7578 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
7579 if ( theFirstNode1 != theFirstNode2 )
7580 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
7581 if ( theSecondNode1 != theSecondNode2 )
7582 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
7584 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7585 set< long > linkIdSet; // links to process
7586 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
7588 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
7589 list< NLink > linkList[2];
7590 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7591 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7592 // loop on links in linkList; find faces by links and append links
7593 // of the found faces to linkList
7594 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7595 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7596 NLink link[] = { *linkIt[0], *linkIt[1] };
7597 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
7598 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
7601 // by links, find faces in the face sets,
7602 // and find indices of link nodes in the found faces;
7603 // in a face set, there is only one or no face sharing a link
7604 // ---------------------------------------------------------------
7606 const SMDS_MeshElement* face[] = { 0, 0 };
7607 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
7608 vector<const SMDS_MeshNode*> fnodes1(9);
7609 vector<const SMDS_MeshNode*> fnodes2(9);
7610 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
7611 vector<const SMDS_MeshNode*> notLinkNodes1(6);
7612 vector<const SMDS_MeshNode*> notLinkNodes2(6);
7613 int iLinkNode[2][2];
7614 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7615 const SMDS_MeshNode* n1 = link[iSide].first;
7616 const SMDS_MeshNode* n2 = link[iSide].second;
7617 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7618 set< const SMDS_MeshElement* > fMap;
7619 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
7620 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
7621 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7622 while ( fIt->more() ) { // loop on faces sharing a node
7623 const SMDS_MeshElement* f = fIt->next();
7624 if (faceSet->find( f ) != faceSet->end() && // f is in face set
7625 ! fMap.insert( f ).second ) // f encounters twice
7627 if ( face[ iSide ] ) {
7628 MESSAGE( "2 faces per link " );
7629 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
7633 faceSet->erase( f );
7634 // get face nodes and find ones of a link
7639 fnodes1.resize(f->NbNodes()+1);
7640 notLinkNodes1.resize(f->NbNodes()-2);
7643 fnodes2.resize(f->NbNodes()+1);
7644 notLinkNodes2.resize(f->NbNodes()-2);
7647 if(!f->IsQuadratic()) {
7648 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
7649 while ( nIt->more() ) {
7650 const SMDS_MeshNode* n =
7651 static_cast<const SMDS_MeshNode*>( nIt->next() );
7653 iLinkNode[ iSide ][ 0 ] = iNode;
7655 else if ( n == n2 ) {
7656 iLinkNode[ iSide ][ 1 ] = iNode;
7658 //else if ( notLinkNodes[ iSide ][ 0 ] )
7659 // notLinkNodes[ iSide ][ 1 ] = n;
7661 // notLinkNodes[ iSide ][ 0 ] = n;
7665 notLinkNodes1[nbl] = n;
7666 //notLinkNodes1.push_back(n);
7668 notLinkNodes2[nbl] = n;
7669 //notLinkNodes2.push_back(n);
7671 //faceNodes[ iSide ][ iNode++ ] = n;
7673 fnodes1[iNode++] = n;
7676 fnodes2[iNode++] = n;
7680 else { // f->IsQuadratic()
7681 const SMDS_QuadraticFaceOfNodes* F =
7682 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
7683 // use special nodes iterator
7684 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7685 while ( anIter->more() ) {
7686 const SMDS_MeshNode* n =
7687 static_cast<const SMDS_MeshNode*>( anIter->next() );
7689 iLinkNode[ iSide ][ 0 ] = iNode;
7691 else if ( n == n2 ) {
7692 iLinkNode[ iSide ][ 1 ] = iNode;
7697 notLinkNodes1[nbl] = n;
7700 notLinkNodes2[nbl] = n;
7704 fnodes1[iNode++] = n;
7707 fnodes2[iNode++] = n;
7711 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
7713 fnodes1[iNode] = fnodes1[0];
7716 fnodes2[iNode] = fnodes1[0];
7723 // check similarity of elements of the sides
7724 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7725 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7726 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7727 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7730 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7732 break; // do not return because it s necessary to remove tmp faces
7735 // set nodes to merge
7736 // -------------------
7738 if ( face[0] && face[1] ) {
7739 int nbNodes = face[0]->NbNodes();
7740 if ( nbNodes != face[1]->NbNodes() ) {
7741 MESSAGE("Diff nb of face nodes");
7742 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7743 break; // do not return because it s necessary to remove tmp faces
7745 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
7746 if ( nbNodes == 3 ) {
7747 //nReplaceMap.insert( TNodeNodeMap::value_type
7748 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7749 nReplaceMap.insert( TNodeNodeMap::value_type
7750 ( notLinkNodes1[0], notLinkNodes2[0] ));
7753 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7754 // analyse link orientation in faces
7755 int i1 = iLinkNode[ iSide ][ 0 ];
7756 int i2 = iLinkNode[ iSide ][ 1 ];
7757 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
7758 // if notLinkNodes are the first and the last ones, then
7759 // their order does not correspond to the link orientation
7760 if (( i1 == 1 && i2 == 2 ) ||
7761 ( i1 == 2 && i2 == 1 ))
7762 reverse[ iSide ] = !reverse[ iSide ];
7764 if ( reverse[0] == reverse[1] ) {
7765 //nReplaceMap.insert( TNodeNodeMap::value_type
7766 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7767 //nReplaceMap.insert( TNodeNodeMap::value_type
7768 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
7769 for(int nn=0; nn<nbNodes-2; nn++) {
7770 nReplaceMap.insert( TNodeNodeMap::value_type
7771 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
7775 //nReplaceMap.insert( TNodeNodeMap::value_type
7776 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
7777 //nReplaceMap.insert( TNodeNodeMap::value_type
7778 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
7779 for(int nn=0; nn<nbNodes-2; nn++) {
7780 nReplaceMap.insert( TNodeNodeMap::value_type
7781 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
7786 // add other links of the faces to linkList
7787 // -----------------------------------------
7789 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
7790 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7791 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
7792 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
7793 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
7794 if ( !iter_isnew.second ) { // already in a set: no need to process
7795 linkIdSet.erase( iter_isnew.first );
7797 else // new in set == encountered for the first time: add
7799 //const SMDS_MeshNode* n1 = nodes[ iNode ];
7800 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
7801 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
7802 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
7803 linkList[0].push_back ( NLink( n1, n2 ));
7804 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7808 } // loop on link lists
7810 if ( aResult == SEW_OK &&
7811 ( linkIt[0] != linkList[0].end() ||
7812 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
7813 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
7814 " " << (faceSetPtr[1]->empty()));
7815 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7818 // ====================================================================
7819 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7820 // ====================================================================
7822 // delete temporary faces: they are in reverseElements of actual nodes
7823 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7824 while ( tmpFaceIt->more() )
7825 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7827 if ( aResult != SEW_OK)
7830 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
7831 // loop on nodes replacement map
7832 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
7833 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
7834 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
7835 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
7836 nodeIDsToRemove.push_back( nToRemove->GetID() );
7837 // loop on elements sharing nToRemove
7838 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7839 while ( invElemIt->more() ) {
7840 const SMDS_MeshElement* e = invElemIt->next();
7841 // get a new suite of nodes: make replacement
7842 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
7843 vector< const SMDS_MeshNode*> nodes( nbNodes );
7844 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7845 while ( nIt->more() ) {
7846 const SMDS_MeshNode* n =
7847 static_cast<const SMDS_MeshNode*>( nIt->next() );
7848 nnIt = nReplaceMap.find( n );
7849 if ( nnIt != nReplaceMap.end() ) {
7855 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
7856 // elemIDsToRemove.push_back( e->GetID() );
7859 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
7863 Remove( nodeIDsToRemove, true );
7868 //================================================================================
7870 * \brief Find corresponding nodes in two sets of faces
7871 * \param theSide1 - first face set
7872 * \param theSide2 - second first face
7873 * \param theFirstNode1 - a boundary node of set 1
7874 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
7875 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
7876 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
7877 * \param nReplaceMap - output map of corresponding nodes
7878 * \retval bool - is a success or not
7880 //================================================================================
7883 //#define DEBUG_MATCHING_NODES
7886 SMESH_MeshEditor::Sew_Error
7887 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
7888 set<const SMDS_MeshElement*>& theSide2,
7889 const SMDS_MeshNode* theFirstNode1,
7890 const SMDS_MeshNode* theFirstNode2,
7891 const SMDS_MeshNode* theSecondNode1,
7892 const SMDS_MeshNode* theSecondNode2,
7893 TNodeNodeMap & nReplaceMap)
7895 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
7897 nReplaceMap.clear();
7898 if ( theFirstNode1 != theFirstNode2 )
7899 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
7900 if ( theSecondNode1 != theSecondNode2 )
7901 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
7903 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
7904 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
7906 list< NLink > linkList[2];
7907 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7908 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7910 // loop on links in linkList; find faces by links and append links
7911 // of the found faces to linkList
7912 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7913 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7914 NLink link[] = { *linkIt[0], *linkIt[1] };
7915 if ( linkSet.find( link[0] ) == linkSet.end() )
7918 // by links, find faces in the face sets,
7919 // and find indices of link nodes in the found faces;
7920 // in a face set, there is only one or no face sharing a link
7921 // ---------------------------------------------------------------
7923 const SMDS_MeshElement* face[] = { 0, 0 };
7924 list<const SMDS_MeshNode*> notLinkNodes[2];
7925 //bool reverse[] = { false, false }; // order of notLinkNodes
7927 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
7929 const SMDS_MeshNode* n1 = link[iSide].first;
7930 const SMDS_MeshNode* n2 = link[iSide].second;
7931 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7932 set< const SMDS_MeshElement* > facesOfNode1;
7933 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
7935 // during a loop of the first node, we find all faces around n1,
7936 // during a loop of the second node, we find one face sharing both n1 and n2
7937 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
7938 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7939 while ( fIt->more() ) { // loop on faces sharing a node
7940 const SMDS_MeshElement* f = fIt->next();
7941 if (faceSet->find( f ) != faceSet->end() && // f is in face set
7942 ! facesOfNode1.insert( f ).second ) // f encounters twice
7944 if ( face[ iSide ] ) {
7945 MESSAGE( "2 faces per link " );
7946 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7949 faceSet->erase( f );
7951 // get not link nodes
7952 int nbN = f->NbNodes();
7953 if ( f->IsQuadratic() )
7955 nbNodes[ iSide ] = nbN;
7956 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
7957 int i1 = f->GetNodeIndex( n1 );
7958 int i2 = f->GetNodeIndex( n2 );
7959 int iEnd = nbN, iBeg = -1, iDelta = 1;
7960 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
7962 std::swap( iEnd, iBeg ); iDelta = -1;
7967 if ( i == iEnd ) i = iBeg + iDelta;
7968 if ( i == i1 ) break;
7969 nodes.push_back ( f->GetNode( i ) );
7975 // check similarity of elements of the sides
7976 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7977 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7978 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7979 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7982 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7986 // set nodes to merge
7987 // -------------------
7989 if ( face[0] && face[1] ) {
7990 if ( nbNodes[0] != nbNodes[1] ) {
7991 MESSAGE("Diff nb of face nodes");
7992 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7994 #ifdef DEBUG_MATCHING_NODES
7995 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
7996 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
7997 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
7999 int nbN = nbNodes[0];
8001 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8002 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8003 for ( int i = 0 ; i < nbN - 2; ++i ) {
8004 #ifdef DEBUG_MATCHING_NODES
8005 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8007 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8011 // add other links of the face 1 to linkList
8012 // -----------------------------------------
8014 const SMDS_MeshElement* f0 = face[0];
8015 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8016 for ( int i = 0; i < nbN; i++ )
8018 const SMDS_MeshNode* n2 = f0->GetNode( i );
8019 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8020 linkSet.insert( SMESH_TLink( n1, n2 ));
8021 if ( !iter_isnew.second ) { // already in a set: no need to process
8022 linkSet.erase( iter_isnew.first );
8024 else // new in set == encountered for the first time: add
8026 #ifdef DEBUG_MATCHING_NODES
8027 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8028 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8030 linkList[0].push_back ( NLink( n1, n2 ));
8031 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8036 } // loop on link lists
8042 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8043 \param theNodes - identifiers of nodes to be doubled
8044 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
8045 nodes. If list of element identifiers is empty then nodes are doubled but
8046 they not assigned to elements
8047 \return TRUE if operation has been completed successfully, FALSE otherwise
8049 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
8050 const std::list< int >& theListOfModifiedElems )
8052 myLastCreatedElems.Clear();
8053 myLastCreatedNodes.Clear();
8055 if ( theListOfNodes.size() == 0 )
8058 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8062 // iterate through nodes and duplicate them
8064 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8066 std::list< int >::const_iterator aNodeIter;
8067 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8069 int aCurr = *aNodeIter;
8070 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8076 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8079 anOldNodeToNewNode[ aNode ] = aNewNode;
8080 myLastCreatedNodes.Append( aNewNode );
8084 // Create map of new nodes for modified elements
8086 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8088 std::list< int >::const_iterator anElemIter;
8089 for ( anElemIter = theListOfModifiedElems.begin();
8090 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8092 int aCurr = *anElemIter;
8093 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8097 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8099 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8101 while ( anIter->more() )
8103 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8104 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8106 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8107 aNodeArr[ ind++ ] = aNewNode;
8110 aNodeArr[ ind++ ] = aCurrNode;
8112 anElemToNodes[ anElem ] = aNodeArr;
8115 // Change nodes of elements
8117 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8118 anElemToNodesIter = anElemToNodes.begin();
8119 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8121 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8122 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8124 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );