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 = MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
3861 else if( aS.ShapeType() == TopAbs_WIRE ) {
3862 list< SMESH_subMesh* > LSM;
3863 TopTools_SequenceOfShape Edges;
3864 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
3865 while(itSM->more()) {
3866 SMESH_subMesh* SM = itSM->next();
3868 const TopoDS_Shape& aS = SM->GetSubShape();
3871 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
3872 int startNid = theN1->GetID();
3873 TColStd_MapOfInteger UsedNums;
3874 int NbEdges = Edges.Length();
3876 for(; i<=NbEdges; i++) {
3878 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
3879 for(; itLSM!=LSM.end(); itLSM++) {
3881 if(UsedNums.Contains(k)) continue;
3882 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
3883 SMESH_subMesh* locTrack = *itLSM;
3884 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
3885 TopExp::Vertices( aTrackEdge, aV1, aV2 );
3886 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
3887 const SMDS_MeshNode* aN1 = aItN->next();
3888 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
3889 const SMDS_MeshNode* aN2 = aItN->next();
3890 // starting node must be aN1 or aN2
3891 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
3892 // 2. Collect parameters on the track edge
3894 aItN = locMeshDS->GetNodes();
3895 while ( aItN->more() ) {
3896 const SMDS_MeshNode* pNode = aItN->next();
3897 const SMDS_EdgePosition* pEPos =
3898 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
3899 double aT = pEPos->GetUParameter();
3900 aPrms.push_back( aT );
3902 list<SMESH_MeshEditor_PathPoint> LPP;
3903 Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge,
3904 (aN1->GetID()==startNid), LPP);
3905 LLPPs.push_back(LPP);
3907 // update startN for search following egde
3908 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
3909 else startNid = aN1->GetID();
3913 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
3914 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
3915 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
3916 for(; itPP!=firstList.end(); itPP++) {
3917 fullList.push_back( *itPP );
3919 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
3920 fullList.pop_back();
3922 for(; itLLPP!=LLPPs.end(); itLLPP++) {
3923 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
3924 itPP = currList.begin();
3925 SMESH_MeshEditor_PathPoint PP2 = currList.front();
3926 gp_Dir D1 = PP1.Tangent();
3927 gp_Dir D2 = PP2.Tangent();
3928 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
3929 (D1.Z()+D2.Z())/2 ) );
3930 PP1.SetTangent(Dnew);
3931 fullList.push_back(PP1);
3933 for(; itPP!=firstList.end(); itPP++) {
3934 fullList.push_back( *itPP );
3936 PP1 = fullList.back();
3937 fullList.pop_back();
3939 // if wire not closed
3940 fullList.push_back(PP1);
3944 return EXTR_BAD_PATH_SHAPE;
3947 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
3948 theHasRefPoint, theRefPoint, theMakeGroups);
3952 //=======================================================================
3953 //function : ExtrusionAlongTrack
3955 //=======================================================================
3956 SMESH_MeshEditor::Extrusion_Error
3957 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3958 SMESH_Mesh* theTrack,
3959 const SMDS_MeshNode* theN1,
3960 const bool theHasAngles,
3961 list<double>& theAngles,
3962 const bool theLinearVariation,
3963 const bool theHasRefPoint,
3964 const gp_Pnt& theRefPoint,
3965 const bool theMakeGroups)
3967 myLastCreatedElems.Clear();
3968 myLastCreatedNodes.Clear();
3971 std::list<double> aPrms;
3972 TIDSortedElemSet::iterator itElem;
3975 TopoDS_Edge aTrackEdge;
3976 TopoDS_Vertex aV1, aV2;
3978 SMDS_ElemIteratorPtr aItE;
3979 SMDS_NodeIteratorPtr aItN;
3980 SMDSAbs_ElementType aTypeE;
3982 TNodeOfNodeListMap mapNewNodes;
3985 aNbE = theElements.size();
3988 return EXTR_NO_ELEMENTS;
3990 // 1.1 Track Pattern
3993 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
3995 aItE = pMeshDS->elementsIterator();
3996 while ( aItE->more() ) {
3997 const SMDS_MeshElement* pE = aItE->next();
3998 aTypeE = pE->GetType();
3999 // Pattern must contain links only
4000 if ( aTypeE != SMDSAbs_Edge )
4001 return EXTR_PATH_NOT_EDGE;
4004 list<SMESH_MeshEditor_PathPoint> fullList;
4006 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4007 // Sub shape for the Pattern must be an Edge or Wire
4008 if( aS.ShapeType() == TopAbs_EDGE ) {
4009 aTrackEdge = TopoDS::Edge( aS );
4010 // the Edge must not be degenerated
4011 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4012 return EXTR_BAD_PATH_SHAPE;
4013 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4014 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4015 const SMDS_MeshNode* aN1 = aItN->next();
4016 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4017 const SMDS_MeshNode* aN2 = aItN->next();
4018 // starting node must be aN1 or aN2
4019 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4020 return EXTR_BAD_STARTING_NODE;
4021 aItN = pMeshDS->nodesIterator();
4022 while ( aItN->more() ) {
4023 const SMDS_MeshNode* pNode = aItN->next();
4024 if( pNode==aN1 || pNode==aN2 ) continue;
4025 const SMDS_EdgePosition* pEPos =
4026 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4027 double aT = pEPos->GetUParameter();
4028 aPrms.push_back( aT );
4030 Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4032 else if( aS.ShapeType() == TopAbs_WIRE ) {
4033 list< SMESH_subMesh* > LSM;
4034 TopTools_SequenceOfShape Edges;
4035 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4036 for(; eExp.More(); eExp.Next()) {
4037 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4038 if( BRep_Tool::Degenerated(E) ) continue;
4039 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4045 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4046 int startNid = theN1->GetID();
4047 TColStd_MapOfInteger UsedNums;
4048 int NbEdges = Edges.Length();
4050 for(; i<=NbEdges; i++) {
4052 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4053 for(; itLSM!=LSM.end(); itLSM++) {
4055 if(UsedNums.Contains(k)) continue;
4056 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4057 SMESH_subMesh* locTrack = *itLSM;
4058 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4059 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4060 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4061 const SMDS_MeshNode* aN1 = aItN->next();
4062 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4063 const SMDS_MeshNode* aN2 = aItN->next();
4064 // starting node must be aN1 or aN2
4065 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4066 // 2. Collect parameters on the track edge
4068 aItN = locMeshDS->GetNodes();
4069 while ( aItN->more() ) {
4070 const SMDS_MeshNode* pNode = aItN->next();
4071 const SMDS_EdgePosition* pEPos =
4072 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4073 double aT = pEPos->GetUParameter();
4074 aPrms.push_back( aT );
4076 list<SMESH_MeshEditor_PathPoint> LPP;
4077 Extrusion_Error err = MakeEdgePathPoints(aPrms, aTrackEdge,
4078 (aN1->GetID()==startNid), LPP);
4079 LLPPs.push_back(LPP);
4081 // update startN for search following egde
4082 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4083 else startNid = aN1->GetID();
4087 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4088 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4089 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4090 for(; itPP!=firstList.end(); itPP++) {
4091 fullList.push_back( *itPP );
4093 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4094 fullList.pop_back();
4096 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4097 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4098 itPP = currList.begin();
4099 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4100 gp_Pnt P1 = PP1.Pnt();
4101 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4102 gp_Pnt P2 = PP2.Pnt();
4103 gp_Dir D1 = PP1.Tangent();
4104 gp_Dir D2 = PP2.Tangent();
4105 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4106 (D1.Z()+D2.Z())/2 ) );
4107 PP1.SetTangent(Dnew);
4108 fullList.push_back(PP1);
4110 for(; itPP!=currList.end(); itPP++) {
4111 fullList.push_back( *itPP );
4113 PP1 = fullList.back();
4114 fullList.pop_back();
4116 // if wire not closed
4117 fullList.push_back(PP1);
4121 return EXTR_BAD_PATH_SHAPE;
4124 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4125 theHasRefPoint, theRefPoint, theMakeGroups);
4129 //=======================================================================
4130 //function : MakeEdgePathPoints
4131 //purpose : auxilary for ExtrusionAlongTrack
4132 //=======================================================================
4133 SMESH_MeshEditor::Extrusion_Error
4134 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4135 const TopoDS_Edge& aTrackEdge,
4137 list<SMESH_MeshEditor_PathPoint>& LPP)
4139 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4141 aTolVec2=aTolVec*aTolVec;
4143 TopoDS_Vertex aV1, aV2;
4144 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4145 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4146 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4147 // 2. Collect parameters on the track edge
4148 aPrms.push_front( aT1 );
4149 aPrms.push_back( aT2 );
4152 if( FirstIsStart ) {
4163 SMESH_MeshEditor_PathPoint aPP;
4164 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4165 std::list<double>::iterator aItD = aPrms.begin();
4166 for(; aItD != aPrms.end(); ++aItD) {
4170 aC3D->D1( aT, aP3D, aVec );
4171 aL2 = aVec.SquareMagnitude();
4172 if ( aL2 < aTolVec2 )
4173 return EXTR_CANT_GET_TANGENT;
4174 gp_Dir aTgt( aVec );
4176 aPP.SetTangent( aTgt );
4177 aPP.SetParameter( aT );
4183 //=======================================================================
4184 //function : MakeExtrElements
4185 //purpose : auxilary for ExtrusionAlongTrack
4186 //=======================================================================
4187 SMESH_MeshEditor::Extrusion_Error
4188 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4189 list<SMESH_MeshEditor_PathPoint>& fullList,
4190 const bool theHasAngles,
4191 list<double>& theAngles,
4192 const bool theLinearVariation,
4193 const bool theHasRefPoint,
4194 const gp_Pnt& theRefPoint,
4195 const bool theMakeGroups)
4197 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4198 int aNbTP = fullList.size();
4199 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4201 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4202 LinearAngleVariation(aNbTP-1, theAngles);
4204 vector<double> aAngles( aNbTP );
4206 for(; j<aNbTP; ++j) {
4209 if ( theHasAngles ) {
4211 std::list<double>::iterator aItD = theAngles.begin();
4212 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4214 aAngles[j] = anAngle;
4217 // fill vector of path points with angles
4218 //aPPs.resize(fullList.size());
4220 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4221 for(; itPP!=fullList.end(); itPP++) {
4223 SMESH_MeshEditor_PathPoint PP = *itPP;
4224 PP.SetAngle(aAngles[j]);
4228 TNodeOfNodeListMap mapNewNodes;
4229 TElemOfVecOfNnlmiMap mapElemNewNodes;
4230 TElemOfElemListMap newElemsMap;
4231 TIDSortedElemSet::iterator itElem;
4234 SMDSAbs_ElementType aTypeE;
4235 // source elements for each generated one
4236 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4238 // 3. Center of rotation aV0
4239 gp_Pnt aV0 = theRefPoint;
4241 if ( !theHasRefPoint ) {
4243 aGC.SetCoord( 0.,0.,0. );
4245 itElem = theElements.begin();
4246 for ( ; itElem != theElements.end(); itElem++ ) {
4247 const SMDS_MeshElement* elem = *itElem;
4249 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4250 while ( itN->more() ) {
4251 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4256 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4257 list<const SMDS_MeshNode*> aLNx;
4258 mapNewNodes[node] = aLNx;
4260 gp_XYZ aXYZ( aX, aY, aZ );
4268 } // if (!theHasRefPoint) {
4269 mapNewNodes.clear();
4271 // 4. Processing the elements
4272 SMESHDS_Mesh* aMesh = GetMeshDS();
4274 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4275 // check element type
4276 const SMDS_MeshElement* elem = *itElem;
4277 aTypeE = elem->GetType();
4278 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4281 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4282 newNodesItVec.reserve( elem->NbNodes() );
4284 // loop on elem nodes
4286 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4287 while ( itN->more() )
4290 // check if a node has been already processed
4291 const SMDS_MeshNode* node =
4292 static_cast<const SMDS_MeshNode*>( itN->next() );
4293 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4294 if ( nIt == mapNewNodes.end() ) {
4295 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4296 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4299 aX = node->X(); aY = node->Y(); aZ = node->Z();
4301 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4302 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4303 gp_Ax1 anAx1, anAxT1T0;
4304 gp_Dir aDT1x, aDT0x, aDT1T0;
4309 aPN0.SetCoord(aX, aY, aZ);
4311 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4313 aDT0x= aPP0.Tangent();
4314 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4316 for ( j = 1; j < aNbTP; ++j ) {
4317 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4319 aDT1x = aPP1.Tangent();
4320 aAngle1x = aPP1.Angle();
4322 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4324 gp_Vec aV01x( aP0x, aP1x );
4325 aTrsf.SetTranslation( aV01x );
4328 aV1x = aV0x.Transformed( aTrsf );
4329 aPN1 = aPN0.Transformed( aTrsf );
4331 // rotation 1 [ T1,T0 ]
4332 aAngleT1T0=-aDT1x.Angle( aDT0x );
4333 if (fabs(aAngleT1T0) > aTolAng) {
4335 anAxT1T0.SetLocation( aV1x );
4336 anAxT1T0.SetDirection( aDT1T0 );
4337 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4339 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4343 if ( theHasAngles ) {
4344 anAx1.SetLocation( aV1x );
4345 anAx1.SetDirection( aDT1x );
4346 aTrsfRot.SetRotation( anAx1, aAngle1x );
4348 aPN1 = aPN1.Transformed( aTrsfRot );
4352 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4353 // create additional node
4354 double x = ( aPN1.X() + aPN0.X() )/2.;
4355 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4356 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4357 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4358 myLastCreatedNodes.Append(newNode);
4359 srcNodes.Append( node );
4360 listNewNodes.push_back( newNode );
4365 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4366 myLastCreatedNodes.Append(newNode);
4367 srcNodes.Append( node );
4368 listNewNodes.push_back( newNode );
4378 // if current elem is quadratic and current node is not medium
4379 // we have to check - may be it is needed to insert additional nodes
4380 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4381 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4382 if(listNewNodes.size()==aNbTP-1) {
4383 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4384 gp_XYZ P(node->X(), node->Y(), node->Z());
4385 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4387 for(i=0; i<aNbTP-1; i++) {
4388 const SMDS_MeshNode* N = *it;
4389 double x = ( N->X() + P.X() )/2.;
4390 double y = ( N->Y() + P.Y() )/2.;
4391 double z = ( N->Z() + P.Z() )/2.;
4392 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4393 srcNodes.Append( node );
4394 myLastCreatedNodes.Append(newN);
4397 P = gp_XYZ(N->X(),N->Y(),N->Z());
4399 listNewNodes.clear();
4400 for(i=0; i<2*(aNbTP-1); i++) {
4401 listNewNodes.push_back(aNodes[i]);
4407 newNodesItVec.push_back( nIt );
4409 // make new elements
4410 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4411 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4412 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4415 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4417 if ( theMakeGroups )
4418 generateGroups( srcNodes, srcElems, "extruded");
4424 //=======================================================================
4425 //function : LinearAngleVariation
4426 //purpose : auxilary for ExtrusionAlongTrack
4427 //=======================================================================
4428 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4429 list<double>& Angles)
4431 int nbAngles = Angles.size();
4432 if( nbSteps > nbAngles ) {
4433 vector<double> theAngles(nbAngles);
4434 list<double>::iterator it = Angles.begin();
4436 for(; it!=Angles.end(); it++) {
4438 theAngles[i] = (*it);
4441 double rAn2St = double( nbAngles ) / double( nbSteps );
4442 double angPrev = 0, angle;
4443 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4444 double angCur = rAn2St * ( iSt+1 );
4445 double angCurFloor = floor( angCur );
4446 double angPrevFloor = floor( angPrev );
4447 if ( angPrevFloor == angCurFloor )
4448 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4450 int iP = int( angPrevFloor );
4451 double angPrevCeil = ceil(angPrev);
4452 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4454 int iC = int( angCurFloor );
4455 if ( iC < nbAngles )
4456 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4458 iP = int( angPrevCeil );
4460 angle += theAngles[ iC ];
4462 res.push_back(angle);
4467 for(; it!=res.end(); it++)
4468 Angles.push_back( *it );
4473 //=======================================================================
4474 //function : Transform
4476 //=======================================================================
4478 SMESH_MeshEditor::PGroupIDs
4479 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4480 const gp_Trsf& theTrsf,
4482 const bool theMakeGroups,
4483 SMESH_Mesh* theTargetMesh)
4485 myLastCreatedElems.Clear();
4486 myLastCreatedNodes.Clear();
4488 bool needReverse = false;
4489 string groupPostfix;
4490 switch ( theTrsf.Form() ) {
4495 groupPostfix = "mirrored";
4498 groupPostfix = "rotated";
4500 case gp_Translation:
4501 groupPostfix = "translated";
4504 groupPostfix = "scaled";
4507 needReverse = false;
4508 groupPostfix = "transformed";
4511 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4512 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4513 SMESHDS_Mesh* aMesh = GetMeshDS();
4516 // map old node to new one
4517 TNodeNodeMap nodeMap;
4519 // elements sharing moved nodes; those of them which have all
4520 // nodes mirrored but are not in theElems are to be reversed
4521 TIDSortedElemSet inverseElemSet;
4523 // source elements for each generated one
4524 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4527 TIDSortedElemSet::iterator itElem;
4528 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4529 const SMDS_MeshElement* elem = *itElem;
4533 // loop on elem nodes
4534 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4535 while ( itN->more() ) {
4537 // check if a node has been already transformed
4538 const SMDS_MeshNode* node = cast2Node( itN->next() );
4539 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4540 nodeMap.insert( make_pair ( node, node ));
4541 if ( !n2n_isnew.second )
4545 coord[0] = node->X();
4546 coord[1] = node->Y();
4547 coord[2] = node->Z();
4548 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4549 if ( theTargetMesh ) {
4550 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4551 n2n_isnew.first->second = newNode;
4552 myLastCreatedNodes.Append(newNode);
4553 srcNodes.Append( node );
4555 else if ( theCopy ) {
4556 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4557 n2n_isnew.first->second = newNode;
4558 myLastCreatedNodes.Append(newNode);
4559 srcNodes.Append( node );
4562 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4563 // node position on shape becomes invalid
4564 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4565 ( SMDS_SpacePosition::originSpacePosition() );
4568 // keep inverse elements
4569 if ( !theCopy && !theTargetMesh && needReverse ) {
4570 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4571 while ( invElemIt->more() ) {
4572 const SMDS_MeshElement* iel = invElemIt->next();
4573 inverseElemSet.insert( iel );
4579 // either create new elements or reverse mirrored ones
4580 if ( !theCopy && !needReverse && !theTargetMesh )
4583 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4584 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4585 theElems.insert( *invElemIt );
4587 // replicate or reverse elements
4590 REV_TETRA = 0, // = nbNodes - 4
4591 REV_PYRAMID = 1, // = nbNodes - 4
4592 REV_PENTA = 2, // = nbNodes - 4
4594 REV_HEXA = 4, // = nbNodes - 4
4598 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4599 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4600 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4601 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4602 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4603 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4606 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4608 const SMDS_MeshElement* elem = *itElem;
4609 if ( !elem || elem->GetType() == SMDSAbs_Node )
4612 int nbNodes = elem->NbNodes();
4613 int elemType = elem->GetType();
4615 if (elem->IsPoly()) {
4616 // Polygon or Polyhedral Volume
4617 switch ( elemType ) {
4620 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4622 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4623 while (itN->more()) {
4624 const SMDS_MeshNode* node =
4625 static_cast<const SMDS_MeshNode*>(itN->next());
4626 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4627 if (nodeMapIt == nodeMap.end())
4628 break; // not all nodes transformed
4630 // reverse mirrored faces and volumes
4631 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4633 poly_nodes[iNode] = (*nodeMapIt).second;
4637 if ( iNode != nbNodes )
4638 continue; // not all nodes transformed
4640 if ( theTargetMesh ) {
4641 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4642 srcElems.Append( elem );
4644 else if ( theCopy ) {
4645 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4646 srcElems.Append( elem );
4649 aMesh->ChangePolygonNodes(elem, poly_nodes);
4653 case SMDSAbs_Volume:
4655 // ATTENTION: Reversing is not yet done!!!
4656 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4657 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4659 MESSAGE("Warning: bad volumic element");
4663 vector<const SMDS_MeshNode*> poly_nodes;
4664 vector<int> quantities;
4666 bool allTransformed = true;
4667 int nbFaces = aPolyedre->NbFaces();
4668 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4669 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4670 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4671 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4672 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4673 if (nodeMapIt == nodeMap.end()) {
4674 allTransformed = false; // not all nodes transformed
4676 poly_nodes.push_back((*nodeMapIt).second);
4679 quantities.push_back(nbFaceNodes);
4681 if ( !allTransformed )
4682 continue; // not all nodes transformed
4684 if ( theTargetMesh ) {
4685 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4686 srcElems.Append( elem );
4688 else if ( theCopy ) {
4689 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4690 srcElems.Append( elem );
4693 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4703 int* i = index[ FORWARD ];
4704 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4705 if ( elemType == SMDSAbs_Face )
4706 i = index[ REV_FACE ];
4708 i = index[ nbNodes - 4 ];
4710 if(elem->IsQuadratic()) {
4711 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4714 if(nbNodes==3) { // quadratic edge
4715 static int anIds[] = {1,0,2};
4718 else if(nbNodes==6) { // quadratic triangle
4719 static int anIds[] = {0,2,1,5,4,3};
4722 else if(nbNodes==8) { // quadratic quadrangle
4723 static int anIds[] = {0,3,2,1,7,6,5,4};
4726 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4727 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4730 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4731 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4734 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4735 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4738 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4739 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4745 // find transformed nodes
4746 vector<const SMDS_MeshNode*> nodes(nbNodes);
4748 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4749 while ( itN->more() ) {
4750 const SMDS_MeshNode* node =
4751 static_cast<const SMDS_MeshNode*>( itN->next() );
4752 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4753 if ( nodeMapIt == nodeMap.end() )
4754 break; // not all nodes transformed
4755 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4757 if ( iNode != nbNodes )
4758 continue; // not all nodes transformed
4760 if ( theTargetMesh ) {
4761 if ( SMDS_MeshElement* copy =
4762 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4763 myLastCreatedElems.Append( copy );
4764 srcElems.Append( elem );
4767 else if ( theCopy ) {
4768 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4769 myLastCreatedElems.Append( copy );
4770 srcElems.Append( elem );
4774 // reverse element as it was reversed by transformation
4776 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4780 PGroupIDs newGroupIDs;
4782 if ( theMakeGroups && theCopy ||
4783 theMakeGroups && theTargetMesh )
4784 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4789 //=======================================================================
4791 * \brief Create groups of elements made during transformation
4792 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4793 * \param elemGens - elements making corresponding myLastCreatedElems
4794 * \param postfix - to append to names of new groups
4796 //=======================================================================
4798 SMESH_MeshEditor::PGroupIDs
4799 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4800 const SMESH_SequenceOfElemPtr& elemGens,
4801 const std::string& postfix,
4802 SMESH_Mesh* targetMesh)
4804 PGroupIDs newGroupIDs( new list<int> );
4805 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4807 // Sort existing groups by types and collect their names
4809 // to store an old group and a generated new one
4810 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4811 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4813 set< string > groupNames;
4815 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4816 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4817 while ( groupIt->more() ) {
4818 SMESH_Group * group = groupIt->next();
4819 if ( !group ) continue;
4820 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4821 if ( !groupDS || groupDS->IsEmpty() ) continue;
4822 groupNames.insert( group->GetName() );
4823 groupDS->SetStoreName( group->GetName() );
4824 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4829 // loop on nodes and elements
4830 for ( int isNodes = 0; isNodes < 2; ++isNodes )
4832 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
4833 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4834 if ( gens.Length() != elems.Length() )
4835 throw SALOME_Exception(LOCALIZED("invalid args"));
4837 // loop on created elements
4838 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4840 const SMDS_MeshElement* sourceElem = gens( iElem );
4841 if ( !sourceElem ) {
4842 MESSAGE("generateGroups(): NULL source element");
4845 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
4846 if ( groupsOldNew.empty() ) {
4847 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4848 ++iElem; // skip all elements made by sourceElem
4851 // collect all elements made by sourceElem
4852 list< const SMDS_MeshElement* > resultElems;
4853 if ( const SMDS_MeshElement* resElem = elems( iElem ))
4854 if ( resElem != sourceElem )
4855 resultElems.push_back( resElem );
4856 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4857 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
4858 if ( resElem != sourceElem )
4859 resultElems.push_back( resElem );
4860 // do not generate element groups from node ones
4861 if ( sourceElem->GetType() == SMDSAbs_Node &&
4862 elems( iElem )->GetType() != SMDSAbs_Node )
4865 // add resultElems to groups made by ones the sourceElem belongs to
4866 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
4867 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
4869 SMESHDS_GroupBase* oldGroup = gOldNew->first;
4870 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
4872 SMDS_MeshGroup* & newGroup = gOldNew->second;
4873 if ( !newGroup )// create a new group
4876 string name = oldGroup->GetStoreName();
4877 if ( !targetMesh ) {
4881 while ( !groupNames.insert( name ).second ) // name exists
4887 TCollection_AsciiString nbStr(nb+1);
4888 name.resize( name.rfind('_')+1 );
4889 name += nbStr.ToCString();
4896 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
4898 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
4899 newGroup = & groupDS->SMDSGroup();
4900 newGroupIDs->push_back( id );
4903 // fill in a new group
4904 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
4905 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
4906 newGroup->Add( *resElemIt );
4909 } // loop on created elements
4910 }// loop on nodes and elements
4915 //=======================================================================
4916 //function : FindCoincidentNodes
4917 //purpose : Return list of group of nodes close to each other within theTolerance
4918 // Search among theNodes or in the whole mesh if theNodes is empty using
4919 // an Octree algorithm
4920 //=======================================================================
4922 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
4923 const double theTolerance,
4924 TListOfListOfNodes & theGroupsOfNodes)
4926 myLastCreatedElems.Clear();
4927 myLastCreatedNodes.Clear();
4929 set<const SMDS_MeshNode*> nodes;
4930 if ( theNodes.empty() )
4931 { // get all nodes in the mesh
4932 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
4933 while ( nIt->more() )
4934 nodes.insert( nodes.end(),nIt->next());
4938 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
4942 //=======================================================================
4944 * \brief Implementation of search for the node closest to point
4946 //=======================================================================
4948 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
4951 * \brief Constructor
4953 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
4955 set<const SMDS_MeshNode*> nodes;
4957 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
4958 while ( nIt->more() )
4959 nodes.insert( nodes.end(), nIt->next() );
4961 myOctreeNode = new SMESH_OctreeNode(nodes) ;
4964 * \brief Do it's job
4966 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
4968 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
4969 list<const SMDS_MeshNode*> nodes;
4970 const double precision = 1e-6;
4971 myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
4973 double minSqDist = DBL_MAX;
4975 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
4977 // sort leafs by their distance from thePnt
4978 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
4979 TDistTreeMap treeMap;
4980 list< SMESH_OctreeNode* > treeList;
4981 list< SMESH_OctreeNode* >::iterator trIt;
4982 treeList.push_back( myOctreeNode );
4983 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
4985 SMESH_OctreeNode* tree = *trIt;
4986 if ( !tree->isLeaf() ) { // put children to the queue
4987 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
4988 while ( cIt->more() )
4989 treeList.push_back( cIt->next() );
4991 else if ( tree->NbNodes() ) { // put tree to treeMap
4992 tree->getBox( box );
4993 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
4994 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
4995 if ( !it_in.second ) // not unique distance to box center
4996 treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
4999 // find distance after which there is no sense to check tree's
5000 double sqLimit = DBL_MAX;
5001 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5002 if ( treeMap.size() > 5 ) {
5003 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5004 closestTree->getBox( box );
5005 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5006 sqLimit = limit * limit;
5008 // get all nodes from trees
5009 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5010 if ( sqDist_tree->first > sqLimit )
5012 SMESH_OctreeNode* tree = sqDist_tree->second;
5013 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5016 // find closest among nodes
5017 minSqDist = DBL_MAX;
5018 const SMDS_MeshNode* closestNode = 0;
5019 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5020 for ( ; nIt != nodes.end(); ++nIt ) {
5021 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5022 if ( minSqDist > sqDist ) {
5032 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5034 SMESH_OctreeNode* myOctreeNode;
5037 //=======================================================================
5039 * \brief Return SMESH_NodeSearcher
5041 //=======================================================================
5043 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5045 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5048 //=======================================================================
5049 //function : SimplifyFace
5051 //=======================================================================
5052 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5053 vector<const SMDS_MeshNode *>& poly_nodes,
5054 vector<int>& quantities) const
5056 int nbNodes = faceNodes.size();
5061 set<const SMDS_MeshNode*> nodeSet;
5063 // get simple seq of nodes
5064 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5065 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5066 int iSimple = 0, nbUnique = 0;
5068 simpleNodes[iSimple++] = faceNodes[0];
5070 for (int iCur = 1; iCur < nbNodes; iCur++) {
5071 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5072 simpleNodes[iSimple++] = faceNodes[iCur];
5073 if (nodeSet.insert( faceNodes[iCur] ).second)
5077 int nbSimple = iSimple;
5078 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5088 bool foundLoop = (nbSimple > nbUnique);
5091 set<const SMDS_MeshNode*> loopSet;
5092 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5093 const SMDS_MeshNode* n = simpleNodes[iSimple];
5094 if (!loopSet.insert( n ).second) {
5098 int iC = 0, curLast = iSimple;
5099 for (; iC < curLast; iC++) {
5100 if (simpleNodes[iC] == n) break;
5102 int loopLen = curLast - iC;
5104 // create sub-element
5106 quantities.push_back(loopLen);
5107 for (; iC < curLast; iC++) {
5108 poly_nodes.push_back(simpleNodes[iC]);
5111 // shift the rest nodes (place from the first loop position)
5112 for (iC = curLast + 1; iC < nbSimple; iC++) {
5113 simpleNodes[iC - loopLen] = simpleNodes[iC];
5115 nbSimple -= loopLen;
5118 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5119 } // while (foundLoop)
5123 quantities.push_back(iSimple);
5124 for (int i = 0; i < iSimple; i++)
5125 poly_nodes.push_back(simpleNodes[i]);
5131 //=======================================================================
5132 //function : MergeNodes
5133 //purpose : In each group, the cdr of nodes are substituted by the first one
5135 //=======================================================================
5137 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5139 myLastCreatedElems.Clear();
5140 myLastCreatedNodes.Clear();
5142 SMESHDS_Mesh* aMesh = GetMeshDS();
5144 TNodeNodeMap nodeNodeMap; // node to replace - new node
5145 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5146 list< int > rmElemIds, rmNodeIds;
5148 // Fill nodeNodeMap and elems
5150 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5151 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5152 list<const SMDS_MeshNode*>& nodes = *grIt;
5153 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5154 const SMDS_MeshNode* nToKeep = *nIt;
5155 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5156 const SMDS_MeshNode* nToRemove = *nIt;
5157 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5158 if ( nToRemove != nToKeep ) {
5159 rmNodeIds.push_back( nToRemove->GetID() );
5160 AddToSameGroups( nToKeep, nToRemove, aMesh );
5163 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5164 while ( invElemIt->more() ) {
5165 const SMDS_MeshElement* elem = invElemIt->next();
5170 // Change element nodes or remove an element
5172 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5173 for ( ; eIt != elems.end(); eIt++ ) {
5174 const SMDS_MeshElement* elem = *eIt;
5175 int nbNodes = elem->NbNodes();
5176 int aShapeId = FindShape( elem );
5178 set<const SMDS_MeshNode*> nodeSet;
5179 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5180 int iUnique = 0, iCur = 0, nbRepl = 0;
5181 vector<int> iRepl( nbNodes );
5183 // get new seq of nodes
5184 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5185 while ( itN->more() ) {
5186 const SMDS_MeshNode* n =
5187 static_cast<const SMDS_MeshNode*>( itN->next() );
5189 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5190 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5192 // BUG 0020185: begin
5194 bool stopRecur = false;
5195 set<const SMDS_MeshNode*> nodesRecur;
5196 nodesRecur.insert(n);
5197 while (!stopRecur) {
5198 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5199 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5200 n = (*nnIt_i).second;
5201 if (!nodesRecur.insert(n).second) {
5202 // error: recursive dependancy
5211 iRepl[ nbRepl++ ] = iCur;
5213 curNodes[ iCur ] = n;
5214 bool isUnique = nodeSet.insert( n ).second;
5216 uniqueNodes[ iUnique++ ] = n;
5220 // Analyse element topology after replacement
5223 int nbUniqueNodes = nodeSet.size();
5224 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5225 // Polygons and Polyhedral volumes
5226 if (elem->IsPoly()) {
5228 if (elem->GetType() == SMDSAbs_Face) {
5230 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5232 for (; inode < nbNodes; inode++) {
5233 face_nodes[inode] = curNodes[inode];
5236 vector<const SMDS_MeshNode *> polygons_nodes;
5237 vector<int> quantities;
5238 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5242 for (int iface = 0; iface < nbNew - 1; iface++) {
5243 int nbNodes = quantities[iface];
5244 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5245 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5246 poly_nodes[ii] = polygons_nodes[inode];
5248 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5249 myLastCreatedElems.Append(newElem);
5251 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5253 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5256 rmElemIds.push_back(elem->GetID());
5260 else if (elem->GetType() == SMDSAbs_Volume) {
5261 // Polyhedral volume
5262 if (nbUniqueNodes < 4) {
5263 rmElemIds.push_back(elem->GetID());
5266 // each face has to be analized in order to check volume validity
5267 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5268 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5270 int nbFaces = aPolyedre->NbFaces();
5272 vector<const SMDS_MeshNode *> poly_nodes;
5273 vector<int> quantities;
5275 for (int iface = 1; iface <= nbFaces; iface++) {
5276 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5277 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5279 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5280 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5281 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5282 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5283 faceNode = (*nnIt).second;
5285 faceNodes[inode - 1] = faceNode;
5288 SimplifyFace(faceNodes, poly_nodes, quantities);
5291 if (quantities.size() > 3) {
5292 // to be done: remove coincident faces
5295 if (quantities.size() > 3)
5296 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5298 rmElemIds.push_back(elem->GetID());
5302 rmElemIds.push_back(elem->GetID());
5313 switch ( nbNodes ) {
5314 case 2: ///////////////////////////////////// EDGE
5315 isOk = false; break;
5316 case 3: ///////////////////////////////////// TRIANGLE
5317 isOk = false; break;
5319 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5321 else { //////////////////////////////////// QUADRANGLE
5322 if ( nbUniqueNodes < 3 )
5324 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5325 isOk = false; // opposite nodes stick
5328 case 6: ///////////////////////////////////// PENTAHEDRON
5329 if ( nbUniqueNodes == 4 ) {
5330 // ---------------------------------> tetrahedron
5332 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5333 // all top nodes stick: reverse a bottom
5334 uniqueNodes[ 0 ] = curNodes [ 1 ];
5335 uniqueNodes[ 1 ] = curNodes [ 0 ];
5337 else if (nbRepl == 3 &&
5338 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5339 // all bottom nodes stick: set a top before
5340 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5341 uniqueNodes[ 0 ] = curNodes [ 3 ];
5342 uniqueNodes[ 1 ] = curNodes [ 4 ];
5343 uniqueNodes[ 2 ] = curNodes [ 5 ];
5345 else if (nbRepl == 4 &&
5346 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5347 // a lateral face turns into a line: reverse a bottom
5348 uniqueNodes[ 0 ] = curNodes [ 1 ];
5349 uniqueNodes[ 1 ] = curNodes [ 0 ];
5354 else if ( nbUniqueNodes == 5 ) {
5355 // PENTAHEDRON --------------------> 2 tetrahedrons
5356 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5357 // a bottom node sticks with a linked top one
5359 SMDS_MeshElement* newElem =
5360 aMesh->AddVolume(curNodes[ 3 ],
5363 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5364 myLastCreatedElems.Append(newElem);
5366 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5367 // 2. : reverse a bottom
5368 uniqueNodes[ 0 ] = curNodes [ 1 ];
5369 uniqueNodes[ 1 ] = curNodes [ 0 ];
5379 if(elem->IsQuadratic()) { // Quadratic quadrangle
5392 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
5393 uniqueNodes[0] = curNodes[0];
5394 uniqueNodes[1] = curNodes[2];
5395 uniqueNodes[2] = curNodes[3];
5396 uniqueNodes[3] = curNodes[5];
5397 uniqueNodes[4] = curNodes[6];
5398 uniqueNodes[5] = curNodes[7];
5401 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
5402 uniqueNodes[0] = curNodes[0];
5403 uniqueNodes[1] = curNodes[1];
5404 uniqueNodes[2] = curNodes[2];
5405 uniqueNodes[3] = curNodes[4];
5406 uniqueNodes[4] = curNodes[5];
5407 uniqueNodes[5] = curNodes[6];
5410 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
5411 uniqueNodes[0] = curNodes[1];
5412 uniqueNodes[1] = curNodes[2];
5413 uniqueNodes[2] = curNodes[3];
5414 uniqueNodes[3] = curNodes[5];
5415 uniqueNodes[4] = curNodes[6];
5416 uniqueNodes[5] = curNodes[0];
5419 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
5420 uniqueNodes[0] = curNodes[0];
5421 uniqueNodes[1] = curNodes[1];
5422 uniqueNodes[2] = curNodes[3];
5423 uniqueNodes[3] = curNodes[4];
5424 uniqueNodes[4] = curNodes[6];
5425 uniqueNodes[5] = curNodes[7];
5428 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
5429 uniqueNodes[0] = curNodes[0];
5430 uniqueNodes[1] = curNodes[2];
5431 uniqueNodes[2] = curNodes[3];
5432 uniqueNodes[3] = curNodes[1];
5433 uniqueNodes[4] = curNodes[6];
5434 uniqueNodes[5] = curNodes[7];
5437 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
5438 uniqueNodes[0] = curNodes[0];
5439 uniqueNodes[1] = curNodes[1];
5440 uniqueNodes[2] = curNodes[2];
5441 uniqueNodes[3] = curNodes[4];
5442 uniqueNodes[4] = curNodes[5];
5443 uniqueNodes[5] = curNodes[7];
5446 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
5447 uniqueNodes[0] = curNodes[0];
5448 uniqueNodes[1] = curNodes[1];
5449 uniqueNodes[2] = curNodes[3];
5450 uniqueNodes[3] = curNodes[4];
5451 uniqueNodes[4] = curNodes[2];
5452 uniqueNodes[5] = curNodes[7];
5455 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
5456 uniqueNodes[0] = curNodes[0];
5457 uniqueNodes[1] = curNodes[1];
5458 uniqueNodes[2] = curNodes[2];
5459 uniqueNodes[3] = curNodes[4];
5460 uniqueNodes[4] = curNodes[5];
5461 uniqueNodes[5] = curNodes[3];
5467 //////////////////////////////////// HEXAHEDRON
5469 SMDS_VolumeTool hexa (elem);
5470 hexa.SetExternalNormal();
5471 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
5472 //////////////////////// ---> tetrahedron
5473 for ( int iFace = 0; iFace < 6; iFace++ ) {
5474 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5475 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5476 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5477 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5478 // one face turns into a point ...
5479 int iOppFace = hexa.GetOppFaceIndex( iFace );
5480 ind = hexa.GetFaceNodesIndices( iOppFace );
5482 iUnique = 2; // reverse a tetrahedron bottom
5483 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
5484 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5486 else if ( iUnique >= 0 )
5487 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5489 if ( nbStick == 1 ) {
5490 // ... and the opposite one - into a triangle.
5492 ind = hexa.GetFaceNodesIndices( iFace );
5493 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
5500 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
5501 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
5502 for ( int iFace = 0; iFace < 6; iFace++ ) {
5503 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5504 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5505 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5506 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5507 // one face turns into a point ...
5508 int iOppFace = hexa.GetOppFaceIndex( iFace );
5509 ind = hexa.GetFaceNodesIndices( iOppFace );
5511 iUnique = 2; // reverse a tetrahedron 1 bottom
5512 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
5513 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5515 else if ( iUnique >= 0 )
5516 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5518 if ( nbStick == 0 ) {
5519 // ... and the opposite one is a quadrangle
5521 const int* indTop = hexa.GetFaceNodesIndices( iFace );
5522 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
5525 SMDS_MeshElement* newElem =
5526 aMesh->AddVolume(curNodes[ind[ 0 ]],
5529 curNodes[indTop[ 0 ]]);
5530 myLastCreatedElems.Append(newElem);
5532 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5539 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
5540 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
5541 // find indices of quad and tri faces
5542 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
5543 for ( iFace = 0; iFace < 6; iFace++ ) {
5544 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5546 for ( iCur = 0; iCur < 4; iCur++ )
5547 nodeSet.insert( curNodes[ind[ iCur ]] );
5548 nbUniqueNodes = nodeSet.size();
5549 if ( nbUniqueNodes == 3 )
5550 iTriFace[ nbTri++ ] = iFace;
5551 else if ( nbUniqueNodes == 4 )
5552 iQuadFace[ nbQuad++ ] = iFace;
5554 if (nbQuad == 2 && nbTri == 4 &&
5555 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
5556 // 2 opposite quadrangles stuck with a diagonal;
5557 // sample groups of merged indices: (0-4)(2-6)
5558 // --------------------------------------------> 2 tetrahedrons
5559 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
5560 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
5561 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
5562 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
5563 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
5564 // stuck with 0-2 diagonal
5572 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
5573 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
5574 // stuck with 1-3 diagonal
5586 uniqueNodes[ 0 ] = curNodes [ i0 ];
5587 uniqueNodes[ 1 ] = curNodes [ i1d ];
5588 uniqueNodes[ 2 ] = curNodes [ i3d ];
5589 uniqueNodes[ 3 ] = curNodes [ i0t ];
5592 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
5596 myLastCreatedElems.Append(newElem);
5598 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5601 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
5602 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
5603 // --------------------------------------------> prism
5604 // find 2 opposite triangles
5606 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
5607 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
5608 // find indices of kept and replaced nodes
5609 // and fill unique nodes of 2 opposite triangles
5610 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
5611 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
5612 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
5613 // fill unique nodes
5616 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
5617 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
5618 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
5620 // iCur of a linked node of the opposite face (make normals co-directed):
5621 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
5622 // check that correspondent corners of triangles are linked
5623 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
5626 uniqueNodes[ iUnique ] = n;
5627 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
5636 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
5642 } // switch ( nbNodes )
5644 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
5647 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
5648 // Change nodes of polyedre
5649 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5650 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5652 int nbFaces = aPolyedre->NbFaces();
5654 vector<const SMDS_MeshNode *> poly_nodes;
5655 vector<int> quantities (nbFaces);
5657 for (int iface = 1; iface <= nbFaces; iface++) {
5658 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5659 quantities[iface - 1] = nbFaceNodes;
5661 for (inode = 1; inode <= nbFaceNodes; inode++) {
5662 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
5664 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
5665 if (nnIt != nodeNodeMap.end()) { // curNode sticks
5666 curNode = (*nnIt).second;
5668 poly_nodes.push_back(curNode);
5671 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
5675 // Change regular element or polygon
5676 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
5680 // Remove invalid regular element or invalid polygon
5681 rmElemIds.push_back( elem->GetID() );
5684 } // loop on elements
5686 // Remove equal nodes and bad elements
5688 Remove( rmNodeIds, true );
5689 Remove( rmElemIds, false );
5694 // ========================================================
5695 // class : SortableElement
5696 // purpose : allow sorting elements basing on their nodes
5697 // ========================================================
5698 class SortableElement : public set <const SMDS_MeshElement*>
5702 SortableElement( const SMDS_MeshElement* theElem )
5705 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
5706 while ( nodeIt->more() )
5707 this->insert( nodeIt->next() );
5710 const SMDS_MeshElement* Get() const
5713 void Set(const SMDS_MeshElement* e) const
5718 mutable const SMDS_MeshElement* myElem;
5721 //=======================================================================
5722 //function : FindEqualElements
5723 //purpose : Return list of group of elements built on the same nodes.
5724 // Search among theElements or in the whole mesh if theElements is empty
5725 //=======================================================================
5726 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
5727 TListOfListOfElementsID & theGroupsOfElementsID)
5729 myLastCreatedElems.Clear();
5730 myLastCreatedNodes.Clear();
5732 typedef set<const SMDS_MeshElement*> TElemsSet;
5733 typedef map< SortableElement, int > TMapOfNodeSet;
5734 typedef list<int> TGroupOfElems;
5737 if ( theElements.empty() )
5738 { // get all elements in the mesh
5739 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
5740 while ( eIt->more() )
5741 elems.insert( elems.end(), eIt->next());
5744 elems = theElements;
5746 vector< TGroupOfElems > arrayOfGroups;
5747 TGroupOfElems groupOfElems;
5748 TMapOfNodeSet mapOfNodeSet;
5750 TElemsSet::iterator elemIt = elems.begin();
5751 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
5752 const SMDS_MeshElement* curElem = *elemIt;
5753 SortableElement SE(curElem);
5756 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
5757 if( !(pp.second) ) {
5758 TMapOfNodeSet::iterator& itSE = pp.first;
5759 ind = (*itSE).second;
5760 arrayOfGroups[ind].push_back(curElem->GetID());
5763 groupOfElems.clear();
5764 groupOfElems.push_back(curElem->GetID());
5765 arrayOfGroups.push_back(groupOfElems);
5770 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
5771 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
5772 groupOfElems = *groupIt;
5773 if ( groupOfElems.size() > 1 ) {
5774 groupOfElems.sort();
5775 theGroupsOfElementsID.push_back(groupOfElems);
5780 //=======================================================================
5781 //function : MergeElements
5782 //purpose : In each given group, substitute all elements by the first one.
5783 //=======================================================================
5785 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
5787 myLastCreatedElems.Clear();
5788 myLastCreatedNodes.Clear();
5790 typedef list<int> TListOfIDs;
5791 TListOfIDs rmElemIds; // IDs of elems to remove
5793 SMESHDS_Mesh* aMesh = GetMeshDS();
5795 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
5796 while ( groupsIt != theGroupsOfElementsID.end() ) {
5797 TListOfIDs& aGroupOfElemID = *groupsIt;
5798 aGroupOfElemID.sort();
5799 int elemIDToKeep = aGroupOfElemID.front();
5800 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
5801 aGroupOfElemID.pop_front();
5802 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
5803 while ( idIt != aGroupOfElemID.end() ) {
5804 int elemIDToRemove = *idIt;
5805 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
5806 // add the kept element in groups of removed one (PAL15188)
5807 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
5808 rmElemIds.push_back( elemIDToRemove );
5814 Remove( rmElemIds, false );
5817 //=======================================================================
5818 //function : MergeEqualElements
5819 //purpose : Remove all but one of elements built on the same nodes.
5820 //=======================================================================
5822 void SMESH_MeshEditor::MergeEqualElements()
5824 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
5825 to merge equal elements in the whole mesh */
5826 TListOfListOfElementsID aGroupsOfElementsID;
5827 FindEqualElements(aMeshElements, aGroupsOfElementsID);
5828 MergeElements(aGroupsOfElementsID);
5831 //=======================================================================
5832 //function : FindFaceInSet
5833 //purpose : Return a face having linked nodes n1 and n2 and which is
5834 // - not in avoidSet,
5835 // - in elemSet provided that !elemSet.empty()
5836 //=======================================================================
5838 const SMDS_MeshElement*
5839 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
5840 const SMDS_MeshNode* n2,
5841 const TIDSortedElemSet& elemSet,
5842 const TIDSortedElemSet& avoidSet)
5845 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
5846 while ( invElemIt->more() ) { // loop on inverse elements of n1
5847 const SMDS_MeshElement* elem = invElemIt->next();
5848 if (avoidSet.find( elem ) != avoidSet.end() )
5850 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
5852 // get face nodes and find index of n1
5853 int i1, nbN = elem->NbNodes(), iNode = 0;
5854 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
5855 vector<const SMDS_MeshNode*> faceNodes( nbN );
5856 const SMDS_MeshNode* n;
5857 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5858 while ( nIt->more() ) {
5859 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5860 if ( faceNodes[ iNode++ ] == n1 )
5863 // find a n2 linked to n1
5864 if(!elem->IsQuadratic()) {
5865 for ( iNode = 0; iNode < 2; iNode++ ) {
5866 if ( iNode ) // node before n1
5867 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5868 else // node after n1
5869 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5874 else { // analysis for quadratic elements
5875 bool IsFind = false;
5876 // check using only corner nodes
5877 for ( iNode = 0; iNode < 2; iNode++ ) {
5878 if ( iNode ) // node before n1
5879 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
5880 else // node after n1
5881 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
5889 // check using all nodes
5890 const SMDS_QuadraticFaceOfNodes* F =
5891 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
5892 // use special nodes iterator
5894 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5895 while ( anIter->more() ) {
5896 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
5897 if ( faceNodes[ iNode++ ] == n1 )
5900 for ( iNode = 0; iNode < 2; iNode++ ) {
5901 if ( iNode ) // node before n1
5902 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
5903 else // node after n1
5904 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
5910 } // end analysis for quadratic elements
5915 //=======================================================================
5916 //function : findAdjacentFace
5918 //=======================================================================
5920 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
5921 const SMDS_MeshNode* n2,
5922 const SMDS_MeshElement* elem)
5924 TIDSortedElemSet elemSet, avoidSet;
5926 avoidSet.insert ( elem );
5927 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
5930 //=======================================================================
5931 //function : FindFreeBorder
5933 //=======================================================================
5935 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
5937 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
5938 const SMDS_MeshNode* theSecondNode,
5939 const SMDS_MeshNode* theLastNode,
5940 list< const SMDS_MeshNode* > & theNodes,
5941 list< const SMDS_MeshElement* >& theFaces)
5943 if ( !theFirstNode || !theSecondNode )
5945 // find border face between theFirstNode and theSecondNode
5946 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
5950 theFaces.push_back( curElem );
5951 theNodes.push_back( theFirstNode );
5952 theNodes.push_back( theSecondNode );
5954 //vector<const SMDS_MeshNode*> nodes;
5955 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
5956 set < const SMDS_MeshElement* > foundElems;
5957 bool needTheLast = ( theLastNode != 0 );
5959 while ( nStart != theLastNode ) {
5960 if ( nStart == theFirstNode )
5961 return !needTheLast;
5963 // find all free border faces sharing form nStart
5965 list< const SMDS_MeshElement* > curElemList;
5966 list< const SMDS_MeshNode* > nStartList;
5967 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
5968 while ( invElemIt->more() ) {
5969 const SMDS_MeshElement* e = invElemIt->next();
5970 if ( e == curElem || foundElems.insert( e ).second ) {
5972 int iNode = 0, nbNodes = e->NbNodes();
5973 //const SMDS_MeshNode* nodes[nbNodes+1];
5974 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
5976 if(e->IsQuadratic()) {
5977 const SMDS_QuadraticFaceOfNodes* F =
5978 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
5979 // use special nodes iterator
5980 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
5981 while( anIter->more() ) {
5982 nodes[ iNode++ ] = anIter->next();
5986 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
5987 while ( nIt->more() )
5988 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
5990 nodes[ iNode ] = nodes[ 0 ];
5992 for ( iNode = 0; iNode < nbNodes; iNode++ )
5993 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
5994 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
5995 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
5997 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
5998 curElemList.push_back( e );
6002 // analyse the found
6004 int nbNewBorders = curElemList.size();
6005 if ( nbNewBorders == 0 ) {
6006 // no free border furthermore
6007 return !needTheLast;
6009 else if ( nbNewBorders == 1 ) {
6010 // one more element found
6012 nStart = nStartList.front();
6013 curElem = curElemList.front();
6014 theFaces.push_back( curElem );
6015 theNodes.push_back( nStart );
6018 // several continuations found
6019 list< const SMDS_MeshElement* >::iterator curElemIt;
6020 list< const SMDS_MeshNode* >::iterator nStartIt;
6021 // check if one of them reached the last node
6022 if ( needTheLast ) {
6023 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6024 curElemIt!= curElemList.end();
6025 curElemIt++, nStartIt++ )
6026 if ( *nStartIt == theLastNode ) {
6027 theFaces.push_back( *curElemIt );
6028 theNodes.push_back( *nStartIt );
6032 // find the best free border by the continuations
6033 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6034 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6035 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6036 curElemIt!= curElemList.end();
6037 curElemIt++, nStartIt++ )
6039 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6040 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6041 // find one more free border
6042 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6046 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6047 // choice: clear a worse one
6048 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6049 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6050 contNodes[ iWorse ].clear();
6051 contFaces[ iWorse ].clear();
6054 if ( contNodes[0].empty() && contNodes[1].empty() )
6057 // append the best free border
6058 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6059 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6060 theNodes.pop_back(); // remove nIgnore
6061 theNodes.pop_back(); // remove nStart
6062 theFaces.pop_back(); // remove curElem
6063 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6064 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6065 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6066 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6069 } // several continuations found
6070 } // while ( nStart != theLastNode )
6075 //=======================================================================
6076 //function : CheckFreeBorderNodes
6077 //purpose : Return true if the tree nodes are on a free border
6078 //=======================================================================
6080 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6081 const SMDS_MeshNode* theNode2,
6082 const SMDS_MeshNode* theNode3)
6084 list< const SMDS_MeshNode* > nodes;
6085 list< const SMDS_MeshElement* > faces;
6086 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6089 //=======================================================================
6090 //function : SewFreeBorder
6092 //=======================================================================
6094 SMESH_MeshEditor::Sew_Error
6095 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6096 const SMDS_MeshNode* theBordSecondNode,
6097 const SMDS_MeshNode* theBordLastNode,
6098 const SMDS_MeshNode* theSideFirstNode,
6099 const SMDS_MeshNode* theSideSecondNode,
6100 const SMDS_MeshNode* theSideThirdNode,
6101 const bool theSideIsFreeBorder,
6102 const bool toCreatePolygons,
6103 const bool toCreatePolyedrs)
6105 myLastCreatedElems.Clear();
6106 myLastCreatedNodes.Clear();
6108 MESSAGE("::SewFreeBorder()");
6109 Sew_Error aResult = SEW_OK;
6111 // ====================================
6112 // find side nodes and elements
6113 // ====================================
6115 list< const SMDS_MeshNode* > nSide[ 2 ];
6116 list< const SMDS_MeshElement* > eSide[ 2 ];
6117 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6118 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6122 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6123 nSide[0], eSide[0])) {
6124 MESSAGE(" Free Border 1 not found " );
6125 aResult = SEW_BORDER1_NOT_FOUND;
6127 if (theSideIsFreeBorder) {
6130 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6131 nSide[1], eSide[1])) {
6132 MESSAGE(" Free Border 2 not found " );
6133 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6136 if ( aResult != SEW_OK )
6139 if (!theSideIsFreeBorder) {
6143 // -------------------------------------------------------------------------
6145 // 1. If nodes to merge are not coincident, move nodes of the free border
6146 // from the coord sys defined by the direction from the first to last
6147 // nodes of the border to the correspondent sys of the side 2
6148 // 2. On the side 2, find the links most co-directed with the correspondent
6149 // links of the free border
6150 // -------------------------------------------------------------------------
6152 // 1. Since sewing may brake if there are volumes to split on the side 2,
6153 // we wont move nodes but just compute new coordinates for them
6154 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6155 TNodeXYZMap nBordXYZ;
6156 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6157 list< const SMDS_MeshNode* >::iterator nBordIt;
6159 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6160 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6161 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6162 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6163 double tol2 = 1.e-8;
6164 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6165 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6166 // Need node movement.
6168 // find X and Z axes to create trsf
6169 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6171 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6173 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6176 gp_Ax3 toBordAx( Pb1, Zb, X );
6177 gp_Ax3 fromSideAx( Ps1, Zs, X );
6178 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6180 gp_Trsf toBordSys, fromSide2Sys;
6181 toBordSys.SetTransformation( toBordAx );
6182 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6183 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6186 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6187 const SMDS_MeshNode* n = *nBordIt;
6188 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6189 toBordSys.Transforms( xyz );
6190 fromSide2Sys.Transforms( xyz );
6191 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6195 // just insert nodes XYZ in the nBordXYZ map
6196 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6197 const SMDS_MeshNode* n = *nBordIt;
6198 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6202 // 2. On the side 2, find the links most co-directed with the correspondent
6203 // links of the free border
6205 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6206 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6207 sideNodes.push_back( theSideFirstNode );
6209 bool hasVolumes = false;
6210 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6211 set<long> foundSideLinkIDs, checkedLinkIDs;
6212 SMDS_VolumeTool volume;
6213 //const SMDS_MeshNode* faceNodes[ 4 ];
6215 const SMDS_MeshNode* sideNode;
6216 const SMDS_MeshElement* sideElem;
6217 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6218 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6219 nBordIt = bordNodes.begin();
6221 // border node position and border link direction to compare with
6222 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6223 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6224 // choose next side node by link direction or by closeness to
6225 // the current border node:
6226 bool searchByDir = ( *nBordIt != theBordLastNode );
6228 // find the next node on the Side 2
6230 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6232 checkedLinkIDs.clear();
6233 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6235 // loop on inverse elements of current node (prevSideNode) on the Side 2
6236 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6237 while ( invElemIt->more() )
6239 const SMDS_MeshElement* elem = invElemIt->next();
6240 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6241 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6242 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6243 bool isVolume = volume.Set( elem );
6244 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6245 if ( isVolume ) // --volume
6247 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6248 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6249 if(elem->IsQuadratic()) {
6250 const SMDS_QuadraticFaceOfNodes* F =
6251 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6252 // use special nodes iterator
6253 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6254 while( anIter->more() ) {
6255 nodes[ iNode ] = anIter->next();
6256 if ( nodes[ iNode++ ] == prevSideNode )
6257 iPrevNode = iNode - 1;
6261 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6262 while ( nIt->more() ) {
6263 nodes[ iNode ] = cast2Node( nIt->next() );
6264 if ( nodes[ iNode++ ] == prevSideNode )
6265 iPrevNode = iNode - 1;
6268 // there are 2 links to check
6273 // loop on links, to be precise, on the second node of links
6274 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6275 const SMDS_MeshNode* n = nodes[ iNode ];
6277 if ( !volume.IsLinked( n, prevSideNode ))
6281 if ( iNode ) // a node before prevSideNode
6282 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6283 else // a node after prevSideNode
6284 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6286 // check if this link was already used
6287 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6288 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6289 if (!isJustChecked &&
6290 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6292 // test a link geometrically
6293 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6294 bool linkIsBetter = false;
6295 double dot = 0.0, dist = 0.0;
6296 if ( searchByDir ) { // choose most co-directed link
6297 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6298 linkIsBetter = ( dot > maxDot );
6300 else { // choose link with the node closest to bordPos
6301 dist = ( nextXYZ - bordPos ).SquareModulus();
6302 linkIsBetter = ( dist < minDist );
6304 if ( linkIsBetter ) {
6313 } // loop on inverse elements of prevSideNode
6316 MESSAGE(" Cant find path by links of the Side 2 ");
6317 return SEW_BAD_SIDE_NODES;
6319 sideNodes.push_back( sideNode );
6320 sideElems.push_back( sideElem );
6321 foundSideLinkIDs.insert ( linkID );
6322 prevSideNode = sideNode;
6324 if ( *nBordIt == theBordLastNode )
6325 searchByDir = false;
6327 // find the next border link to compare with
6328 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6329 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6330 // move to next border node if sideNode is before forward border node (bordPos)
6331 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6332 prevBordNode = *nBordIt;
6334 bordPos = nBordXYZ[ *nBordIt ];
6335 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6336 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6340 while ( sideNode != theSideSecondNode );
6342 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6343 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6344 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6346 } // end nodes search on the side 2
6348 // ============================
6349 // sew the border to the side 2
6350 // ============================
6352 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6353 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6355 TListOfListOfNodes nodeGroupsToMerge;
6356 if ( nbNodes[0] == nbNodes[1] ||
6357 ( theSideIsFreeBorder && !theSideThirdNode)) {
6359 // all nodes are to be merged
6361 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6362 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6363 nIt[0]++, nIt[1]++ )
6365 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6366 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6367 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6372 // insert new nodes into the border and the side to get equal nb of segments
6374 // get normalized parameters of nodes on the borders
6375 //double param[ 2 ][ maxNbNodes ];
6377 param[0] = new double [ maxNbNodes ];
6378 param[1] = new double [ maxNbNodes ];
6380 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6381 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6382 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6383 const SMDS_MeshNode* nPrev = *nIt;
6384 double bordLength = 0;
6385 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
6386 const SMDS_MeshNode* nCur = *nIt;
6387 gp_XYZ segment (nCur->X() - nPrev->X(),
6388 nCur->Y() - nPrev->Y(),
6389 nCur->Z() - nPrev->Z());
6390 double segmentLen = segment.Modulus();
6391 bordLength += segmentLen;
6392 param[ iBord ][ iNode ] = bordLength;
6395 // normalize within [0,1]
6396 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
6397 param[ iBord ][ iNode ] /= bordLength;
6401 // loop on border segments
6402 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
6403 int i[ 2 ] = { 0, 0 };
6404 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
6405 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
6407 TElemOfNodeListMap insertMap;
6408 TElemOfNodeListMap::iterator insertMapIt;
6410 // key: elem to insert nodes into
6411 // value: 2 nodes to insert between + nodes to be inserted
6413 bool next[ 2 ] = { false, false };
6415 // find min adjacent segment length after sewing
6416 double nextParam = 10., prevParam = 0;
6417 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6418 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
6419 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
6420 if ( i[ iBord ] > 0 )
6421 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
6423 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6424 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6425 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
6427 // choose to insert or to merge nodes
6428 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
6429 if ( Abs( du ) <= minSegLen * 0.2 ) {
6432 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6433 const SMDS_MeshNode* n0 = *nIt[0];
6434 const SMDS_MeshNode* n1 = *nIt[1];
6435 nodeGroupsToMerge.back().push_back( n1 );
6436 nodeGroupsToMerge.back().push_back( n0 );
6437 // position of node of the border changes due to merge
6438 param[ 0 ][ i[0] ] += du;
6439 // move n1 for the sake of elem shape evaluation during insertion.
6440 // n1 will be removed by MergeNodes() anyway
6441 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
6442 next[0] = next[1] = true;
6447 int intoBord = ( du < 0 ) ? 0 : 1;
6448 const SMDS_MeshElement* elem = *eIt[ intoBord ];
6449 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
6450 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
6451 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
6452 if ( intoBord == 1 ) {
6453 // move node of the border to be on a link of elem of the side
6454 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
6455 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
6456 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
6457 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
6458 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
6460 insertMapIt = insertMap.find( elem );
6461 bool notFound = ( insertMapIt == insertMap.end() );
6462 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
6464 // insert into another link of the same element:
6465 // 1. perform insertion into the other link of the elem
6466 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6467 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
6468 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
6469 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
6470 // 2. perform insertion into the link of adjacent faces
6472 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
6474 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
6478 if (toCreatePolyedrs) {
6479 // perform insertion into the links of adjacent volumes
6480 UpdateVolumes(n12, n22, nodeList);
6482 // 3. find an element appeared on n1 and n2 after the insertion
6483 insertMap.erase( elem );
6484 elem = findAdjacentFace( n1, n2, 0 );
6486 if ( notFound || otherLink ) {
6487 // add element and nodes of the side into the insertMap
6488 insertMapIt = insertMap.insert
6489 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
6490 (*insertMapIt).second.push_back( n1 );
6491 (*insertMapIt).second.push_back( n2 );
6493 // add node to be inserted into elem
6494 (*insertMapIt).second.push_back( nIns );
6495 next[ 1 - intoBord ] = true;
6498 // go to the next segment
6499 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6500 if ( next[ iBord ] ) {
6501 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
6503 nPrev[ iBord ] = *nIt[ iBord ];
6504 nIt[ iBord ]++; i[ iBord ]++;
6508 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
6510 // perform insertion of nodes into elements
6512 for (insertMapIt = insertMap.begin();
6513 insertMapIt != insertMap.end();
6516 const SMDS_MeshElement* elem = (*insertMapIt).first;
6517 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6518 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
6519 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
6521 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
6523 if ( !theSideIsFreeBorder ) {
6524 // look for and insert nodes into the faces adjacent to elem
6526 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
6528 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
6533 if (toCreatePolyedrs) {
6534 // perform insertion into the links of adjacent volumes
6535 UpdateVolumes(n1, n2, nodeList);
6541 } // end: insert new nodes
6543 MergeNodes ( nodeGroupsToMerge );
6548 //=======================================================================
6549 //function : InsertNodesIntoLink
6550 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
6551 // and theBetweenNode2 and split theElement
6552 //=======================================================================
6554 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
6555 const SMDS_MeshNode* theBetweenNode1,
6556 const SMDS_MeshNode* theBetweenNode2,
6557 list<const SMDS_MeshNode*>& theNodesToInsert,
6558 const bool toCreatePoly)
6560 if ( theFace->GetType() != SMDSAbs_Face ) return;
6562 // find indices of 2 link nodes and of the rest nodes
6563 int iNode = 0, il1, il2, i3, i4;
6564 il1 = il2 = i3 = i4 = -1;
6565 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
6566 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
6568 if(theFace->IsQuadratic()) {
6569 const SMDS_QuadraticFaceOfNodes* F =
6570 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6571 // use special nodes iterator
6572 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6573 while( anIter->more() ) {
6574 const SMDS_MeshNode* n = anIter->next();
6575 if ( n == theBetweenNode1 )
6577 else if ( n == theBetweenNode2 )
6583 nodes[ iNode++ ] = n;
6587 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6588 while ( nodeIt->more() ) {
6589 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6590 if ( n == theBetweenNode1 )
6592 else if ( n == theBetweenNode2 )
6598 nodes[ iNode++ ] = n;
6601 if ( il1 < 0 || il2 < 0 || i3 < 0 )
6604 // arrange link nodes to go one after another regarding the face orientation
6605 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
6606 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
6611 aNodesToInsert.reverse();
6613 // check that not link nodes of a quadrangles are in good order
6614 int nbFaceNodes = theFace->NbNodes();
6615 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
6621 if (toCreatePoly || theFace->IsPoly()) {
6624 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
6626 // add nodes of face up to first node of link
6629 if(theFace->IsQuadratic()) {
6630 const SMDS_QuadraticFaceOfNodes* F =
6631 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6632 // use special nodes iterator
6633 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6634 while( anIter->more() && !isFLN ) {
6635 const SMDS_MeshNode* n = anIter->next();
6636 poly_nodes[iNode++] = n;
6637 if (n == nodes[il1]) {
6641 // add nodes to insert
6642 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6643 for (; nIt != aNodesToInsert.end(); nIt++) {
6644 poly_nodes[iNode++] = *nIt;
6646 // add nodes of face starting from last node of link
6647 while ( anIter->more() ) {
6648 poly_nodes[iNode++] = anIter->next();
6652 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6653 while ( nodeIt->more() && !isFLN ) {
6654 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6655 poly_nodes[iNode++] = n;
6656 if (n == nodes[il1]) {
6660 // add nodes to insert
6661 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6662 for (; nIt != aNodesToInsert.end(); nIt++) {
6663 poly_nodes[iNode++] = *nIt;
6665 // add nodes of face starting from last node of link
6666 while ( nodeIt->more() ) {
6667 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6668 poly_nodes[iNode++] = n;
6672 // edit or replace the face
6673 SMESHDS_Mesh *aMesh = GetMeshDS();
6675 if (theFace->IsPoly()) {
6676 aMesh->ChangePolygonNodes(theFace, poly_nodes);
6679 int aShapeId = FindShape( theFace );
6681 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6682 myLastCreatedElems.Append(newElem);
6683 if ( aShapeId && newElem )
6684 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6686 aMesh->RemoveElement(theFace);
6691 if( !theFace->IsQuadratic() ) {
6693 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
6694 int nbLinkNodes = 2 + aNodesToInsert.size();
6695 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
6696 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
6697 linkNodes[ 0 ] = nodes[ il1 ];
6698 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
6699 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6700 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6701 linkNodes[ iNode++ ] = *nIt;
6703 // decide how to split a quadrangle: compare possible variants
6704 // and choose which of splits to be a quadrangle
6705 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
6706 if ( nbFaceNodes == 3 ) {
6707 iBestQuad = nbSplits;
6710 else if ( nbFaceNodes == 4 ) {
6711 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
6712 double aBestRate = DBL_MAX;
6713 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
6715 double aBadRate = 0;
6716 // evaluate elements quality
6717 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
6718 if ( iSplit == iQuad ) {
6719 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
6723 aBadRate += getBadRate( &quad, aCrit );
6726 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
6728 nodes[ iSplit < iQuad ? i4 : i3 ]);
6729 aBadRate += getBadRate( &tria, aCrit );
6733 if ( aBadRate < aBestRate ) {
6735 aBestRate = aBadRate;
6740 // create new elements
6741 SMESHDS_Mesh *aMesh = GetMeshDS();
6742 int aShapeId = FindShape( theFace );
6745 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
6746 SMDS_MeshElement* newElem = 0;
6747 if ( iSplit == iBestQuad )
6748 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6753 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6755 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
6756 myLastCreatedElems.Append(newElem);
6757 if ( aShapeId && newElem )
6758 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6761 // change nodes of theFace
6762 const SMDS_MeshNode* newNodes[ 4 ];
6763 newNodes[ 0 ] = linkNodes[ i1 ];
6764 newNodes[ 1 ] = linkNodes[ i2 ];
6765 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
6766 newNodes[ 3 ] = nodes[ i4 ];
6767 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
6768 } // end if(!theFace->IsQuadratic())
6769 else { // theFace is quadratic
6770 // we have to split theFace on simple triangles and one simple quadrangle
6772 int nbshift = tmp*2;
6773 // shift nodes in nodes[] by nbshift
6775 for(i=0; i<nbshift; i++) {
6776 const SMDS_MeshNode* n = nodes[0];
6777 for(j=0; j<nbFaceNodes-1; j++) {
6778 nodes[j] = nodes[j+1];
6780 nodes[nbFaceNodes-1] = n;
6782 il1 = il1 - nbshift;
6783 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
6784 // n0 n1 n2 n0 n1 n2
6785 // +-----+-----+ +-----+-----+
6794 // create new elements
6795 SMESHDS_Mesh *aMesh = GetMeshDS();
6796 int aShapeId = FindShape( theFace );
6799 if(nbFaceNodes==6) { // quadratic triangle
6800 SMDS_MeshElement* newElem =
6801 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6802 myLastCreatedElems.Append(newElem);
6803 if ( aShapeId && newElem )
6804 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6805 if(theFace->IsMediumNode(nodes[il1])) {
6806 // create quadrangle
6807 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
6808 myLastCreatedElems.Append(newElem);
6809 if ( aShapeId && newElem )
6810 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6816 // create quadrangle
6817 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
6818 myLastCreatedElems.Append(newElem);
6819 if ( aShapeId && newElem )
6820 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6826 else { // nbFaceNodes==8 - quadratic quadrangle
6827 SMDS_MeshElement* newElem =
6828 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6829 myLastCreatedElems.Append(newElem);
6830 if ( aShapeId && newElem )
6831 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6832 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
6833 myLastCreatedElems.Append(newElem);
6834 if ( aShapeId && newElem )
6835 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6836 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
6837 myLastCreatedElems.Append(newElem);
6838 if ( aShapeId && newElem )
6839 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6840 if(theFace->IsMediumNode(nodes[il1])) {
6841 // create quadrangle
6842 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
6843 myLastCreatedElems.Append(newElem);
6844 if ( aShapeId && newElem )
6845 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6851 // create quadrangle
6852 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
6853 myLastCreatedElems.Append(newElem);
6854 if ( aShapeId && newElem )
6855 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6861 // create needed triangles using n1,n2,n3 and inserted nodes
6862 int nbn = 2 + aNodesToInsert.size();
6863 //const SMDS_MeshNode* aNodes[nbn];
6864 vector<const SMDS_MeshNode*> aNodes(nbn);
6865 aNodes[0] = nodes[n1];
6866 aNodes[nbn-1] = nodes[n2];
6867 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6868 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6869 aNodes[iNode++] = *nIt;
6871 for(i=1; i<nbn; i++) {
6872 SMDS_MeshElement* newElem =
6873 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
6874 myLastCreatedElems.Append(newElem);
6875 if ( aShapeId && newElem )
6876 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6878 // remove old quadratic face
6879 aMesh->RemoveElement(theFace);
6883 //=======================================================================
6884 //function : UpdateVolumes
6886 //=======================================================================
6887 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
6888 const SMDS_MeshNode* theBetweenNode2,
6889 list<const SMDS_MeshNode*>& theNodesToInsert)
6891 myLastCreatedElems.Clear();
6892 myLastCreatedNodes.Clear();
6894 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
6895 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
6896 const SMDS_MeshElement* elem = invElemIt->next();
6898 // check, if current volume has link theBetweenNode1 - theBetweenNode2
6899 SMDS_VolumeTool aVolume (elem);
6900 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
6903 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
6904 int iface, nbFaces = aVolume.NbFaces();
6905 vector<const SMDS_MeshNode *> poly_nodes;
6906 vector<int> quantities (nbFaces);
6908 for (iface = 0; iface < nbFaces; iface++) {
6909 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
6910 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
6911 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
6913 for (int inode = 0; inode < nbFaceNodes; inode++) {
6914 poly_nodes.push_back(faceNodes[inode]);
6916 if (nbInserted == 0) {
6917 if (faceNodes[inode] == theBetweenNode1) {
6918 if (faceNodes[inode + 1] == theBetweenNode2) {
6919 nbInserted = theNodesToInsert.size();
6921 // add nodes to insert
6922 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
6923 for (; nIt != theNodesToInsert.end(); nIt++) {
6924 poly_nodes.push_back(*nIt);
6928 else if (faceNodes[inode] == theBetweenNode2) {
6929 if (faceNodes[inode + 1] == theBetweenNode1) {
6930 nbInserted = theNodesToInsert.size();
6932 // add nodes to insert in reversed order
6933 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
6935 for (; nIt != theNodesToInsert.begin(); nIt--) {
6936 poly_nodes.push_back(*nIt);
6938 poly_nodes.push_back(*nIt);
6945 quantities[iface] = nbFaceNodes + nbInserted;
6948 // Replace or update the volume
6949 SMESHDS_Mesh *aMesh = GetMeshDS();
6951 if (elem->IsPoly()) {
6952 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6956 int aShapeId = FindShape( elem );
6958 SMDS_MeshElement* newElem =
6959 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
6960 myLastCreatedElems.Append(newElem);
6961 if (aShapeId && newElem)
6962 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6964 aMesh->RemoveElement(elem);
6969 //=======================================================================
6971 * \brief Convert elements contained in a submesh to quadratic
6972 * \retval int - nb of checked elements
6974 //=======================================================================
6976 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
6977 SMESH_MesherHelper& theHelper,
6978 const bool theForce3d)
6981 if( !theSm ) return nbElem;
6983 const bool notFromGroups = false;
6984 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
6985 while(ElemItr->more())
6988 const SMDS_MeshElement* elem = ElemItr->next();
6989 if( !elem || elem->IsQuadratic() ) continue;
6991 int id = elem->GetID();
6992 int nbNodes = elem->NbNodes();
6993 vector<const SMDS_MeshNode *> aNds (nbNodes);
6995 for(int i = 0; i < nbNodes; i++)
6997 aNds[i] = elem->GetNode(i);
6999 SMDSAbs_ElementType aType = elem->GetType();
7001 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7003 const SMDS_MeshElement* NewElem = 0;
7009 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7017 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7020 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7027 case SMDSAbs_Volume :
7032 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7035 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7038 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7039 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7049 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7051 theSm->AddElement( NewElem );
7056 //=======================================================================
7057 //function : ConvertToQuadratic
7059 //=======================================================================
7060 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7062 SMESHDS_Mesh* meshDS = GetMeshDS();
7064 SMESH_MesherHelper aHelper(*myMesh);
7065 aHelper.SetIsQuadratic( true );
7066 const bool notFromGroups = false;
7068 int nbCheckedElems = 0;
7069 if ( myMesh->HasShapeToMesh() )
7071 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7073 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7074 while ( smIt->more() ) {
7075 SMESH_subMesh* sm = smIt->next();
7076 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7077 aHelper.SetSubShape( sm->GetSubShape() );
7078 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7083 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7084 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7086 SMESHDS_SubMesh *smDS = 0;
7087 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7088 while(aEdgeItr->more())
7090 const SMDS_MeshEdge* edge = aEdgeItr->next();
7091 if(edge && !edge->IsQuadratic())
7093 int id = edge->GetID();
7094 const SMDS_MeshNode* n1 = edge->GetNode(0);
7095 const SMDS_MeshNode* n2 = edge->GetNode(1);
7097 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7099 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7100 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7103 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7104 while(aFaceItr->more())
7106 const SMDS_MeshFace* face = aFaceItr->next();
7107 if(!face || face->IsQuadratic() ) continue;
7109 int id = face->GetID();
7110 int nbNodes = face->NbNodes();
7111 vector<const SMDS_MeshNode *> aNds (nbNodes);
7113 for(int i = 0; i < nbNodes; i++)
7115 aNds[i] = face->GetNode(i);
7118 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7120 SMDS_MeshFace * NewFace = 0;
7124 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7127 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7132 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7134 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7135 while(aVolumeItr->more())
7137 const SMDS_MeshVolume* volume = aVolumeItr->next();
7138 if(!volume || volume->IsQuadratic() ) continue;
7140 int id = volume->GetID();
7141 int nbNodes = volume->NbNodes();
7142 vector<const SMDS_MeshNode *> aNds (nbNodes);
7144 for(int i = 0; i < nbNodes; i++)
7146 aNds[i] = volume->GetNode(i);
7149 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7151 SMDS_MeshVolume * NewVolume = 0;
7155 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7156 aNds[3], id, theForce3d );
7159 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7160 aNds[3], aNds[4], aNds[5], id, theForce3d);
7163 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7164 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7169 ReplaceElemInGroups(volume, NewVolume, meshDS);
7174 //=======================================================================
7176 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7177 * \retval int - nb of checked elements
7179 //=======================================================================
7181 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7182 SMDS_ElemIteratorPtr theItr,
7183 const int theShapeID)
7186 SMESHDS_Mesh* meshDS = GetMeshDS();
7187 const bool notFromGroups = false;
7189 while( theItr->more() )
7191 const SMDS_MeshElement* elem = theItr->next();
7193 if( elem && elem->IsQuadratic())
7195 int id = elem->GetID();
7196 int nbNodes = elem->NbNodes();
7197 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7198 aNds.reserve( nbNodes );
7199 mediumNodes.reserve( nbNodes );
7201 for(int i = 0; i < nbNodes; i++)
7203 const SMDS_MeshNode* n = elem->GetNode(i);
7205 if( elem->IsMediumNode( n ) )
7206 mediumNodes.push_back( n );
7208 aNds.push_back( n );
7210 if( aNds.empty() ) continue;
7211 SMDSAbs_ElementType aType = elem->GetType();
7213 //remove old quadratic element
7214 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7216 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7217 ReplaceElemInGroups(elem, NewElem, meshDS);
7218 if( theSm && NewElem )
7219 theSm->AddElement( NewElem );
7221 // remove medium nodes
7222 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7223 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7224 const SMDS_MeshNode* n = *nIt;
7225 if ( n->NbInverseElements() == 0 ) {
7226 if ( n->GetPosition()->GetShapeId() != theShapeID )
7227 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7228 ( n->GetPosition()->GetShapeId() ));
7230 meshDS->RemoveFreeNode( n, theSm );
7238 //=======================================================================
7239 //function : ConvertFromQuadratic
7241 //=======================================================================
7242 bool SMESH_MeshEditor::ConvertFromQuadratic()
7244 int nbCheckedElems = 0;
7245 if ( myMesh->HasShapeToMesh() )
7247 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7249 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7250 while ( smIt->more() ) {
7251 SMESH_subMesh* sm = smIt->next();
7252 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7253 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7259 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7260 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7262 SMESHDS_SubMesh *aSM = 0;
7263 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7269 //=======================================================================
7270 //function : SewSideElements
7272 //=======================================================================
7274 SMESH_MeshEditor::Sew_Error
7275 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7276 TIDSortedElemSet& theSide2,
7277 const SMDS_MeshNode* theFirstNode1,
7278 const SMDS_MeshNode* theFirstNode2,
7279 const SMDS_MeshNode* theSecondNode1,
7280 const SMDS_MeshNode* theSecondNode2)
7282 myLastCreatedElems.Clear();
7283 myLastCreatedNodes.Clear();
7285 MESSAGE ("::::SewSideElements()");
7286 if ( theSide1.size() != theSide2.size() )
7287 return SEW_DIFF_NB_OF_ELEMENTS;
7289 Sew_Error aResult = SEW_OK;
7291 // 1. Build set of faces representing each side
7292 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7293 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7295 // =======================================================================
7296 // 1. Build set of faces representing each side:
7297 // =======================================================================
7298 // a. build set of nodes belonging to faces
7299 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7300 // c. create temporary faces representing side of volumes if correspondent
7301 // face does not exist
7303 SMESHDS_Mesh* aMesh = GetMeshDS();
7304 SMDS_Mesh aTmpFacesMesh;
7305 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7306 set<const SMDS_MeshElement*> volSet1, volSet2;
7307 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7308 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7309 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7310 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7311 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7312 int iSide, iFace, iNode;
7314 for ( iSide = 0; iSide < 2; iSide++ ) {
7315 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7316 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7317 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7318 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7319 set<const SMDS_MeshElement*>::iterator vIt;
7320 TIDSortedElemSet::iterator eIt;
7321 set<const SMDS_MeshNode*>::iterator nIt;
7323 // check that given nodes belong to given elements
7324 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7325 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7326 int firstIndex = -1, secondIndex = -1;
7327 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7328 const SMDS_MeshElement* elem = *eIt;
7329 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7330 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7331 if ( firstIndex > -1 && secondIndex > -1 ) break;
7333 if ( firstIndex < 0 || secondIndex < 0 ) {
7334 // we can simply return until temporary faces created
7335 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7338 // -----------------------------------------------------------
7339 // 1a. Collect nodes of existing faces
7340 // and build set of face nodes in order to detect missing
7341 // faces corresponing to sides of volumes
7342 // -----------------------------------------------------------
7344 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7346 // loop on the given element of a side
7347 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7348 //const SMDS_MeshElement* elem = *eIt;
7349 const SMDS_MeshElement* elem = *eIt;
7350 if ( elem->GetType() == SMDSAbs_Face ) {
7351 faceSet->insert( elem );
7352 set <const SMDS_MeshNode*> faceNodeSet;
7353 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7354 while ( nodeIt->more() ) {
7355 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7356 nodeSet->insert( n );
7357 faceNodeSet.insert( n );
7359 setOfFaceNodeSet.insert( faceNodeSet );
7361 else if ( elem->GetType() == SMDSAbs_Volume )
7362 volSet->insert( elem );
7364 // ------------------------------------------------------------------------------
7365 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7366 // ------------------------------------------------------------------------------
7368 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7369 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7370 while ( fIt->more() ) { // loop on faces sharing a node
7371 const SMDS_MeshElement* f = fIt->next();
7372 if ( faceSet->find( f ) == faceSet->end() ) {
7373 // check if all nodes are in nodeSet and
7374 // complete setOfFaceNodeSet if they are
7375 set <const SMDS_MeshNode*> faceNodeSet;
7376 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7377 bool allInSet = true;
7378 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7379 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7380 if ( nodeSet->find( n ) == nodeSet->end() )
7383 faceNodeSet.insert( n );
7386 faceSet->insert( f );
7387 setOfFaceNodeSet.insert( faceNodeSet );
7393 // -------------------------------------------------------------------------
7394 // 1c. Create temporary faces representing sides of volumes if correspondent
7395 // face does not exist
7396 // -------------------------------------------------------------------------
7398 if ( !volSet->empty() ) {
7399 //int nodeSetSize = nodeSet->size();
7401 // loop on given volumes
7402 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
7403 SMDS_VolumeTool vol (*vIt);
7404 // loop on volume faces: find free faces
7405 // --------------------------------------
7406 list<const SMDS_MeshElement* > freeFaceList;
7407 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
7408 if ( !vol.IsFreeFace( iFace ))
7410 // check if there is already a face with same nodes in a face set
7411 const SMDS_MeshElement* aFreeFace = 0;
7412 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
7413 int nbNodes = vol.NbFaceNodes( iFace );
7414 set <const SMDS_MeshNode*> faceNodeSet;
7415 vol.GetFaceNodes( iFace, faceNodeSet );
7416 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
7418 // no such a face is given but it still can exist, check it
7419 if ( nbNodes == 3 ) {
7420 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
7422 else if ( nbNodes == 4 ) {
7423 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7426 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7427 aFreeFace = aMesh->FindFace(poly_nodes);
7431 // create a temporary face
7432 if ( nbNodes == 3 ) {
7433 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
7435 else if ( nbNodes == 4 ) {
7436 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7439 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7440 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
7444 freeFaceList.push_back( aFreeFace );
7446 } // loop on faces of a volume
7448 // choose one of several free faces
7449 // --------------------------------------
7450 if ( freeFaceList.size() > 1 ) {
7451 // choose a face having max nb of nodes shared by other elems of a side
7452 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
7453 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
7454 while ( fIt != freeFaceList.end() ) { // loop on free faces
7455 int nbSharedNodes = 0;
7456 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7457 while ( nodeIt->more() ) { // loop on free face nodes
7458 const SMDS_MeshNode* n =
7459 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7460 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
7461 while ( invElemIt->more() ) {
7462 const SMDS_MeshElement* e = invElemIt->next();
7463 if ( faceSet->find( e ) != faceSet->end() )
7465 if ( elemSet->find( e ) != elemSet->end() )
7469 if ( nbSharedNodes >= maxNbNodes ) {
7470 maxNbNodes = nbSharedNodes;
7474 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
7476 if ( freeFaceList.size() > 1 )
7478 // could not choose one face, use another way
7479 // choose a face most close to the bary center of the opposite side
7480 gp_XYZ aBC( 0., 0., 0. );
7481 set <const SMDS_MeshNode*> addedNodes;
7482 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
7483 eIt = elemSet2->begin();
7484 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
7485 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
7486 while ( nodeIt->more() ) { // loop on free face nodes
7487 const SMDS_MeshNode* n =
7488 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7489 if ( addedNodes.insert( n ).second )
7490 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
7493 aBC /= addedNodes.size();
7494 double minDist = DBL_MAX;
7495 fIt = freeFaceList.begin();
7496 while ( fIt != freeFaceList.end() ) { // loop on free faces
7498 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7499 while ( nodeIt->more() ) { // loop on free face nodes
7500 const SMDS_MeshNode* n =
7501 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7502 gp_XYZ p( n->X(),n->Y(),n->Z() );
7503 dist += ( aBC - p ).SquareModulus();
7505 if ( dist < minDist ) {
7507 freeFaceList.erase( freeFaceList.begin(), fIt++ );
7510 fIt = freeFaceList.erase( fIt++ );
7513 } // choose one of several free faces of a volume
7515 if ( freeFaceList.size() == 1 ) {
7516 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
7517 faceSet->insert( aFreeFace );
7518 // complete a node set with nodes of a found free face
7519 // for ( iNode = 0; iNode < ; iNode++ )
7520 // nodeSet->insert( fNodes[ iNode ] );
7523 } // loop on volumes of a side
7525 // // complete a set of faces if new nodes in a nodeSet appeared
7526 // // ----------------------------------------------------------
7527 // if ( nodeSetSize != nodeSet->size() ) {
7528 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7529 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7530 // while ( fIt->more() ) { // loop on faces sharing a node
7531 // const SMDS_MeshElement* f = fIt->next();
7532 // if ( faceSet->find( f ) == faceSet->end() ) {
7533 // // check if all nodes are in nodeSet and
7534 // // complete setOfFaceNodeSet if they are
7535 // set <const SMDS_MeshNode*> faceNodeSet;
7536 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7537 // bool allInSet = true;
7538 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7539 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7540 // if ( nodeSet->find( n ) == nodeSet->end() )
7541 // allInSet = false;
7543 // faceNodeSet.insert( n );
7545 // if ( allInSet ) {
7546 // faceSet->insert( f );
7547 // setOfFaceNodeSet.insert( faceNodeSet );
7553 } // Create temporary faces, if there are volumes given
7556 if ( faceSet1.size() != faceSet2.size() ) {
7557 // delete temporary faces: they are in reverseElements of actual nodes
7558 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7559 while ( tmpFaceIt->more() )
7560 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7561 MESSAGE("Diff nb of faces");
7562 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7565 // ============================================================
7566 // 2. Find nodes to merge:
7567 // bind a node to remove to a node to put instead
7568 // ============================================================
7570 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
7571 if ( theFirstNode1 != theFirstNode2 )
7572 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
7573 if ( theSecondNode1 != theSecondNode2 )
7574 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
7576 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7577 set< long > linkIdSet; // links to process
7578 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
7580 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
7581 list< NLink > linkList[2];
7582 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7583 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7584 // loop on links in linkList; find faces by links and append links
7585 // of the found faces to linkList
7586 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7587 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7588 NLink link[] = { *linkIt[0], *linkIt[1] };
7589 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
7590 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
7593 // by links, find faces in the face sets,
7594 // and find indices of link nodes in the found faces;
7595 // in a face set, there is only one or no face sharing a link
7596 // ---------------------------------------------------------------
7598 const SMDS_MeshElement* face[] = { 0, 0 };
7599 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
7600 vector<const SMDS_MeshNode*> fnodes1(9);
7601 vector<const SMDS_MeshNode*> fnodes2(9);
7602 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
7603 vector<const SMDS_MeshNode*> notLinkNodes1(6);
7604 vector<const SMDS_MeshNode*> notLinkNodes2(6);
7605 int iLinkNode[2][2];
7606 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7607 const SMDS_MeshNode* n1 = link[iSide].first;
7608 const SMDS_MeshNode* n2 = link[iSide].second;
7609 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7610 set< const SMDS_MeshElement* > fMap;
7611 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
7612 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
7613 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7614 while ( fIt->more() ) { // loop on faces sharing a node
7615 const SMDS_MeshElement* f = fIt->next();
7616 if (faceSet->find( f ) != faceSet->end() && // f is in face set
7617 ! fMap.insert( f ).second ) // f encounters twice
7619 if ( face[ iSide ] ) {
7620 MESSAGE( "2 faces per link " );
7621 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
7625 faceSet->erase( f );
7626 // get face nodes and find ones of a link
7631 fnodes1.resize(f->NbNodes()+1);
7632 notLinkNodes1.resize(f->NbNodes()-2);
7635 fnodes2.resize(f->NbNodes()+1);
7636 notLinkNodes2.resize(f->NbNodes()-2);
7639 if(!f->IsQuadratic()) {
7640 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
7641 while ( nIt->more() ) {
7642 const SMDS_MeshNode* n =
7643 static_cast<const SMDS_MeshNode*>( nIt->next() );
7645 iLinkNode[ iSide ][ 0 ] = iNode;
7647 else if ( n == n2 ) {
7648 iLinkNode[ iSide ][ 1 ] = iNode;
7650 //else if ( notLinkNodes[ iSide ][ 0 ] )
7651 // notLinkNodes[ iSide ][ 1 ] = n;
7653 // notLinkNodes[ iSide ][ 0 ] = n;
7657 notLinkNodes1[nbl] = n;
7658 //notLinkNodes1.push_back(n);
7660 notLinkNodes2[nbl] = n;
7661 //notLinkNodes2.push_back(n);
7663 //faceNodes[ iSide ][ iNode++ ] = n;
7665 fnodes1[iNode++] = n;
7668 fnodes2[iNode++] = n;
7672 else { // f->IsQuadratic()
7673 const SMDS_QuadraticFaceOfNodes* F =
7674 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
7675 // use special nodes iterator
7676 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7677 while ( anIter->more() ) {
7678 const SMDS_MeshNode* n =
7679 static_cast<const SMDS_MeshNode*>( anIter->next() );
7681 iLinkNode[ iSide ][ 0 ] = iNode;
7683 else if ( n == n2 ) {
7684 iLinkNode[ iSide ][ 1 ] = iNode;
7689 notLinkNodes1[nbl] = n;
7692 notLinkNodes2[nbl] = n;
7696 fnodes1[iNode++] = n;
7699 fnodes2[iNode++] = n;
7703 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
7705 fnodes1[iNode] = fnodes1[0];
7708 fnodes2[iNode] = fnodes1[0];
7715 // check similarity of elements of the sides
7716 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7717 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7718 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7719 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7722 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7724 break; // do not return because it s necessary to remove tmp faces
7727 // set nodes to merge
7728 // -------------------
7730 if ( face[0] && face[1] ) {
7731 int nbNodes = face[0]->NbNodes();
7732 if ( nbNodes != face[1]->NbNodes() ) {
7733 MESSAGE("Diff nb of face nodes");
7734 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7735 break; // do not return because it s necessary to remove tmp faces
7737 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
7738 if ( nbNodes == 3 ) {
7739 //nReplaceMap.insert( TNodeNodeMap::value_type
7740 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7741 nReplaceMap.insert( TNodeNodeMap::value_type
7742 ( notLinkNodes1[0], notLinkNodes2[0] ));
7745 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7746 // analyse link orientation in faces
7747 int i1 = iLinkNode[ iSide ][ 0 ];
7748 int i2 = iLinkNode[ iSide ][ 1 ];
7749 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
7750 // if notLinkNodes are the first and the last ones, then
7751 // their order does not correspond to the link orientation
7752 if (( i1 == 1 && i2 == 2 ) ||
7753 ( i1 == 2 && i2 == 1 ))
7754 reverse[ iSide ] = !reverse[ iSide ];
7756 if ( reverse[0] == reverse[1] ) {
7757 //nReplaceMap.insert( TNodeNodeMap::value_type
7758 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7759 //nReplaceMap.insert( TNodeNodeMap::value_type
7760 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
7761 for(int nn=0; nn<nbNodes-2; nn++) {
7762 nReplaceMap.insert( TNodeNodeMap::value_type
7763 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
7767 //nReplaceMap.insert( TNodeNodeMap::value_type
7768 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
7769 //nReplaceMap.insert( TNodeNodeMap::value_type
7770 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
7771 for(int nn=0; nn<nbNodes-2; nn++) {
7772 nReplaceMap.insert( TNodeNodeMap::value_type
7773 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
7778 // add other links of the faces to linkList
7779 // -----------------------------------------
7781 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
7782 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7783 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
7784 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
7785 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
7786 if ( !iter_isnew.second ) { // already in a set: no need to process
7787 linkIdSet.erase( iter_isnew.first );
7789 else // new in set == encountered for the first time: add
7791 //const SMDS_MeshNode* n1 = nodes[ iNode ];
7792 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
7793 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
7794 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
7795 linkList[0].push_back ( NLink( n1, n2 ));
7796 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7800 } // loop on link lists
7802 if ( aResult == SEW_OK &&
7803 ( linkIt[0] != linkList[0].end() ||
7804 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
7805 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
7806 " " << (faceSetPtr[1]->empty()));
7807 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7810 // ====================================================================
7811 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7812 // ====================================================================
7814 // delete temporary faces: they are in reverseElements of actual nodes
7815 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7816 while ( tmpFaceIt->more() )
7817 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7819 if ( aResult != SEW_OK)
7822 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
7823 // loop on nodes replacement map
7824 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
7825 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
7826 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
7827 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
7828 nodeIDsToRemove.push_back( nToRemove->GetID() );
7829 // loop on elements sharing nToRemove
7830 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7831 while ( invElemIt->more() ) {
7832 const SMDS_MeshElement* e = invElemIt->next();
7833 // get a new suite of nodes: make replacement
7834 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
7835 vector< const SMDS_MeshNode*> nodes( nbNodes );
7836 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7837 while ( nIt->more() ) {
7838 const SMDS_MeshNode* n =
7839 static_cast<const SMDS_MeshNode*>( nIt->next() );
7840 nnIt = nReplaceMap.find( n );
7841 if ( nnIt != nReplaceMap.end() ) {
7847 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
7848 // elemIDsToRemove.push_back( e->GetID() );
7851 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
7855 Remove( nodeIDsToRemove, true );
7860 //================================================================================
7862 * \brief Find corresponding nodes in two sets of faces
7863 * \param theSide1 - first face set
7864 * \param theSide2 - second first face
7865 * \param theFirstNode1 - a boundary node of set 1
7866 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
7867 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
7868 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
7869 * \param nReplaceMap - output map of corresponding nodes
7870 * \retval bool - is a success or not
7872 //================================================================================
7875 //#define DEBUG_MATCHING_NODES
7878 SMESH_MeshEditor::Sew_Error
7879 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
7880 set<const SMDS_MeshElement*>& theSide2,
7881 const SMDS_MeshNode* theFirstNode1,
7882 const SMDS_MeshNode* theFirstNode2,
7883 const SMDS_MeshNode* theSecondNode1,
7884 const SMDS_MeshNode* theSecondNode2,
7885 TNodeNodeMap & nReplaceMap)
7887 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
7889 nReplaceMap.clear();
7890 if ( theFirstNode1 != theFirstNode2 )
7891 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
7892 if ( theSecondNode1 != theSecondNode2 )
7893 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
7895 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
7896 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
7898 list< NLink > linkList[2];
7899 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7900 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7902 // loop on links in linkList; find faces by links and append links
7903 // of the found faces to linkList
7904 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7905 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7906 NLink link[] = { *linkIt[0], *linkIt[1] };
7907 if ( linkSet.find( link[0] ) == linkSet.end() )
7910 // by links, find faces in the face sets,
7911 // and find indices of link nodes in the found faces;
7912 // in a face set, there is only one or no face sharing a link
7913 // ---------------------------------------------------------------
7915 const SMDS_MeshElement* face[] = { 0, 0 };
7916 list<const SMDS_MeshNode*> notLinkNodes[2];
7917 //bool reverse[] = { false, false }; // order of notLinkNodes
7919 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
7921 const SMDS_MeshNode* n1 = link[iSide].first;
7922 const SMDS_MeshNode* n2 = link[iSide].second;
7923 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7924 set< const SMDS_MeshElement* > facesOfNode1;
7925 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
7927 // during a loop of the first node, we find all faces around n1,
7928 // during a loop of the second node, we find one face sharing both n1 and n2
7929 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
7930 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7931 while ( fIt->more() ) { // loop on faces sharing a node
7932 const SMDS_MeshElement* f = fIt->next();
7933 if (faceSet->find( f ) != faceSet->end() && // f is in face set
7934 ! facesOfNode1.insert( f ).second ) // f encounters twice
7936 if ( face[ iSide ] ) {
7937 MESSAGE( "2 faces per link " );
7938 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7941 faceSet->erase( f );
7943 // get not link nodes
7944 int nbN = f->NbNodes();
7945 if ( f->IsQuadratic() )
7947 nbNodes[ iSide ] = nbN;
7948 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
7949 int i1 = f->GetNodeIndex( n1 );
7950 int i2 = f->GetNodeIndex( n2 );
7951 int iEnd = nbN, iBeg = -1, iDelta = 1;
7952 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
7954 std::swap( iEnd, iBeg ); iDelta = -1;
7959 if ( i == iEnd ) i = iBeg + iDelta;
7960 if ( i == i1 ) break;
7961 nodes.push_back ( f->GetNode( i ) );
7967 // check similarity of elements of the sides
7968 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7969 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7970 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7971 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7974 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7978 // set nodes to merge
7979 // -------------------
7981 if ( face[0] && face[1] ) {
7982 if ( nbNodes[0] != nbNodes[1] ) {
7983 MESSAGE("Diff nb of face nodes");
7984 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7986 #ifdef DEBUG_MATCHING_NODES
7987 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
7988 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
7989 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
7991 int nbN = nbNodes[0];
7993 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
7994 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
7995 for ( int i = 0 ; i < nbN - 2; ++i ) {
7996 #ifdef DEBUG_MATCHING_NODES
7997 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
7999 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8003 // add other links of the face 1 to linkList
8004 // -----------------------------------------
8006 const SMDS_MeshElement* f0 = face[0];
8007 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8008 for ( int i = 0; i < nbN; i++ )
8010 const SMDS_MeshNode* n2 = f0->GetNode( i );
8011 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8012 linkSet.insert( SMESH_TLink( n1, n2 ));
8013 if ( !iter_isnew.second ) { // already in a set: no need to process
8014 linkSet.erase( iter_isnew.first );
8016 else // new in set == encountered for the first time: add
8018 #ifdef DEBUG_MATCHING_NODES
8019 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8020 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8022 linkList[0].push_back ( NLink( n1, n2 ));
8023 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8028 } // loop on link lists
8034 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8035 \param theNodes - identifiers of nodes to be doubled
8036 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
8037 nodes. If list of element identifiers is empty then nodes are doubled but
8038 they not assigned to elements
8039 \return TRUE if operation has been completed successfully, FALSE otherwise
8041 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
8042 const std::list< int >& theListOfModifiedElems )
8044 myLastCreatedElems.Clear();
8045 myLastCreatedNodes.Clear();
8047 if ( theListOfNodes.size() == 0 )
8050 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8054 // iterate through nodes and duplicate them
8056 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8058 std::list< int >::const_iterator aNodeIter;
8059 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8061 int aCurr = *aNodeIter;
8062 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8068 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8071 anOldNodeToNewNode[ aNode ] = aNewNode;
8072 myLastCreatedNodes.Append( aNewNode );
8076 // Create map of new nodes for modified elements
8078 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8080 std::list< int >::const_iterator anElemIter;
8081 for ( anElemIter = theListOfModifiedElems.begin();
8082 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8084 int aCurr = *anElemIter;
8085 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8089 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8091 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8093 while ( anIter->more() )
8095 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8096 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8098 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8099 aNodeArr[ ind++ ] = aNewNode;
8102 aNodeArr[ ind++ ] = aCurrNode;
8104 anElemToNodes[ anElem ] = aNodeArr;
8107 // Change nodes of elements
8109 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8110 anElemToNodesIter = anElemToNodes.begin();
8111 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8113 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8114 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8116 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );