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>
50 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <Extrema_GenExtPS.hxx>
53 #include <Extrema_POnSurf.hxx>
54 #include <Geom2d_Curve.hxx>
55 #include <GeomAdaptor_Surface.hxx>
56 #include <Geom_Curve.hxx>
57 #include <Geom_Surface.hxx>
58 #include <Precision.hxx>
59 #include <TColStd_ListOfInteger.hxx>
60 #include <TopAbs_State.hxx>
62 #include <TopExp_Explorer.hxx>
63 #include <TopTools_ListIteratorOfListOfShape.hxx>
64 #include <TopTools_ListOfShape.hxx>
65 #include <TopTools_SequenceOfShape.hxx>
67 #include <TopoDS_Face.hxx>
73 #include <gp_Trsf.hxx>
82 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
85 using namespace SMESH::Controls;
87 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
88 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
89 //typedef map<const SMDS_MeshNode*, vector<const SMDS_MeshNode*> > TNodeOfNodeVecMap;
90 //typedef TNodeOfNodeVecMap::iterator TNodeOfNodeVecMapItr;
91 //typedef map<const SMDS_MeshElement*, vector<TNodeOfNodeVecMapItr> > TElemOfVecOfMapNodesMap;
93 struct TNodeXYZ : public gp_XYZ {
94 TNodeXYZ( const SMDS_MeshNode* n ):gp_XYZ( n->X(), n->Y(), n->Z() ) {}
97 //=======================================================================
98 //function : SMESH_MeshEditor
100 //=======================================================================
102 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
103 :myMesh( theMesh ) // theMesh may be NULL
107 //=======================================================================
111 //=======================================================================
114 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
115 const SMDSAbs_ElementType type,
119 SMDS_MeshElement* e = 0;
120 int nbnode = node.size();
121 SMESHDS_Mesh* mesh = GetMeshDS();
125 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
126 else e = mesh->AddEdge (node[0], node[1] );
127 else if ( nbnode == 3 )
128 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
129 else e = mesh->AddEdge (node[0], node[1], node[2] );
134 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
135 else e = mesh->AddFace (node[0], node[1], node[2] );
136 else if (nbnode == 4)
137 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
138 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
139 else if (nbnode == 6)
140 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
141 node[4], node[5], ID);
142 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
144 else if (nbnode == 8)
145 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
146 node[4], node[5], node[6], node[7], ID);
147 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
148 node[4], node[5], node[6], node[7] );
150 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
151 else e = mesh->AddPolygonalFace (node );
157 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
158 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
159 else if (nbnode == 5)
160 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
162 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
164 else if (nbnode == 6)
165 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
166 node[4], node[5], ID);
167 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
169 else if (nbnode == 8)
170 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171 node[4], node[5], node[6], node[7], ID);
172 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
173 node[4], node[5], node[6], node[7] );
174 else if (nbnode == 10)
175 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176 node[4], node[5], node[6], node[7],
177 node[8], node[9], ID);
178 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
179 node[4], node[5], node[6], node[7],
181 else if (nbnode == 13)
182 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7],
184 node[8], node[9], node[10],node[11],
186 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7],
188 node[8], node[9], node[10],node[11],
190 else if (nbnode == 15)
191 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
193 node[8], node[9], node[10],node[11],
194 node[12],node[13],node[14],ID);
195 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7],
197 node[8], node[9], node[10],node[11],
198 node[12],node[13],node[14] );
199 else if (nbnode == 20)
200 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
203 node[12],node[13],node[14],node[15],
204 node[16],node[17],node[18],node[19],ID);
205 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
206 node[4], node[5], node[6], node[7],
207 node[8], node[9], node[10],node[11],
208 node[12],node[13],node[14],node[15],
209 node[16],node[17],node[18],node[19] );
215 //=======================================================================
219 //=======================================================================
221 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
222 const SMDSAbs_ElementType type,
226 vector<const SMDS_MeshNode*> nodes;
227 nodes.reserve( nodeIDs.size() );
228 vector<int>::const_iterator id = nodeIDs.begin();
229 while ( id != nodeIDs.end() ) {
230 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
231 nodes.push_back( node );
235 return AddElement( nodes, type, isPoly, ID );
238 //=======================================================================
240 //purpose : Remove a node or an element.
241 // Modify a compute state of sub-meshes which become empty
242 //=======================================================================
244 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
247 myLastCreatedElems.Clear();
248 myLastCreatedNodes.Clear();
250 SMESHDS_Mesh* aMesh = GetMeshDS();
251 set< SMESH_subMesh *> smmap;
253 list<int>::const_iterator it = theIDs.begin();
254 for ( ; it != theIDs.end(); it++ ) {
255 const SMDS_MeshElement * elem;
257 elem = aMesh->FindNode( *it );
259 elem = aMesh->FindElement( *it );
263 // Notify VERTEX sub-meshes about modification
265 const SMDS_MeshNode* node = cast2Node( elem );
266 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
267 if ( int aShapeID = node->GetPosition()->GetShapeId() )
268 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
271 // Find sub-meshes to notify about modification
272 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
273 // while ( nodeIt->more() ) {
274 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
275 // const SMDS_PositionPtr& aPosition = node->GetPosition();
276 // if ( aPosition.get() ) {
277 // if ( int aShapeID = aPosition->GetShapeId() ) {
278 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
279 // smmap.insert( sm );
286 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
288 aMesh->RemoveElement( elem );
291 // Notify sub-meshes about modification
292 if ( !smmap.empty() ) {
293 set< SMESH_subMesh *>::iterator smIt;
294 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
295 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
298 // // Check if the whole mesh becomes empty
299 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
300 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
305 //=======================================================================
306 //function : FindShape
307 //purpose : Return an index of the shape theElem is on
308 // or zero if a shape not found
309 //=======================================================================
311 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
313 myLastCreatedElems.Clear();
314 myLastCreatedNodes.Clear();
316 SMESHDS_Mesh * aMesh = GetMeshDS();
317 if ( aMesh->ShapeToMesh().IsNull() )
320 if ( theElem->GetType() == SMDSAbs_Node ) {
321 const SMDS_PositionPtr& aPosition =
322 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
323 if ( aPosition.get() )
324 return aPosition->GetShapeId();
329 TopoDS_Shape aShape; // the shape a node is on
330 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
331 while ( nodeIt->more() ) {
332 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
333 const SMDS_PositionPtr& aPosition = node->GetPosition();
334 if ( aPosition.get() ) {
335 int aShapeID = aPosition->GetShapeId();
336 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
338 if ( sm->Contains( theElem ))
340 if ( aShape.IsNull() )
341 aShape = aMesh->IndexToShape( aShapeID );
344 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
349 // None of nodes is on a proper shape,
350 // find the shape among ancestors of aShape on which a node is
351 if ( aShape.IsNull() ) {
352 //MESSAGE ("::FindShape() - NONE node is on shape")
355 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
356 for ( ; ancIt.More(); ancIt.Next() ) {
357 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
358 if ( sm && sm->Contains( theElem ))
359 return aMesh->ShapeToIndex( ancIt.Value() );
362 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
366 //=======================================================================
367 //function : IsMedium
369 //=======================================================================
371 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
372 const SMDSAbs_ElementType typeToCheck)
374 bool isMedium = false;
375 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
376 while (it->more() && !isMedium ) {
377 const SMDS_MeshElement* elem = it->next();
378 isMedium = elem->IsMediumNode(node);
383 //=======================================================================
384 //function : ShiftNodesQuadTria
386 // Shift nodes in the array corresponded to quadratic triangle
387 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
388 //=======================================================================
389 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
391 const SMDS_MeshNode* nd1 = aNodes[0];
392 aNodes[0] = aNodes[1];
393 aNodes[1] = aNodes[2];
395 const SMDS_MeshNode* nd2 = aNodes[3];
396 aNodes[3] = aNodes[4];
397 aNodes[4] = aNodes[5];
401 //=======================================================================
402 //function : GetNodesFromTwoTria
404 // Shift nodes in the array corresponded to quadratic triangle
405 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
406 //=======================================================================
407 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
408 const SMDS_MeshElement * theTria2,
409 const SMDS_MeshNode* N1[],
410 const SMDS_MeshNode* N2[])
412 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
415 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
418 if(it->more()) return false;
419 it = theTria2->nodesIterator();
422 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
425 if(it->more()) return false;
427 int sames[3] = {-1,-1,-1};
439 if(nbsames!=2) return false;
441 ShiftNodesQuadTria(N1);
443 ShiftNodesQuadTria(N1);
446 i = sames[0] + sames[1] + sames[2];
448 ShiftNodesQuadTria(N2);
450 // now we receive following N1 and N2 (using numeration as above image)
451 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
452 // i.e. first nodes from both arrays determ new diagonal
456 //=======================================================================
457 //function : InverseDiag
458 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
459 // but having other common link.
460 // Return False if args are improper
461 //=======================================================================
463 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
464 const SMDS_MeshElement * theTria2 )
466 myLastCreatedElems.Clear();
467 myLastCreatedNodes.Clear();
469 if (!theTria1 || !theTria2)
472 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
473 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
476 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
477 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
481 // put nodes in array and find out indices of the same ones
482 const SMDS_MeshNode* aNodes [6];
483 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
485 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
486 while ( it->more() ) {
487 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
489 if ( i > 2 ) // theTria2
490 // find same node of theTria1
491 for ( int j = 0; j < 3; j++ )
492 if ( aNodes[ i ] == aNodes[ j ]) {
501 return false; // theTria1 is not a triangle
502 it = theTria2->nodesIterator();
504 if ( i == 6 && it->more() )
505 return false; // theTria2 is not a triangle
508 // find indices of 1,2 and of A,B in theTria1
509 int iA = 0, iB = 0, i1 = 0, i2 = 0;
510 for ( i = 0; i < 6; i++ ) {
511 if ( sameInd [ i ] == 0 )
518 // nodes 1 and 2 should not be the same
519 if ( aNodes[ i1 ] == aNodes[ i2 ] )
523 aNodes[ iA ] = aNodes[ i2 ];
525 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
527 //MESSAGE( theTria1 << theTria2 );
529 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
530 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
532 //MESSAGE( theTria1 << theTria2 );
536 } // end if(F1 && F2)
538 // check case of quadratic faces
539 const SMDS_QuadraticFaceOfNodes* QF1 =
540 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
541 if(!QF1) return false;
542 const SMDS_QuadraticFaceOfNodes* QF2 =
543 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
544 if(!QF2) return false;
547 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
548 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
556 const SMDS_MeshNode* N1 [6];
557 const SMDS_MeshNode* N2 [6];
558 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
560 // now we receive following N1 and N2 (using numeration as above image)
561 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
562 // i.e. first nodes from both arrays determ new diagonal
564 const SMDS_MeshNode* N1new [6];
565 const SMDS_MeshNode* N2new [6];
578 // replaces nodes in faces
579 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
580 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
585 //=======================================================================
586 //function : findTriangles
587 //purpose : find triangles sharing theNode1-theNode2 link
588 //=======================================================================
590 static bool findTriangles(const SMDS_MeshNode * theNode1,
591 const SMDS_MeshNode * theNode2,
592 const SMDS_MeshElement*& theTria1,
593 const SMDS_MeshElement*& theTria2)
595 if ( !theNode1 || !theNode2 ) return false;
597 theTria1 = theTria2 = 0;
599 set< const SMDS_MeshElement* > emap;
600 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
602 const SMDS_MeshElement* elem = it->next();
603 if ( elem->NbNodes() == 3 )
606 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
608 const SMDS_MeshElement* elem = it->next();
609 if ( emap.find( elem ) != emap.end() )
611 // theTria1 must be element with minimum ID
612 if( theTria1->GetID() < elem->GetID() ) {
625 return ( theTria1 && theTria2 );
628 //=======================================================================
629 //function : InverseDiag
630 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
631 // with ones built on the same 4 nodes but having other common link.
632 // Return false if proper faces not found
633 //=======================================================================
635 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
636 const SMDS_MeshNode * theNode2)
638 myLastCreatedElems.Clear();
639 myLastCreatedNodes.Clear();
641 MESSAGE( "::InverseDiag()" );
643 const SMDS_MeshElement *tr1, *tr2;
644 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
647 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
648 //if (!F1) return false;
649 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
650 //if (!F2) return false;
653 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
654 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
658 // put nodes in array
659 // and find indices of 1,2 and of A in tr1 and of B in tr2
660 int i, iA1 = 0, i1 = 0;
661 const SMDS_MeshNode* aNodes1 [3];
662 SMDS_ElemIteratorPtr it;
663 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
664 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
665 if ( aNodes1[ i ] == theNode1 )
666 iA1 = i; // node A in tr1
667 else if ( aNodes1[ i ] != theNode2 )
671 const SMDS_MeshNode* aNodes2 [3];
672 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
673 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
674 if ( aNodes2[ i ] == theNode2 )
675 iB2 = i; // node B in tr2
676 else if ( aNodes2[ i ] != theNode1 )
680 // nodes 1 and 2 should not be the same
681 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
685 aNodes1[ iA1 ] = aNodes2[ i2 ];
687 aNodes2[ iB2 ] = aNodes1[ i1 ];
689 //MESSAGE( tr1 << tr2 );
691 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
692 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
694 //MESSAGE( tr1 << tr2 );
699 // check case of quadratic faces
700 const SMDS_QuadraticFaceOfNodes* QF1 =
701 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
702 if(!QF1) return false;
703 const SMDS_QuadraticFaceOfNodes* QF2 =
704 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
705 if(!QF2) return false;
706 return InverseDiag(tr1,tr2);
709 //=======================================================================
710 //function : getQuadrangleNodes
711 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
712 // fusion of triangles tr1 and tr2 having shared link on
713 // theNode1 and theNode2
714 //=======================================================================
716 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
717 const SMDS_MeshNode * theNode1,
718 const SMDS_MeshNode * theNode2,
719 const SMDS_MeshElement * tr1,
720 const SMDS_MeshElement * tr2 )
722 if( tr1->NbNodes() != tr2->NbNodes() )
724 // find the 4-th node to insert into tr1
725 const SMDS_MeshNode* n4 = 0;
726 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
728 while ( !n4 && i<3 ) {
729 const SMDS_MeshNode * n = cast2Node( it->next() );
731 bool isDiag = ( n == theNode1 || n == theNode2 );
735 // Make an array of nodes to be in a quadrangle
736 int iNode = 0, iFirstDiag = -1;
737 it = tr1->nodesIterator();
740 const SMDS_MeshNode * n = cast2Node( it->next() );
742 bool isDiag = ( n == theNode1 || n == theNode2 );
744 if ( iFirstDiag < 0 )
746 else if ( iNode - iFirstDiag == 1 )
747 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
749 else if ( n == n4 ) {
750 return false; // tr1 and tr2 should not have all the same nodes
752 theQuadNodes[ iNode++ ] = n;
754 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
755 theQuadNodes[ iNode ] = n4;
760 //=======================================================================
761 //function : DeleteDiag
762 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
763 // with a quadrangle built on the same 4 nodes.
764 // Return false if proper faces not found
765 //=======================================================================
767 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
768 const SMDS_MeshNode * theNode2)
770 myLastCreatedElems.Clear();
771 myLastCreatedNodes.Clear();
773 MESSAGE( "::DeleteDiag()" );
775 const SMDS_MeshElement *tr1, *tr2;
776 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
779 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
780 //if (!F1) return false;
781 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
782 //if (!F2) return false;
785 const SMDS_MeshNode* aNodes [ 4 ];
786 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
789 //MESSAGE( endl << tr1 << tr2 );
791 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
792 myLastCreatedElems.Append(tr1);
793 GetMeshDS()->RemoveElement( tr2 );
795 //MESSAGE( endl << tr1 );
800 // check case of quadratic faces
801 const SMDS_QuadraticFaceOfNodes* QF1 =
802 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
803 if(!QF1) return false;
804 const SMDS_QuadraticFaceOfNodes* QF2 =
805 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
806 if(!QF2) return false;
809 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
810 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
818 const SMDS_MeshNode* N1 [6];
819 const SMDS_MeshNode* N2 [6];
820 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
822 // now we receive following N1 and N2 (using numeration as above image)
823 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
824 // i.e. first nodes from both arrays determ new diagonal
826 const SMDS_MeshNode* aNodes[8];
836 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
837 myLastCreatedElems.Append(tr1);
838 GetMeshDS()->RemoveElement( tr2 );
840 // remove middle node (9)
841 GetMeshDS()->RemoveNode( N1[4] );
846 //=======================================================================
847 //function : Reorient
848 //purpose : Reverse theElement orientation
849 //=======================================================================
851 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
853 myLastCreatedElems.Clear();
854 myLastCreatedNodes.Clear();
858 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
859 if ( !it || !it->more() )
862 switch ( theElem->GetType() ) {
866 if(!theElem->IsQuadratic()) {
867 int i = theElem->NbNodes();
868 vector<const SMDS_MeshNode*> aNodes( i );
870 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
871 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
874 // quadratic elements
875 if(theElem->GetType()==SMDSAbs_Edge) {
876 vector<const SMDS_MeshNode*> aNodes(3);
877 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
878 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
879 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
880 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
883 int nbn = theElem->NbNodes();
884 vector<const SMDS_MeshNode*> aNodes(nbn);
885 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
887 for(; i<nbn/2; i++) {
888 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
890 for(i=0; i<nbn/2; i++) {
891 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
893 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
897 case SMDSAbs_Volume: {
898 if (theElem->IsPoly()) {
899 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
900 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
902 MESSAGE("Warning: bad volumic element");
906 int nbFaces = aPolyedre->NbFaces();
907 vector<const SMDS_MeshNode *> poly_nodes;
908 vector<int> quantities (nbFaces);
910 // reverse each face of the polyedre
911 for (int iface = 1; iface <= nbFaces; iface++) {
912 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
913 quantities[iface - 1] = nbFaceNodes;
915 for (inode = nbFaceNodes; inode >= 1; inode--) {
916 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
917 poly_nodes.push_back(curNode);
921 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
925 SMDS_VolumeTool vTool;
926 if ( !vTool.Set( theElem ))
929 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
938 //=======================================================================
939 //function : getBadRate
941 //=======================================================================
943 static double getBadRate (const SMDS_MeshElement* theElem,
944 SMESH::Controls::NumericalFunctorPtr& theCrit)
946 SMESH::Controls::TSequenceOfXYZ P;
947 if ( !theElem || !theCrit->GetPoints( theElem, P ))
949 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
950 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
953 //=======================================================================
954 //function : QuadToTri
955 //purpose : Cut quadrangles into triangles.
956 // theCrit is used to select a diagonal to cut
957 //=======================================================================
959 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
960 SMESH::Controls::NumericalFunctorPtr theCrit)
962 myLastCreatedElems.Clear();
963 myLastCreatedNodes.Clear();
965 MESSAGE( "::QuadToTri()" );
967 if ( !theCrit.get() )
970 SMESHDS_Mesh * aMesh = GetMeshDS();
972 Handle(Geom_Surface) surface;
973 SMESH_MesherHelper helper( *GetMesh() );
975 TIDSortedElemSet::iterator itElem;
976 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
977 const SMDS_MeshElement* elem = *itElem;
978 if ( !elem || elem->GetType() != SMDSAbs_Face )
980 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
983 // retrieve element nodes
984 const SMDS_MeshNode* aNodes [8];
985 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
987 while ( itN->more() )
988 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
990 // compare two sets of possible triangles
991 double aBadRate1, aBadRate2; // to what extent a set is bad
992 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
993 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
994 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
996 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
997 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
998 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1000 int aShapeId = FindShape( elem );
1001 const SMDS_MeshElement* newElem = 0;
1003 if( !elem->IsQuadratic() ) {
1005 // split liner quadrangle
1007 if ( aBadRate1 <= aBadRate2 ) {
1008 // tr1 + tr2 is better
1009 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1010 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1013 // tr3 + tr4 is better
1014 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1015 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1020 // split quadratic quadrangle
1022 // get surface elem is on
1023 if ( aShapeId != helper.GetSubShapeID() ) {
1027 shape = aMesh->IndexToShape( aShapeId );
1028 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1029 TopoDS_Face face = TopoDS::Face( shape );
1030 surface = BRep_Tool::Surface( face );
1031 if ( !surface.IsNull() )
1032 helper.SetSubShape( shape );
1036 const SMDS_MeshNode* aNodes [8];
1037 const SMDS_MeshNode* inFaceNode = 0;
1038 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1040 while ( itN->more() ) {
1041 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1042 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1043 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1045 inFaceNode = aNodes[ i-1 ];
1048 // find middle point for (0,1,2,3)
1049 // and create a node in this point;
1051 if ( surface.IsNull() ) {
1053 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1057 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1060 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1062 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1064 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1065 myLastCreatedNodes.Append(newN);
1067 // create a new element
1068 const SMDS_MeshNode* N[6];
1069 if ( aBadRate1 <= aBadRate2 ) {
1076 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1077 aNodes[6], aNodes[7], newN );
1086 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1087 aNodes[7], aNodes[4], newN );
1089 aMesh->ChangeElementNodes( elem, N, 6 );
1093 // care of a new element
1095 myLastCreatedElems.Append(newElem);
1096 AddToSameGroups( newElem, elem, aMesh );
1098 // put a new triangle on the same shape
1100 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1105 //=======================================================================
1106 //function : BestSplit
1107 //purpose : Find better diagonal for cutting.
1108 //=======================================================================
1109 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1110 SMESH::Controls::NumericalFunctorPtr theCrit)
1112 myLastCreatedElems.Clear();
1113 myLastCreatedNodes.Clear();
1118 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1121 if( theQuad->NbNodes()==4 ||
1122 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1124 // retrieve element nodes
1125 const SMDS_MeshNode* aNodes [4];
1126 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1128 //while (itN->more())
1130 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1132 // compare two sets of possible triangles
1133 double aBadRate1, aBadRate2; // to what extent a set is bad
1134 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1135 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1136 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1138 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1139 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1140 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1142 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1143 return 1; // diagonal 1-3
1145 return 2; // diagonal 2-4
1150 //=======================================================================
1151 //function : AddToSameGroups
1152 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1153 //=======================================================================
1155 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1156 const SMDS_MeshElement* elemInGroups,
1157 SMESHDS_Mesh * aMesh)
1159 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1160 if (!groups.empty()) {
1161 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1162 for ( ; grIt != groups.end(); grIt++ ) {
1163 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1164 if ( group && group->Contains( elemInGroups ))
1165 group->SMDSGroup().Add( elemToAdd );
1171 //=======================================================================
1172 //function : RemoveElemFromGroups
1173 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1174 //=======================================================================
1175 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1176 SMESHDS_Mesh * aMesh)
1178 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1179 if (!groups.empty())
1181 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1182 for (; GrIt != groups.end(); GrIt++)
1184 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1185 if (!grp || grp->IsEmpty()) continue;
1186 grp->SMDSGroup().Remove(removeelem);
1191 //=======================================================================
1192 //function : ReplaceElemInGroups
1193 //purpose : replace elemToRm by elemToAdd in the all groups
1194 //=======================================================================
1196 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1197 const SMDS_MeshElement* elemToAdd,
1198 SMESHDS_Mesh * aMesh)
1200 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1201 if (!groups.empty()) {
1202 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1203 for ( ; grIt != groups.end(); grIt++ ) {
1204 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1205 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1206 group->SMDSGroup().Add( elemToAdd );
1211 //=======================================================================
1212 //function : QuadToTri
1213 //purpose : Cut quadrangles into triangles.
1214 // theCrit is used to select a diagonal to cut
1215 //=======================================================================
1217 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1218 const bool the13Diag)
1220 myLastCreatedElems.Clear();
1221 myLastCreatedNodes.Clear();
1223 MESSAGE( "::QuadToTri()" );
1225 SMESHDS_Mesh * aMesh = GetMeshDS();
1227 Handle(Geom_Surface) surface;
1228 SMESH_MesherHelper helper( *GetMesh() );
1230 TIDSortedElemSet::iterator itElem;
1231 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1232 const SMDS_MeshElement* elem = *itElem;
1233 if ( !elem || elem->GetType() != SMDSAbs_Face )
1235 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1236 if(!isquad) continue;
1238 if(elem->NbNodes()==4) {
1239 // retrieve element nodes
1240 const SMDS_MeshNode* aNodes [4];
1241 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1243 while ( itN->more() )
1244 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1246 int aShapeId = FindShape( elem );
1247 const SMDS_MeshElement* newElem = 0;
1249 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1250 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1253 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1254 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1256 myLastCreatedElems.Append(newElem);
1257 // put a new triangle on the same shape and add to the same groups
1259 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1260 AddToSameGroups( newElem, elem, aMesh );
1263 // Quadratic quadrangle
1265 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1267 // get surface elem is on
1268 int aShapeId = FindShape( elem );
1269 if ( aShapeId != helper.GetSubShapeID() ) {
1273 shape = aMesh->IndexToShape( aShapeId );
1274 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1275 TopoDS_Face face = TopoDS::Face( shape );
1276 surface = BRep_Tool::Surface( face );
1277 if ( !surface.IsNull() )
1278 helper.SetSubShape( shape );
1282 const SMDS_MeshNode* aNodes [8];
1283 const SMDS_MeshNode* inFaceNode = 0;
1284 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1286 while ( itN->more() ) {
1287 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1288 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1289 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1291 inFaceNode = aNodes[ i-1 ];
1295 // find middle point for (0,1,2,3)
1296 // and create a node in this point;
1298 if ( surface.IsNull() ) {
1300 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1304 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1307 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1309 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1311 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1312 myLastCreatedNodes.Append(newN);
1314 // create a new element
1315 const SMDS_MeshElement* newElem = 0;
1316 const SMDS_MeshNode* N[6];
1324 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1325 aNodes[6], aNodes[7], newN );
1334 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1335 aNodes[7], aNodes[4], newN );
1337 myLastCreatedElems.Append(newElem);
1338 aMesh->ChangeElementNodes( elem, N, 6 );
1339 // put a new triangle on the same shape and add to the same groups
1341 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1342 AddToSameGroups( newElem, elem, aMesh );
1349 //=======================================================================
1350 //function : getAngle
1352 //=======================================================================
1354 double getAngle(const SMDS_MeshElement * tr1,
1355 const SMDS_MeshElement * tr2,
1356 const SMDS_MeshNode * n1,
1357 const SMDS_MeshNode * n2)
1359 double angle = 2*PI; // bad angle
1362 SMESH::Controls::TSequenceOfXYZ P1, P2;
1363 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1364 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1367 if(!tr1->IsQuadratic())
1368 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1370 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1371 if ( N1.SquareMagnitude() <= gp::Resolution() )
1373 if(!tr2->IsQuadratic())
1374 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1376 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1377 if ( N2.SquareMagnitude() <= gp::Resolution() )
1380 // find the first diagonal node n1 in the triangles:
1381 // take in account a diagonal link orientation
1382 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1383 for ( int t = 0; t < 2; t++ ) {
1384 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1385 int i = 0, iDiag = -1;
1386 while ( it->more()) {
1387 const SMDS_MeshElement *n = it->next();
1388 if ( n == n1 || n == n2 )
1392 if ( i - iDiag == 1 )
1393 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1401 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1404 angle = N1.Angle( N2 );
1409 // =================================================
1410 // class generating a unique ID for a pair of nodes
1411 // and able to return nodes by that ID
1412 // =================================================
1416 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1417 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1420 long GetLinkID (const SMDS_MeshNode * n1,
1421 const SMDS_MeshNode * n2) const
1423 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1426 bool GetNodes (const long theLinkID,
1427 const SMDS_MeshNode* & theNode1,
1428 const SMDS_MeshNode* & theNode2) const
1430 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1431 if ( !theNode1 ) return false;
1432 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1433 if ( !theNode2 ) return false;
1439 const SMESHDS_Mesh* myMesh;
1444 //=======================================================================
1445 //function : TriToQuad
1446 //purpose : Fuse neighbour triangles into quadrangles.
1447 // theCrit is used to select a neighbour to fuse with.
1448 // theMaxAngle is a max angle between element normals at which
1449 // fusion is still performed.
1450 //=======================================================================
1452 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1453 SMESH::Controls::NumericalFunctorPtr theCrit,
1454 const double theMaxAngle)
1456 myLastCreatedElems.Clear();
1457 myLastCreatedNodes.Clear();
1459 MESSAGE( "::TriToQuad()" );
1461 if ( !theCrit.get() )
1464 SMESHDS_Mesh * aMesh = GetMeshDS();
1466 // Prepare data for algo: build
1467 // 1. map of elements with their linkIDs
1468 // 2. map of linkIDs with their elements
1470 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1471 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1472 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1473 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1475 TIDSortedElemSet::iterator itElem;
1476 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1477 const SMDS_MeshElement* elem = *itElem;
1478 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1479 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1480 if(!IsTria) continue;
1482 // retrieve element nodes
1483 const SMDS_MeshNode* aNodes [4];
1484 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1487 aNodes[ i++ ] = cast2Node( itN->next() );
1488 aNodes[ 3 ] = aNodes[ 0 ];
1491 for ( i = 0; i < 3; i++ ) {
1492 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1493 // check if elements sharing a link can be fused
1494 itLE = mapLi_listEl.find( link );
1495 if ( itLE != mapLi_listEl.end() ) {
1496 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1498 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1499 //if ( FindShape( elem ) != FindShape( elem2 ))
1500 // continue; // do not fuse triangles laying on different shapes
1501 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1502 continue; // avoid making badly shaped quads
1503 (*itLE).second.push_back( elem );
1506 mapLi_listEl[ link ].push_back( elem );
1508 mapEl_setLi [ elem ].insert( link );
1511 // Clean the maps from the links shared by a sole element, ie
1512 // links to which only one element is bound in mapLi_listEl
1514 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1515 int nbElems = (*itLE).second.size();
1516 if ( nbElems < 2 ) {
1517 const SMDS_MeshElement* elem = (*itLE).second.front();
1518 SMESH_TLink link = (*itLE).first;
1519 mapEl_setLi[ elem ].erase( link );
1520 if ( mapEl_setLi[ elem ].empty() )
1521 mapEl_setLi.erase( elem );
1525 // Algo: fuse triangles into quadrangles
1527 while ( ! mapEl_setLi.empty() ) {
1528 // Look for the start element:
1529 // the element having the least nb of shared links
1530 const SMDS_MeshElement* startElem = 0;
1532 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1533 int nbLinks = (*itEL).second.size();
1534 if ( nbLinks < minNbLinks ) {
1535 startElem = (*itEL).first;
1536 minNbLinks = nbLinks;
1537 if ( minNbLinks == 1 )
1542 // search elements to fuse starting from startElem or links of elements
1543 // fused earlyer - startLinks
1544 list< SMESH_TLink > startLinks;
1545 while ( startElem || !startLinks.empty() ) {
1546 while ( !startElem && !startLinks.empty() ) {
1547 // Get an element to start, by a link
1548 SMESH_TLink linkId = startLinks.front();
1549 startLinks.pop_front();
1550 itLE = mapLi_listEl.find( linkId );
1551 if ( itLE != mapLi_listEl.end() ) {
1552 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1553 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1554 for ( ; itE != listElem.end() ; itE++ )
1555 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1557 mapLi_listEl.erase( itLE );
1562 // Get candidates to be fused
1563 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1564 const SMESH_TLink *link12, *link13;
1566 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1567 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1568 ASSERT( !setLi.empty() );
1569 set< SMESH_TLink >::iterator itLi;
1570 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1572 const SMESH_TLink & link = (*itLi);
1573 itLE = mapLi_listEl.find( link );
1574 if ( itLE == mapLi_listEl.end() )
1577 const SMDS_MeshElement* elem = (*itLE).second.front();
1579 elem = (*itLE).second.back();
1580 mapLi_listEl.erase( itLE );
1581 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1592 // add other links of elem to list of links to re-start from
1593 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1594 set< SMESH_TLink >::iterator it;
1595 for ( it = links.begin(); it != links.end(); it++ ) {
1596 const SMESH_TLink& link2 = (*it);
1597 if ( link2 != link )
1598 startLinks.push_back( link2 );
1602 // Get nodes of possible quadrangles
1603 const SMDS_MeshNode *n12 [4], *n13 [4];
1604 bool Ok12 = false, Ok13 = false;
1605 const SMDS_MeshNode *linkNode1, *linkNode2;
1607 linkNode1 = link12->first;
1608 linkNode2 = link12->second;
1609 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1613 linkNode1 = link13->first;
1614 linkNode2 = link13->second;
1615 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1619 // Choose a pair to fuse
1620 if ( Ok12 && Ok13 ) {
1621 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1622 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1623 double aBadRate12 = getBadRate( &quad12, theCrit );
1624 double aBadRate13 = getBadRate( &quad13, theCrit );
1625 if ( aBadRate13 < aBadRate12 )
1632 // and remove fused elems and removed links from the maps
1633 mapEl_setLi.erase( tr1 );
1635 mapEl_setLi.erase( tr2 );
1636 mapLi_listEl.erase( *link12 );
1637 if(tr1->NbNodes()==3) {
1638 if( tr1->GetID() < tr2->GetID() ) {
1639 aMesh->ChangeElementNodes( tr1, n12, 4 );
1640 myLastCreatedElems.Append(tr1);
1641 aMesh->RemoveElement( tr2 );
1644 aMesh->ChangeElementNodes( tr2, n12, 4 );
1645 myLastCreatedElems.Append(tr2);
1646 aMesh->RemoveElement( tr1);
1650 const SMDS_MeshNode* N1 [6];
1651 const SMDS_MeshNode* N2 [6];
1652 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1653 // now we receive following N1 and N2 (using numeration as above image)
1654 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1655 // i.e. first nodes from both arrays determ new diagonal
1656 const SMDS_MeshNode* aNodes[8];
1665 if( tr1->GetID() < tr2->GetID() ) {
1666 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1667 myLastCreatedElems.Append(tr1);
1668 GetMeshDS()->RemoveElement( tr2 );
1671 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1672 myLastCreatedElems.Append(tr2);
1673 GetMeshDS()->RemoveElement( tr1 );
1675 // remove middle node (9)
1676 GetMeshDS()->RemoveNode( N1[4] );
1680 mapEl_setLi.erase( tr3 );
1681 mapLi_listEl.erase( *link13 );
1682 if(tr1->NbNodes()==3) {
1683 if( tr1->GetID() < tr2->GetID() ) {
1684 aMesh->ChangeElementNodes( tr1, n13, 4 );
1685 myLastCreatedElems.Append(tr1);
1686 aMesh->RemoveElement( tr3 );
1689 aMesh->ChangeElementNodes( tr3, n13, 4 );
1690 myLastCreatedElems.Append(tr3);
1691 aMesh->RemoveElement( tr1 );
1695 const SMDS_MeshNode* N1 [6];
1696 const SMDS_MeshNode* N2 [6];
1697 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1698 // now we receive following N1 and N2 (using numeration as above image)
1699 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1700 // i.e. first nodes from both arrays determ new diagonal
1701 const SMDS_MeshNode* aNodes[8];
1710 if( tr1->GetID() < tr2->GetID() ) {
1711 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1712 myLastCreatedElems.Append(tr1);
1713 GetMeshDS()->RemoveElement( tr3 );
1716 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1717 myLastCreatedElems.Append(tr3);
1718 GetMeshDS()->RemoveElement( tr1 );
1720 // remove middle node (9)
1721 GetMeshDS()->RemoveNode( N1[4] );
1725 // Next element to fuse: the rejected one
1727 startElem = Ok12 ? tr3 : tr2;
1729 } // if ( startElem )
1730 } // while ( startElem || !startLinks.empty() )
1731 } // while ( ! mapEl_setLi.empty() )
1737 /*#define DUMPSO(txt) \
1738 // cout << txt << endl;
1739 //=============================================================================
1743 //=============================================================================
1744 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1748 int tmp = idNodes[ i1 ];
1749 idNodes[ i1 ] = idNodes[ i2 ];
1750 idNodes[ i2 ] = tmp;
1751 gp_Pnt Ptmp = P[ i1 ];
1754 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1757 //=======================================================================
1758 //function : SortQuadNodes
1759 //purpose : Set 4 nodes of a quadrangle face in a good order.
1760 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1762 //=======================================================================
1764 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1769 for ( i = 0; i < 4; i++ ) {
1770 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1772 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1775 gp_Vec V1(P[0], P[1]);
1776 gp_Vec V2(P[0], P[2]);
1777 gp_Vec V3(P[0], P[3]);
1779 gp_Vec Cross1 = V1 ^ V2;
1780 gp_Vec Cross2 = V2 ^ V3;
1783 if (Cross1.Dot(Cross2) < 0)
1788 if (Cross1.Dot(Cross2) < 0)
1792 swap ( i, i + 1, idNodes, P );
1794 // for ( int ii = 0; ii < 4; ii++ ) {
1795 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1796 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1802 //=======================================================================
1803 //function : SortHexaNodes
1804 //purpose : Set 8 nodes of a hexahedron in a good order.
1805 // Return success status
1806 //=======================================================================
1808 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1813 DUMPSO( "INPUT: ========================================");
1814 for ( i = 0; i < 8; i++ ) {
1815 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1816 if ( !n ) return false;
1817 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1818 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1820 DUMPSO( "========================================");
1823 set<int> faceNodes; // ids of bottom face nodes, to be found
1824 set<int> checkedId1; // ids of tried 2-nd nodes
1825 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1826 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1827 int iMin, iLoop1 = 0;
1829 // Loop to try the 2-nd nodes
1831 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1833 // Find not checked 2-nd node
1834 for ( i = 1; i < 8; i++ )
1835 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1836 int id1 = idNodes[i];
1837 swap ( 1, i, idNodes, P );
1838 checkedId1.insert ( id1 );
1842 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1843 // ie that all but meybe one (id3 which is on the same face) nodes
1844 // lay on the same side from the triangle plane.
1846 bool manyInPlane = false; // more than 4 nodes lay in plane
1848 while ( ++iLoop2 < 6 ) {
1850 // get 1-2-3 plane coeffs
1851 Standard_Real A, B, C, D;
1852 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1853 if ( N.SquareMagnitude() > gp::Resolution() )
1855 gp_Pln pln ( P[0], N );
1856 pln.Coefficients( A, B, C, D );
1858 // find the node (iMin) closest to pln
1859 Standard_Real dist[ 8 ], minDist = DBL_MAX;
1861 for ( i = 3; i < 8; i++ ) {
1862 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1863 if ( fabs( dist[i] ) < minDist ) {
1864 minDist = fabs( dist[i] );
1867 if ( fabs( dist[i] ) <= tol )
1868 idInPln.insert( idNodes[i] );
1871 // there should not be more than 4 nodes in bottom plane
1872 if ( idInPln.size() > 1 )
1874 DUMPSO( "### idInPln.size() = " << idInPln.size());
1875 // idInPlane does not contain the first 3 nodes
1876 if ( manyInPlane || idInPln.size() == 5)
1877 return false; // all nodes in one plane
1880 // set the 1-st node to be not in plane
1881 for ( i = 3; i < 8; i++ ) {
1882 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1883 DUMPSO( "### Reset 0-th node");
1884 swap( 0, i, idNodes, P );
1889 // reset to re-check second nodes
1890 leastDist = DBL_MAX;
1894 break; // from iLoop2;
1897 // check that the other 4 nodes are on the same side
1898 bool sameSide = true;
1899 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1900 for ( i = 3; sameSide && i < 8; i++ ) {
1902 sameSide = ( isNeg == dist[i] <= 0.);
1905 // keep best solution
1906 if ( sameSide && minDist < leastDist ) {
1907 leastDist = minDist;
1909 faceNodes.insert( idNodes[ 1 ] );
1910 faceNodes.insert( idNodes[ 2 ] );
1911 faceNodes.insert( idNodes[ iMin ] );
1912 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1913 << " leastDist = " << leastDist);
1914 if ( leastDist <= DBL_MIN )
1919 // set next 3-d node to check
1920 int iNext = 2 + iLoop2;
1922 DUMPSO( "Try 2-nd");
1923 swap ( 2, iNext, idNodes, P );
1925 } // while ( iLoop2 < 6 )
1928 if ( faceNodes.empty() ) return false;
1930 // Put the faceNodes in proper places
1931 for ( i = 4; i < 8; i++ ) {
1932 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1933 // find a place to put
1935 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1937 DUMPSO( "Set faceNodes");
1938 swap ( iTo, i, idNodes, P );
1943 // Set nodes of the found bottom face in good order
1944 DUMPSO( " Found bottom face: ");
1945 i = SortQuadNodes( theMesh, idNodes );
1947 gp_Pnt Ptmp = P[ i ];
1952 // for ( int ii = 0; ii < 4; ii++ ) {
1953 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1954 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1957 // Gravity center of the top and bottom faces
1958 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1959 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1961 // Get direction from the bottom to the top face
1962 gp_Vec upDir ( aGCb, aGCt );
1963 Standard_Real upDirSize = upDir.Magnitude();
1964 if ( upDirSize <= gp::Resolution() ) return false;
1967 // Assure that the bottom face normal points up
1968 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1969 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1970 if ( Nb.Dot( upDir ) < 0 ) {
1971 DUMPSO( "Reverse bottom face");
1972 swap( 1, 3, idNodes, P );
1975 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1976 Standard_Real minDist = DBL_MAX;
1977 for ( i = 4; i < 8; i++ ) {
1978 // projection of P[i] to the plane defined by P[0] and upDir
1979 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1980 Standard_Real sqDist = P[0].SquareDistance( Pp );
1981 if ( sqDist < minDist ) {
1986 DUMPSO( "Set 4-th");
1987 swap ( 4, iMin, idNodes, P );
1989 // Set nodes of the top face in good order
1990 DUMPSO( "Sort top face");
1991 i = SortQuadNodes( theMesh, &idNodes[4] );
1994 gp_Pnt Ptmp = P[ i ];
1999 // Assure that direction of the top face normal is from the bottom face
2000 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2001 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2002 if ( Nt.Dot( upDir ) < 0 ) {
2003 DUMPSO( "Reverse top face");
2004 swap( 5, 7, idNodes, P );
2007 // DUMPSO( "OUTPUT: ========================================");
2008 // for ( i = 0; i < 8; i++ ) {
2009 // float *p = ugrid->GetPoint(idNodes[i]);
2010 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2016 //================================================================================
2018 * \brief Return nodes linked to the given one
2019 * \param theNode - the node
2020 * \param linkedNodes - the found nodes
2021 * \param type - the type of elements to check
2023 * Medium nodes are ignored
2025 //================================================================================
2027 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2028 TIDSortedElemSet & linkedNodes,
2029 SMDSAbs_ElementType type )
2031 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2032 while ( elemIt->more() )
2034 const SMDS_MeshElement* elem = elemIt->next();
2035 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2036 if ( elem->GetType() == SMDSAbs_Volume )
2038 SMDS_VolumeTool vol( elem );
2039 while ( nodeIt->more() ) {
2040 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2041 if ( theNode != n && vol.IsLinked( theNode, n ))
2042 linkedNodes.insert( n );
2047 for ( int i = 0; nodeIt->more(); ++i ) {
2048 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2049 if ( n == theNode ) {
2050 int iBefore = i - 1;
2052 if ( elem->IsQuadratic() ) {
2053 int nb = elem->NbNodes() / 2;
2054 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2055 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2057 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2058 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2065 //=======================================================================
2066 //function : laplacianSmooth
2067 //purpose : pulls theNode toward the center of surrounding nodes directly
2068 // connected to that node along an element edge
2069 //=======================================================================
2071 void laplacianSmooth(const SMDS_MeshNode* theNode,
2072 const Handle(Geom_Surface)& theSurface,
2073 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2075 // find surrounding nodes
2077 TIDSortedElemSet nodeSet;
2078 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2080 // compute new coodrs
2082 double coord[] = { 0., 0., 0. };
2083 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2084 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2085 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2086 if ( theSurface.IsNull() ) { // smooth in 3D
2087 coord[0] += node->X();
2088 coord[1] += node->Y();
2089 coord[2] += node->Z();
2091 else { // smooth in 2D
2092 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2093 gp_XY* uv = theUVMap[ node ];
2094 coord[0] += uv->X();
2095 coord[1] += uv->Y();
2098 int nbNodes = nodeSet.size();
2101 coord[0] /= nbNodes;
2102 coord[1] /= nbNodes;
2104 if ( !theSurface.IsNull() ) {
2105 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2106 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2107 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2113 coord[2] /= nbNodes;
2117 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2120 //=======================================================================
2121 //function : centroidalSmooth
2122 //purpose : pulls theNode toward the element-area-weighted centroid of the
2123 // surrounding elements
2124 //=======================================================================
2126 void centroidalSmooth(const SMDS_MeshNode* theNode,
2127 const Handle(Geom_Surface)& theSurface,
2128 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2130 gp_XYZ aNewXYZ(0.,0.,0.);
2131 SMESH::Controls::Area anAreaFunc;
2132 double totalArea = 0.;
2137 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2138 while ( elemIt->more() )
2140 const SMDS_MeshElement* elem = elemIt->next();
2143 gp_XYZ elemCenter(0.,0.,0.);
2144 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2145 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2146 int nn = elem->NbNodes();
2147 if(elem->IsQuadratic()) nn = nn/2;
2149 //while ( itN->more() ) {
2151 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2153 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2154 aNodePoints.push_back( aP );
2155 if ( !theSurface.IsNull() ) { // smooth in 2D
2156 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2157 gp_XY* uv = theUVMap[ aNode ];
2158 aP.SetCoord( uv->X(), uv->Y(), 0. );
2162 double elemArea = anAreaFunc.GetValue( aNodePoints );
2163 totalArea += elemArea;
2165 aNewXYZ += elemCenter * elemArea;
2167 aNewXYZ /= totalArea;
2168 if ( !theSurface.IsNull() ) {
2169 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2170 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2175 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2178 //=======================================================================
2179 //function : getClosestUV
2180 //purpose : return UV of closest projection
2181 //=======================================================================
2183 static bool getClosestUV (Extrema_GenExtPS& projector,
2184 const gp_Pnt& point,
2187 projector.Perform( point );
2188 if ( projector.IsDone() ) {
2189 double u, v, minVal = DBL_MAX;
2190 for ( int i = projector.NbExt(); i > 0; i-- )
2191 if ( projector.Value( i ) < minVal ) {
2192 minVal = projector.Value( i );
2193 projector.Point( i ).Parameter( u, v );
2195 result.SetCoord( u, v );
2201 //=======================================================================
2203 //purpose : Smooth theElements during theNbIterations or until a worst
2204 // element has aspect ratio <= theTgtAspectRatio.
2205 // Aspect Ratio varies in range [1.0, inf].
2206 // If theElements is empty, the whole mesh is smoothed.
2207 // theFixedNodes contains additionally fixed nodes. Nodes built
2208 // on edges and boundary nodes are always fixed.
2209 //=======================================================================
2211 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2212 set<const SMDS_MeshNode*> & theFixedNodes,
2213 const SmoothMethod theSmoothMethod,
2214 const int theNbIterations,
2215 double theTgtAspectRatio,
2218 myLastCreatedElems.Clear();
2219 myLastCreatedNodes.Clear();
2221 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2223 if ( theTgtAspectRatio < 1.0 )
2224 theTgtAspectRatio = 1.0;
2226 const double disttol = 1.e-16;
2228 SMESH::Controls::AspectRatio aQualityFunc;
2230 SMESHDS_Mesh* aMesh = GetMeshDS();
2232 if ( theElems.empty() ) {
2233 // add all faces to theElems
2234 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2235 while ( fIt->more() ) {
2236 const SMDS_MeshElement* face = fIt->next();
2237 theElems.insert( face );
2240 // get all face ids theElems are on
2241 set< int > faceIdSet;
2242 TIDSortedElemSet::iterator itElem;
2244 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2245 int fId = FindShape( *itElem );
2246 // check that corresponding submesh exists and a shape is face
2248 faceIdSet.find( fId ) == faceIdSet.end() &&
2249 aMesh->MeshElements( fId )) {
2250 TopoDS_Shape F = aMesh->IndexToShape( fId );
2251 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2252 faceIdSet.insert( fId );
2255 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2257 // ===============================================
2258 // smooth elements on each TopoDS_Face separately
2259 // ===============================================
2261 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2262 for ( ; fId != faceIdSet.rend(); ++fId ) {
2263 // get face surface and submesh
2264 Handle(Geom_Surface) surface;
2265 SMESHDS_SubMesh* faceSubMesh = 0;
2267 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2268 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2269 bool isUPeriodic = false, isVPeriodic = false;
2271 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2272 surface = BRep_Tool::Surface( face );
2273 faceSubMesh = aMesh->MeshElements( *fId );
2274 fToler2 = BRep_Tool::Tolerance( face );
2275 fToler2 *= fToler2 * 10.;
2276 isUPeriodic = surface->IsUPeriodic();
2278 vPeriod = surface->UPeriod();
2279 isVPeriodic = surface->IsVPeriodic();
2281 uPeriod = surface->VPeriod();
2282 surface->Bounds( u1, u2, v1, v2 );
2284 // ---------------------------------------------------------
2285 // for elements on a face, find movable and fixed nodes and
2286 // compute UV for them
2287 // ---------------------------------------------------------
2288 bool checkBoundaryNodes = false;
2289 bool isQuadratic = false;
2290 set<const SMDS_MeshNode*> setMovableNodes;
2291 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2292 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2293 list< const SMDS_MeshElement* > elemsOnFace;
2295 Extrema_GenExtPS projector;
2296 GeomAdaptor_Surface surfAdaptor;
2297 if ( !surface.IsNull() ) {
2298 surfAdaptor.Load( surface );
2299 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2301 int nbElemOnFace = 0;
2302 itElem = theElems.begin();
2303 // loop on not yet smoothed elements: look for elems on a face
2304 while ( itElem != theElems.end() ) {
2305 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2306 break; // all elements found
2308 const SMDS_MeshElement* elem = *itElem;
2309 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2310 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2314 elemsOnFace.push_back( elem );
2315 theElems.erase( itElem++ );
2319 isQuadratic = elem->IsQuadratic();
2321 // get movable nodes of elem
2322 const SMDS_MeshNode* node;
2323 SMDS_TypeOfPosition posType;
2324 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2325 int nn = 0, nbn = elem->NbNodes();
2326 if(elem->IsQuadratic())
2328 while ( nn++ < nbn ) {
2329 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2330 const SMDS_PositionPtr& pos = node->GetPosition();
2331 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2332 if (posType != SMDS_TOP_EDGE &&
2333 posType != SMDS_TOP_VERTEX &&
2334 theFixedNodes.find( node ) == theFixedNodes.end())
2336 // check if all faces around the node are on faceSubMesh
2337 // because a node on edge may be bound to face
2338 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2340 if ( faceSubMesh ) {
2341 while ( eIt->more() && all ) {
2342 const SMDS_MeshElement* e = eIt->next();
2343 all = faceSubMesh->Contains( e );
2347 setMovableNodes.insert( node );
2349 checkBoundaryNodes = true;
2351 if ( posType == SMDS_TOP_3DSPACE )
2352 checkBoundaryNodes = true;
2355 if ( surface.IsNull() )
2358 // get nodes to check UV
2359 list< const SMDS_MeshNode* > uvCheckNodes;
2360 itN = elem->nodesIterator();
2361 nn = 0; nbn = elem->NbNodes();
2362 if(elem->IsQuadratic())
2364 while ( nn++ < nbn ) {
2365 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2366 if ( uvMap.find( node ) == uvMap.end() )
2367 uvCheckNodes.push_back( node );
2368 // add nodes of elems sharing node
2369 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2370 // while ( eIt->more() ) {
2371 // const SMDS_MeshElement* e = eIt->next();
2372 // if ( e != elem ) {
2373 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2374 // while ( nIt->more() ) {
2375 // const SMDS_MeshNode* n =
2376 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2377 // if ( uvMap.find( n ) == uvMap.end() )
2378 // uvCheckNodes.push_back( n );
2384 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2385 for ( ; n != uvCheckNodes.end(); ++n ) {
2388 const SMDS_PositionPtr& pos = node->GetPosition();
2389 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2391 switch ( posType ) {
2392 case SMDS_TOP_FACE: {
2393 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2394 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2397 case SMDS_TOP_EDGE: {
2398 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2399 Handle(Geom2d_Curve) pcurve;
2400 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2401 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2402 if ( !pcurve.IsNull() ) {
2403 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2404 uv = pcurve->Value( u ).XY();
2408 case SMDS_TOP_VERTEX: {
2409 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2410 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2411 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2416 // check existing UV
2417 bool project = true;
2418 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2419 double dist1 = DBL_MAX, dist2 = 0;
2420 if ( posType != SMDS_TOP_3DSPACE ) {
2421 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2422 project = dist1 > fToler2;
2424 if ( project ) { // compute new UV
2426 if ( !getClosestUV( projector, pNode, newUV )) {
2427 MESSAGE("Node Projection Failed " << node);
2431 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2433 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2435 if ( posType != SMDS_TOP_3DSPACE )
2436 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2437 if ( dist2 < dist1 )
2441 // store UV in the map
2442 listUV.push_back( uv );
2443 uvMap.insert( make_pair( node, &listUV.back() ));
2445 } // loop on not yet smoothed elements
2447 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2448 checkBoundaryNodes = true;
2450 // fix nodes on mesh boundary
2452 if ( checkBoundaryNodes ) {
2453 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2454 map< NLink, int >::iterator link_nb;
2455 // put all elements links to linkNbMap
2456 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2457 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2458 const SMDS_MeshElement* elem = (*elemIt);
2459 int nbn = elem->NbNodes();
2460 if(elem->IsQuadratic())
2462 // loop on elem links: insert them in linkNbMap
2463 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2464 for ( int iN = 0; iN < nbn; ++iN ) {
2465 curNode = elem->GetNode( iN );
2467 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2468 else link = make_pair( prevNode , curNode );
2470 link_nb = linkNbMap.find( link );
2471 if ( link_nb == linkNbMap.end() )
2472 linkNbMap.insert( make_pair ( link, 1 ));
2477 // remove nodes that are in links encountered only once from setMovableNodes
2478 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2479 if ( link_nb->second == 1 ) {
2480 setMovableNodes.erase( link_nb->first.first );
2481 setMovableNodes.erase( link_nb->first.second );
2486 // -----------------------------------------------------
2487 // for nodes on seam edge, compute one more UV ( uvMap2 );
2488 // find movable nodes linked to nodes on seam and which
2489 // are to be smoothed using the second UV ( uvMap2 )
2490 // -----------------------------------------------------
2492 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2493 if ( !surface.IsNull() ) {
2494 TopExp_Explorer eExp( face, TopAbs_EDGE );
2495 for ( ; eExp.More(); eExp.Next() ) {
2496 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2497 if ( !BRep_Tool::IsClosed( edge, face ))
2499 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2500 if ( !sm ) continue;
2501 // find out which parameter varies for a node on seam
2504 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2505 if ( pcurve.IsNull() ) continue;
2506 uv1 = pcurve->Value( f );
2508 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2509 if ( pcurve.IsNull() ) continue;
2510 uv2 = pcurve->Value( f );
2511 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2513 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2514 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2516 // get nodes on seam and its vertices
2517 list< const SMDS_MeshNode* > seamNodes;
2518 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2519 while ( nSeamIt->more() ) {
2520 const SMDS_MeshNode* node = nSeamIt->next();
2521 if ( !isQuadratic || !IsMedium( node ))
2522 seamNodes.push_back( node );
2524 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2525 for ( ; vExp.More(); vExp.Next() ) {
2526 sm = aMesh->MeshElements( vExp.Current() );
2528 nSeamIt = sm->GetNodes();
2529 while ( nSeamIt->more() )
2530 seamNodes.push_back( nSeamIt->next() );
2533 // loop on nodes on seam
2534 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2535 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2536 const SMDS_MeshNode* nSeam = *noSeIt;
2537 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2538 if ( n_uv == uvMap.end() )
2541 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2542 // set the second UV
2543 listUV.push_back( *n_uv->second );
2544 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2545 if ( uvMap2.empty() )
2546 uvMap2 = uvMap; // copy the uvMap contents
2547 uvMap2[ nSeam ] = &listUV.back();
2549 // collect movable nodes linked to ones on seam in nodesNearSeam
2550 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2551 while ( eIt->more() ) {
2552 const SMDS_MeshElement* e = eIt->next();
2553 int nbUseMap1 = 0, nbUseMap2 = 0;
2554 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2555 int nn = 0, nbn = e->NbNodes();
2556 if(e->IsQuadratic()) nbn = nbn/2;
2557 while ( nn++ < nbn )
2559 const SMDS_MeshNode* n =
2560 static_cast<const SMDS_MeshNode*>( nIt->next() );
2562 setMovableNodes.find( n ) == setMovableNodes.end() )
2564 // add only nodes being closer to uv2 than to uv1
2565 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2566 0.5 * ( n->Y() + nSeam->Y() ),
2567 0.5 * ( n->Z() + nSeam->Z() ));
2569 getClosestUV( projector, pMid, uv );
2570 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2571 nodesNearSeam.insert( n );
2577 // for centroidalSmooth all element nodes must
2578 // be on one side of a seam
2579 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2580 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2582 while ( nn++ < nbn ) {
2583 const SMDS_MeshNode* n =
2584 static_cast<const SMDS_MeshNode*>( nIt->next() );
2585 setMovableNodes.erase( n );
2589 } // loop on nodes on seam
2590 } // loop on edge of a face
2591 } // if ( !face.IsNull() )
2593 if ( setMovableNodes.empty() ) {
2594 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2595 continue; // goto next face
2603 double maxRatio = -1., maxDisplacement = -1.;
2604 set<const SMDS_MeshNode*>::iterator nodeToMove;
2605 for ( it = 0; it < theNbIterations; it++ ) {
2606 maxDisplacement = 0.;
2607 nodeToMove = setMovableNodes.begin();
2608 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2609 const SMDS_MeshNode* node = (*nodeToMove);
2610 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2613 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2614 if ( theSmoothMethod == LAPLACIAN )
2615 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2617 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2619 // node displacement
2620 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2621 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2622 if ( aDispl > maxDisplacement )
2623 maxDisplacement = aDispl;
2625 // no node movement => exit
2626 //if ( maxDisplacement < 1.e-16 ) {
2627 if ( maxDisplacement < disttol ) {
2628 MESSAGE("-- no node movement --");
2632 // check elements quality
2634 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2635 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2636 const SMDS_MeshElement* elem = (*elemIt);
2637 if ( !elem || elem->GetType() != SMDSAbs_Face )
2639 SMESH::Controls::TSequenceOfXYZ aPoints;
2640 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2641 double aValue = aQualityFunc.GetValue( aPoints );
2642 if ( aValue > maxRatio )
2646 if ( maxRatio <= theTgtAspectRatio ) {
2647 MESSAGE("-- quality achived --");
2650 if (it+1 == theNbIterations) {
2651 MESSAGE("-- Iteration limit exceeded --");
2653 } // smoothing iterations
2655 MESSAGE(" Face id: " << *fId <<
2656 " Nb iterstions: " << it <<
2657 " Displacement: " << maxDisplacement <<
2658 " Aspect Ratio " << maxRatio);
2660 // ---------------------------------------
2661 // new nodes positions are computed,
2662 // record movement in DS and set new UV
2663 // ---------------------------------------
2664 nodeToMove = setMovableNodes.begin();
2665 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2666 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2667 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2668 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2669 if ( node_uv != uvMap.end() ) {
2670 gp_XY* uv = node_uv->second;
2672 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2676 // move medium nodes of quadratic elements
2679 SMESH_MesherHelper helper( *GetMesh() );
2680 if ( !face.IsNull() )
2681 helper.SetSubShape( face );
2682 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2683 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2684 const SMDS_QuadraticFaceOfNodes* QF =
2685 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2687 vector<const SMDS_MeshNode*> Ns;
2688 Ns.reserve(QF->NbNodes()+1);
2689 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2690 while ( anIter->more() )
2691 Ns.push_back( anIter->next() );
2692 Ns.push_back( Ns[0] );
2694 for(int i=0; i<QF->NbNodes(); i=i+2) {
2695 if ( !surface.IsNull() ) {
2696 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2697 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2698 gp_XY uv = ( uv1 + uv2 ) / 2.;
2699 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2700 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2703 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2704 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2705 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2707 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2708 fabs( Ns[i+1]->Y() - y ) > disttol ||
2709 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2710 // we have to move i+1 node
2711 aMesh->MoveNode( Ns[i+1], x, y, z );
2718 } // loop on face ids
2722 //=======================================================================
2723 //function : isReverse
2724 //purpose : Return true if normal of prevNodes is not co-directied with
2725 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2726 // iNotSame is where prevNodes and nextNodes are different
2727 //=======================================================================
2729 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2730 vector<const SMDS_MeshNode*> nextNodes,
2734 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2735 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2737 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2738 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2739 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2740 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2742 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2743 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2744 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2745 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2747 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2749 return (vA ^ vB) * vN < 0.0;
2752 //=======================================================================
2754 * \brief Create elements by sweeping an element
2755 * \param elem - element to sweep
2756 * \param newNodesItVec - nodes generated from each node of the element
2757 * \param newElems - generated elements
2758 * \param nbSteps - number of sweeping steps
2759 * \param srcElements - to append elem for each generated element
2761 //=======================================================================
2763 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2764 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2765 list<const SMDS_MeshElement*>& newElems,
2767 SMESH_SequenceOfElemPtr& srcElements)
2769 SMESHDS_Mesh* aMesh = GetMeshDS();
2771 // Loop on elem nodes:
2772 // find new nodes and detect same nodes indices
2773 int nbNodes = elem->NbNodes();
2774 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2775 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2776 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2777 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2779 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2780 vector<int> sames(nbNodes);
2781 vector<bool> issimple(nbNodes);
2783 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2784 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2785 const SMDS_MeshNode* node = nnIt->first;
2786 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2787 if ( listNewNodes.empty() ) {
2791 issimple[iNode] = (listNewNodes.size()==nbSteps);
2793 itNN[ iNode ] = listNewNodes.begin();
2794 prevNod[ iNode ] = node;
2795 nextNod[ iNode ] = listNewNodes.front();
2796 if( !issimple[iNode] ) {
2797 if ( prevNod[ iNode ] != nextNod [ iNode ])
2798 iNotSameNode = iNode;
2802 sames[nbSame++] = iNode;
2807 //cout<<" nbSame = "<<nbSame<<endl;
2808 if ( nbSame == nbNodes || nbSame > 2) {
2809 //MESSAGE( " Too many same nodes of element " << elem->GetID() );
2810 INFOS( " Too many same nodes of element " << elem->GetID() );
2814 // if( elem->IsQuadratic() && nbSame>0 ) {
2815 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2819 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2820 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2822 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2823 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2824 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2828 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2829 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2830 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2831 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2833 // check element orientation
2835 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2836 //MESSAGE("Reversed elem " << elem );
2840 std::swap( iBeforeSame, iAfterSame );
2843 // make new elements
2844 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2846 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2847 if(issimple[iNode]) {
2848 nextNod[ iNode ] = *itNN[ iNode ];
2852 if( elem->GetType()==SMDSAbs_Node ) {
2853 // we have to use two nodes
2854 midlNod[ iNode ] = *itNN[ iNode ];
2856 nextNod[ iNode ] = *itNN[ iNode ];
2859 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2860 // we have to use each second node
2862 nextNod[ iNode ] = *itNN[ iNode ];
2866 // we have to use two nodes
2867 midlNod[ iNode ] = *itNN[ iNode ];
2869 nextNod[ iNode ] = *itNN[ iNode ];
2874 SMDS_MeshElement* aNewElem = 0;
2875 if(!elem->IsPoly()) {
2876 switch ( nbNodes ) {
2880 if ( nbSame == 0 ) {
2882 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2884 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2890 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2891 nextNod[ 1 ], nextNod[ 0 ] );
2893 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2894 nextNod[ iNotSameNode ] );
2898 case 3: { // TRIANGLE or quadratic edge
2899 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2901 if ( nbSame == 0 ) // --- pentahedron
2902 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2903 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2905 else if ( nbSame == 1 ) // --- pyramid
2906 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2907 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2908 nextNod[ iSameNode ]);
2910 else // 2 same nodes: --- tetrahedron
2911 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2912 nextNod[ iNotSameNode ]);
2914 else { // quadratic edge
2915 if(nbSame==0) { // quadratic quadrangle
2916 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2917 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2919 else if(nbSame==1) { // quadratic triangle
2921 return; // medium node on axis
2923 else if(sames[0]==0) {
2924 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2925 nextNod[2], midlNod[1], prevNod[2]);
2927 else { // sames[0]==1
2928 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2929 midlNod[0], nextNod[2], prevNod[2]);
2938 case 4: { // QUADRANGLE
2940 if ( nbSame == 0 ) // --- hexahedron
2941 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2942 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2944 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2945 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2946 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2947 nextNod[ iSameNode ]);
2948 newElems.push_back( aNewElem );
2949 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2950 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2951 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2953 else if ( nbSame == 2 ) { // pentahedron
2954 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2955 // iBeforeSame is same too
2956 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2957 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2958 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2960 // iAfterSame is same too
2961 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2962 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2963 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2967 case 6: { // quadratic triangle
2968 // create pentahedron with 15 nodes
2970 if(i0>0) { // reversed case
2971 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2972 nextNod[0], nextNod[2], nextNod[1],
2973 prevNod[5], prevNod[4], prevNod[3],
2974 nextNod[5], nextNod[4], nextNod[3],
2975 midlNod[0], midlNod[2], midlNod[1]);
2977 else { // not reversed case
2978 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2979 nextNod[0], nextNod[1], nextNod[2],
2980 prevNod[3], prevNod[4], prevNod[5],
2981 nextNod[3], nextNod[4], nextNod[5],
2982 midlNod[0], midlNod[1], midlNod[2]);
2985 else if(nbSame==1) {
2986 // 2d order pyramid of 13 nodes
2987 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
2988 // int n12,int n23,int n34,int n41,
2989 // int n15,int n25,int n35,int n45, int ID);
2991 int n1,n4,n41,n15,n45;
2992 if(i0>0) { // reversed case
2993 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
2994 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3000 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3001 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3006 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3007 nextNod[n4], prevNod[n4], prevNod[n5],
3008 midlNod[n1], nextNod[n41],
3009 midlNod[n4], prevNod[n41],
3010 prevNod[n15], nextNod[n15],
3011 nextNod[n45], prevNod[n45]);
3013 else if(nbSame==2) {
3014 // 2d order tetrahedron of 10 nodes
3015 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3016 // int n12,int n23,int n31,
3017 // int n14,int n24,int n34, int ID);
3018 int n1 = iNotSameNode;
3019 int n2,n3,n12,n23,n31;
3020 if(i0>0) { // reversed case
3021 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3022 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3028 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3029 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3034 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3035 prevNod[n12], prevNod[n23], prevNod[n31],
3036 midlNod[n1], nextNod[n12], nextNod[n31]);
3040 case 8: { // quadratic quadrangle
3042 // create hexahedron with 20 nodes
3043 if(i0>0) { // reversed case
3044 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3045 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3046 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3047 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3048 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3050 else { // not reversed case
3051 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3052 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3053 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3054 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3055 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3058 else if(nbSame==1) {
3059 // --- pyramid + pentahedron - can not be created since it is needed
3060 // additional middle node ot the center of face
3061 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3064 else if(nbSame==2) {
3065 // 2d order Pentahedron with 15 nodes
3066 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3067 // int n12,int n23,int n31,int n45,int n56,int n64,
3068 // int n14,int n25,int n36, int ID);
3070 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3071 // iBeforeSame is same too
3078 // iAfterSame is same too
3084 int n12,n45,n14,n25;
3085 if(i0>0) { //reversed case
3097 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3098 prevNod[n4], prevNod[n5], nextNod[n5],
3099 prevNod[n12], midlNod[n2], nextNod[n12],
3100 prevNod[n45], midlNod[n5], nextNod[n45],
3101 prevNod[n14], prevNod[n25], nextNod[n25]);
3106 // realized for extrusion only
3107 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3108 //vector<int> quantities (nbNodes + 2);
3110 //quantities[0] = nbNodes; // bottom of prism
3111 //for (int inode = 0; inode < nbNodes; inode++) {
3112 // polyedre_nodes[inode] = prevNod[inode];
3115 //quantities[1] = nbNodes; // top of prism
3116 //for (int inode = 0; inode < nbNodes; inode++) {
3117 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3120 //for (int iface = 0; iface < nbNodes; iface++) {
3121 // quantities[iface + 2] = 4;
3122 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3123 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3124 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3125 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3126 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3128 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3135 // realized for extrusion only
3136 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3137 vector<int> quantities (nbNodes + 2);
3139 quantities[0] = nbNodes; // bottom of prism
3140 for (int inode = 0; inode < nbNodes; inode++) {
3141 polyedre_nodes[inode] = prevNod[inode];
3144 quantities[1] = nbNodes; // top of prism
3145 for (int inode = 0; inode < nbNodes; inode++) {
3146 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3149 for (int iface = 0; iface < nbNodes; iface++) {
3150 quantities[iface + 2] = 4;
3151 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3152 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3153 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3154 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3155 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3157 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3161 newElems.push_back( aNewElem );
3162 myLastCreatedElems.Append(aNewElem);
3163 srcElements.Append( elem );
3166 // set new prev nodes
3167 for ( iNode = 0; iNode < nbNodes; iNode++ )
3168 prevNod[ iNode ] = nextNod[ iNode ];
3173 //=======================================================================
3175 * \brief Create 1D and 2D elements around swept elements
3176 * \param mapNewNodes - source nodes and ones generated from them
3177 * \param newElemsMap - source elements and ones generated from them
3178 * \param elemNewNodesMap - nodes generated from each node of each element
3179 * \param elemSet - all swept elements
3180 * \param nbSteps - number of sweeping steps
3181 * \param srcElements - to append elem for each generated element
3183 //=======================================================================
3185 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3186 TElemOfElemListMap & newElemsMap,
3187 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3188 TIDSortedElemSet& elemSet,
3190 SMESH_SequenceOfElemPtr& srcElements)
3192 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3193 SMESHDS_Mesh* aMesh = GetMeshDS();
3195 // Find nodes belonging to only one initial element - sweep them to get edges.
3197 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3198 for ( ; nList != mapNewNodes.end(); nList++ ) {
3199 const SMDS_MeshNode* node =
3200 static_cast<const SMDS_MeshNode*>( nList->first );
3201 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3202 int nbInitElems = 0;
3203 const SMDS_MeshElement* el = 0;
3204 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3205 while ( eIt->more() && nbInitElems < 2 ) {
3207 SMDSAbs_ElementType type = el->GetType();
3208 if ( type == SMDSAbs_Volume || type < highType ) continue;
3209 if ( type > highType ) {
3213 if ( elemSet.find(el) != elemSet.end() )
3216 if ( nbInitElems < 2 ) {
3217 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3218 if(!NotCreateEdge) {
3219 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3220 list<const SMDS_MeshElement*> newEdges;
3221 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3226 // Make a ceiling for each element ie an equal element of last new nodes.
3227 // Find free links of faces - make edges and sweep them into faces.
3229 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3230 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3231 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3232 const SMDS_MeshElement* elem = itElem->first;
3233 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3235 if ( elem->GetType() == SMDSAbs_Edge ) {
3236 // create a ceiling edge
3237 if (!elem->IsQuadratic()) {
3238 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3239 vecNewNodes[ 1 ]->second.back())) {
3240 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3241 vecNewNodes[ 1 ]->second.back()));
3242 srcElements.Append( myLastCreatedElems.Last() );
3246 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3247 vecNewNodes[ 1 ]->second.back(),
3248 vecNewNodes[ 2 ]->second.back())) {
3249 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3250 vecNewNodes[ 1 ]->second.back(),
3251 vecNewNodes[ 2 ]->second.back()));
3252 srcElements.Append( myLastCreatedElems.Last() );
3256 if ( elem->GetType() != SMDSAbs_Face )
3259 if(itElem->second.size()==0) continue;
3261 bool hasFreeLinks = false;
3263 TIDSortedElemSet avoidSet;
3264 avoidSet.insert( elem );
3266 set<const SMDS_MeshNode*> aFaceLastNodes;
3267 int iNode, nbNodes = vecNewNodes.size();
3268 if(!elem->IsQuadratic()) {
3269 // loop on the face nodes
3270 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3271 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3272 // look for free links of the face
3273 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3274 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3275 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3276 // check if a link is free
3277 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3278 hasFreeLinks = true;
3279 // make an edge and a ceiling for a new edge
3280 if ( !aMesh->FindEdge( n1, n2 )) {
3281 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3282 srcElements.Append( myLastCreatedElems.Last() );
3284 n1 = vecNewNodes[ iNode ]->second.back();
3285 n2 = vecNewNodes[ iNext ]->second.back();
3286 if ( !aMesh->FindEdge( n1, n2 )) {
3287 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3288 srcElements.Append( myLastCreatedElems.Last() );
3293 else { // elem is quadratic face
3294 int nbn = nbNodes/2;
3295 for ( iNode = 0; iNode < nbn; iNode++ ) {
3296 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3297 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3298 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3299 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3300 // check if a link is free
3301 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3302 hasFreeLinks = true;
3303 // make an edge and a ceiling for a new edge
3305 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3306 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3307 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3308 srcElements.Append( myLastCreatedElems.Last() );
3310 n1 = vecNewNodes[ iNode ]->second.back();
3311 n2 = vecNewNodes[ iNext ]->second.back();
3312 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3313 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3314 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3315 srcElements.Append( myLastCreatedElems.Last() );
3319 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3320 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3324 // sweep free links into faces
3326 if ( hasFreeLinks ) {
3327 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3328 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3330 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3331 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3332 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3333 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3335 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3336 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3338 while ( iVol++ < volNb ) v++;
3339 // find indices of free faces of a volume and their source edges
3340 list< int > freeInd;
3341 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3342 SMDS_VolumeTool vTool( *v );
3343 int iF, nbF = vTool.NbFaces();
3344 for ( iF = 0; iF < nbF; iF ++ ) {
3345 if (vTool.IsFreeFace( iF ) &&
3346 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3347 initNodeSet != faceNodeSet) // except an initial face
3349 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3351 freeInd.push_back( iF );
3352 // find source edge of a free face iF
3353 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3354 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3355 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3356 initNodeSet.begin(), initNodeSet.end(),
3357 commonNodes.begin());
3358 if ( (*v)->IsQuadratic() )
3359 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3361 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3363 if ( !srcEdges.back() )
3365 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3366 << iF << " of volume #" << vTool.ID() << endl;
3371 if ( freeInd.empty() )
3374 // create faces for all steps;
3375 // if such a face has been already created by sweep of edge,
3376 // assure that its orientation is OK
3377 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3379 vTool.SetExternalNormal();
3380 list< int >::iterator ind = freeInd.begin();
3381 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3382 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3384 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3385 int nbn = vTool.NbFaceNodes( *ind );
3387 case 3: { ///// triangle
3388 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3390 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3391 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3392 aMesh->ChangeElementNodes( f, nodes, nbn );
3395 case 4: { ///// quadrangle
3396 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3398 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3399 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3400 aMesh->ChangeElementNodes( f, nodes, nbn );
3404 if( (*v)->IsQuadratic() ) {
3405 if(nbn==6) { /////// quadratic triangle
3406 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3407 nodes[1], nodes[3], nodes[5] );
3409 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3410 nodes[1], nodes[3], nodes[5]));
3412 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3413 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3414 tmpnodes[0] = nodes[0];
3415 tmpnodes[1] = nodes[2];
3416 tmpnodes[2] = nodes[4];
3417 tmpnodes[3] = nodes[1];
3418 tmpnodes[4] = nodes[3];
3419 tmpnodes[5] = nodes[5];
3420 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3423 else { /////// quadratic quadrangle
3424 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3425 nodes[1], nodes[3], nodes[5], nodes[7] );
3427 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3428 nodes[1], nodes[3], nodes[5], nodes[7]));
3430 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3431 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3432 tmpnodes[0] = nodes[0];
3433 tmpnodes[1] = nodes[2];
3434 tmpnodes[2] = nodes[4];
3435 tmpnodes[3] = nodes[6];
3436 tmpnodes[4] = nodes[1];
3437 tmpnodes[5] = nodes[3];
3438 tmpnodes[6] = nodes[5];
3439 tmpnodes[7] = nodes[7];
3440 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3444 else { //////// polygon
3445 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3446 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3448 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3449 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3450 aMesh->ChangeElementNodes( f, nodes, nbn );
3453 while ( srcElements.Length() < myLastCreatedElems.Length() )
3454 srcElements.Append( *srcEdge );
3456 } // loop on free faces
3458 // go to the next volume
3460 while ( iVol++ < nbVolumesByStep ) v++;
3463 } // sweep free links into faces
3465 // Make a ceiling face with a normal external to a volume
3467 SMDS_VolumeTool lastVol( itElem->second.back() );
3469 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3471 lastVol.SetExternalNormal();
3472 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3473 int nbn = lastVol.NbFaceNodes( iF );
3476 if (!hasFreeLinks ||
3477 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3478 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3481 if (!hasFreeLinks ||
3482 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3483 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3486 if(itElem->second.back()->IsQuadratic()) {
3488 if (!hasFreeLinks ||
3489 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3490 nodes[1], nodes[3], nodes[5]) ) {
3491 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3492 nodes[1], nodes[3], nodes[5]));
3496 if (!hasFreeLinks ||
3497 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3498 nodes[1], nodes[3], nodes[5], nodes[7]) )
3499 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3500 nodes[1], nodes[3], nodes[5], nodes[7]));
3504 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3505 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3506 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3510 while ( srcElements.Length() < myLastCreatedElems.Length() )
3511 srcElements.Append( myLastCreatedElems.Last() );
3513 } // loop on swept elements
3516 //=======================================================================
3517 //function : RotationSweep
3519 //=======================================================================
3521 SMESH_MeshEditor::PGroupIDs
3522 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3523 const gp_Ax1& theAxis,
3524 const double theAngle,
3525 const int theNbSteps,
3526 const double theTol,
3527 const bool theMakeGroups,
3528 const bool theMakeWalls)
3530 myLastCreatedElems.Clear();
3531 myLastCreatedNodes.Clear();
3533 // source elements for each generated one
3534 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3536 MESSAGE( "RotationSweep()");
3538 aTrsf.SetRotation( theAxis, theAngle );
3540 aTrsf2.SetRotation( theAxis, theAngle/2. );
3542 gp_Lin aLine( theAxis );
3543 double aSqTol = theTol * theTol;
3545 SMESHDS_Mesh* aMesh = GetMeshDS();
3547 TNodeOfNodeListMap mapNewNodes;
3548 TElemOfVecOfNnlmiMap mapElemNewNodes;
3549 TElemOfElemListMap newElemsMap;
3552 TIDSortedElemSet::iterator itElem;
3553 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3554 const SMDS_MeshElement* elem = *itElem;
3555 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3557 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3558 newNodesItVec.reserve( elem->NbNodes() );
3560 // loop on elem nodes
3561 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3562 while ( itN->more() ) {
3563 // check if a node has been already sweeped
3564 const SMDS_MeshNode* node = cast2Node( itN->next() );
3566 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3568 aXYZ.Coord( coord[0], coord[1], coord[2] );
3569 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3571 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3572 if ( nIt == mapNewNodes.end() ) {
3573 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3574 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3577 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3579 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3580 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3581 const SMDS_MeshNode * newNode = node;
3582 for ( int i = 0; i < theNbSteps; i++ ) {
3584 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3586 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3587 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3588 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3589 myLastCreatedNodes.Append(newNode);
3590 srcNodes.Append( node );
3591 listNewNodes.push_back( newNode );
3592 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3593 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3596 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3598 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3599 myLastCreatedNodes.Append(newNode);
3600 srcNodes.Append( node );
3601 listNewNodes.push_back( newNode );
3604 listNewNodes.push_back( newNode );
3605 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3606 listNewNodes.push_back( newNode );
3613 // if current elem is quadratic and current node is not medium
3614 // we have to check - may be it is needed to insert additional nodes
3615 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3616 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3617 if(listNewNodes.size()==theNbSteps) {
3618 listNewNodes.clear();
3620 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3622 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3623 const SMDS_MeshNode * newNode = node;
3625 for(int i = 0; i<theNbSteps; i++) {
3626 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3627 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3628 cout<<" 3 AddNode: "<<newNode;
3629 myLastCreatedNodes.Append(newNode);
3630 listNewNodes.push_back( newNode );
3631 srcNodes.Append( node );
3632 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3633 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3634 cout<<" 4 AddNode: "<<newNode;
3635 myLastCreatedNodes.Append(newNode);
3636 srcNodes.Append( node );
3637 listNewNodes.push_back( newNode );
3641 listNewNodes.push_back( newNode );
3647 newNodesItVec.push_back( nIt );
3649 // make new elements
3650 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3654 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3656 PGroupIDs newGroupIDs;
3657 if ( theMakeGroups )
3658 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3664 //=======================================================================
3665 //function : CreateNode
3667 //=======================================================================
3668 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3671 const double tolnode,
3672 SMESH_SequenceOfNode& aNodes)
3674 myLastCreatedElems.Clear();
3675 myLastCreatedNodes.Clear();
3678 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3680 // try to search in sequence of existing nodes
3681 // if aNodes.Length()>0 we 'nave to use given sequence
3682 // else - use all nodes of mesh
3683 if(aNodes.Length()>0) {
3685 for(i=1; i<=aNodes.Length(); i++) {
3686 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3687 if(P1.Distance(P2)<tolnode)
3688 return aNodes.Value(i);
3692 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3693 while(itn->more()) {
3694 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3695 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3696 if(P1.Distance(P2)<tolnode)
3701 // create new node and return it
3702 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3703 myLastCreatedNodes.Append(NewNode);
3708 //=======================================================================
3709 //function : ExtrusionSweep
3711 //=======================================================================
3713 SMESH_MeshEditor::PGroupIDs
3714 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3715 const gp_Vec& theStep,
3716 const int theNbSteps,
3717 TElemOfElemListMap& newElemsMap,
3718 const bool theMakeGroups,
3720 const double theTolerance)
3722 ExtrusParam aParams;
3723 aParams.myDir = gp_Dir(theStep);
3724 aParams.myNodes.Clear();
3725 aParams.mySteps = new TColStd_HSequenceOfReal;
3727 for(i=1; i<=theNbSteps; i++)
3728 aParams.mySteps->Append(theStep.Magnitude());
3731 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3735 //=======================================================================
3736 //function : ExtrusionSweep
3738 //=======================================================================
3740 SMESH_MeshEditor::PGroupIDs
3741 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3742 ExtrusParam& theParams,
3743 TElemOfElemListMap& newElemsMap,
3744 const bool theMakeGroups,
3746 const double theTolerance)
3748 myLastCreatedElems.Clear();
3749 myLastCreatedNodes.Clear();
3751 // source elements for each generated one
3752 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3754 SMESHDS_Mesh* aMesh = GetMeshDS();
3756 int nbsteps = theParams.mySteps->Length();
3758 TNodeOfNodeListMap mapNewNodes;
3759 //TNodeOfNodeVecMap mapNewNodes;
3760 TElemOfVecOfNnlmiMap mapElemNewNodes;
3761 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3764 TIDSortedElemSet::iterator itElem;
3765 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3766 // check element type
3767 const SMDS_MeshElement* elem = *itElem;
3768 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3771 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3772 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3773 newNodesItVec.reserve( elem->NbNodes() );
3775 // loop on elem nodes
3776 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3777 while ( itN->more() )
3779 // check if a node has been already sweeped
3780 const SMDS_MeshNode* node = cast2Node( itN->next() );
3781 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3782 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3783 if ( nIt == mapNewNodes.end() ) {
3784 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3785 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3786 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3787 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3788 //vecNewNodes.reserve(nbsteps);
3791 double coord[] = { node->X(), node->Y(), node->Z() };
3792 //int nbsteps = theParams.mySteps->Length();
3793 for ( int i = 0; i < nbsteps; i++ ) {
3794 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3795 // create additional node
3796 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3797 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3798 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3799 if( theFlags & EXTRUSION_FLAG_SEW ) {
3800 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3801 theTolerance, theParams.myNodes);
3802 listNewNodes.push_back( newNode );
3805 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3806 myLastCreatedNodes.Append(newNode);
3807 srcNodes.Append( node );
3808 listNewNodes.push_back( newNode );
3811 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3812 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3813 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3814 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3815 if( theFlags & EXTRUSION_FLAG_SEW ) {
3816 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3817 theTolerance, theParams.myNodes);
3818 listNewNodes.push_back( newNode );
3819 //vecNewNodes[i]=newNode;
3822 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3823 myLastCreatedNodes.Append(newNode);
3824 srcNodes.Append( node );
3825 listNewNodes.push_back( newNode );
3826 //vecNewNodes[i]=newNode;
3831 // if current elem is quadratic and current node is not medium
3832 // we have to check - may be it is needed to insert additional nodes
3833 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3834 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3835 if(listNewNodes.size()==nbsteps) {
3836 listNewNodes.clear();
3837 double coord[] = { node->X(), node->Y(), node->Z() };
3838 for ( int i = 0; i < nbsteps; i++ ) {
3839 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3840 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3841 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3842 if( theFlags & EXTRUSION_FLAG_SEW ) {
3843 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3844 theTolerance, theParams.myNodes);
3845 listNewNodes.push_back( newNode );
3848 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3849 myLastCreatedNodes.Append(newNode);
3850 srcNodes.Append( node );
3851 listNewNodes.push_back( newNode );
3853 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3854 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3855 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3856 if( theFlags & EXTRUSION_FLAG_SEW ) {
3857 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3858 theTolerance, theParams.myNodes);
3859 listNewNodes.push_back( newNode );
3862 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3863 myLastCreatedNodes.Append(newNode);
3864 srcNodes.Append( node );
3865 listNewNodes.push_back( newNode );
3871 newNodesItVec.push_back( nIt );
3873 // make new elements
3874 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3877 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3878 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3880 PGroupIDs newGroupIDs;
3881 if ( theMakeGroups )
3882 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3888 //=======================================================================
3889 //class : SMESH_MeshEditor_PathPoint
3890 //purpose : auxiliary class
3891 //=======================================================================
3892 class SMESH_MeshEditor_PathPoint {
3894 SMESH_MeshEditor_PathPoint() {
3895 myPnt.SetCoord(99., 99., 99.);
3896 myTgt.SetCoord(1.,0.,0.);
3900 void SetPnt(const gp_Pnt& aP3D){
3903 void SetTangent(const gp_Dir& aTgt){
3906 void SetAngle(const double& aBeta){
3909 void SetParameter(const double& aPrm){
3912 const gp_Pnt& Pnt()const{
3915 const gp_Dir& Tangent()const{
3918 double Angle()const{
3921 double Parameter()const{
3933 //=======================================================================
3934 //function : ExtrusionAlongTrack
3936 //=======================================================================
3937 SMESH_MeshEditor::Extrusion_Error
3938 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3939 SMESH_subMesh* theTrack,
3940 const SMDS_MeshNode* theN1,
3941 const bool theHasAngles,
3942 list<double>& theAngles,
3943 const bool theLinearVariation,
3944 const bool theHasRefPoint,
3945 const gp_Pnt& theRefPoint,
3946 const bool theMakeGroups)
3948 myLastCreatedElems.Clear();
3949 myLastCreatedNodes.Clear();
3952 std::list<double> aPrms;
3953 TIDSortedElemSet::iterator itElem;
3956 TopoDS_Edge aTrackEdge;
3957 TopoDS_Vertex aV1, aV2;
3959 SMDS_ElemIteratorPtr aItE;
3960 SMDS_NodeIteratorPtr aItN;
3961 SMDSAbs_ElementType aTypeE;
3963 TNodeOfNodeListMap mapNewNodes;
3966 aNbE = theElements.size();
3969 return EXTR_NO_ELEMENTS;
3971 // 1.1 Track Pattern
3974 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3976 aItE = pSubMeshDS->GetElements();
3977 while ( aItE->more() ) {
3978 const SMDS_MeshElement* pE = aItE->next();
3979 aTypeE = pE->GetType();
3980 // Pattern must contain links only
3981 if ( aTypeE != SMDSAbs_Edge )
3982 return EXTR_PATH_NOT_EDGE;
3985 list<SMESH_MeshEditor_PathPoint> fullList;
3987 const TopoDS_Shape& aS = theTrack->GetSubShape();
3988 // Sub shape for the Pattern must be an Edge or Wire
3989 if( aS.ShapeType() == TopAbs_EDGE ) {
3990 aTrackEdge = TopoDS::Edge( aS );
3991 // the Edge must not be degenerated
3992 if ( BRep_Tool::Degenerated( aTrackEdge ) )
3993 return EXTR_BAD_PATH_SHAPE;
3994 TopExp::Vertices( aTrackEdge, aV1, aV2 );
3995 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3996 const SMDS_MeshNode* aN1 = aItN->next();
3997 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3998 const SMDS_MeshNode* aN2 = aItN->next();
3999 // starting node must be aN1 or aN2
4000 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4001 return EXTR_BAD_STARTING_NODE;
4002 aItN = pSubMeshDS->GetNodes();
4003 while ( aItN->more() ) {
4004 const SMDS_MeshNode* pNode = aItN->next();
4005 const SMDS_EdgePosition* pEPos =
4006 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4007 double aT = pEPos->GetUParameter();
4008 aPrms.push_back( aT );
4010 //Extrusion_Error err =
4011 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4013 else if( aS.ShapeType() == TopAbs_WIRE ) {
4014 list< SMESH_subMesh* > LSM;
4015 TopTools_SequenceOfShape Edges;
4016 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4017 while(itSM->more()) {
4018 SMESH_subMesh* SM = itSM->next();
4020 const TopoDS_Shape& aS = SM->GetSubShape();
4023 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4024 int startNid = theN1->GetID();
4025 TColStd_MapOfInteger UsedNums;
4026 int NbEdges = Edges.Length();
4028 for(; i<=NbEdges; i++) {
4030 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4031 for(; itLSM!=LSM.end(); itLSM++) {
4033 if(UsedNums.Contains(k)) continue;
4034 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4035 SMESH_subMesh* locTrack = *itLSM;
4036 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4037 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4038 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4039 const SMDS_MeshNode* aN1 = aItN->next();
4040 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4041 const SMDS_MeshNode* aN2 = aItN->next();
4042 // starting node must be aN1 or aN2
4043 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4044 // 2. Collect parameters on the track edge
4046 aItN = locMeshDS->GetNodes();
4047 while ( aItN->more() ) {
4048 const SMDS_MeshNode* pNode = aItN->next();
4049 const SMDS_EdgePosition* pEPos =
4050 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4051 double aT = pEPos->GetUParameter();
4052 aPrms.push_back( aT );
4054 list<SMESH_MeshEditor_PathPoint> LPP;
4055 //Extrusion_Error err =
4056 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4057 LLPPs.push_back(LPP);
4059 // update startN for search following egde
4060 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4061 else startNid = aN1->GetID();
4065 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4066 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4067 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4068 for(; itPP!=firstList.end(); itPP++) {
4069 fullList.push_back( *itPP );
4071 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4072 fullList.pop_back();
4074 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4075 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4076 itPP = currList.begin();
4077 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4078 gp_Dir D1 = PP1.Tangent();
4079 gp_Dir D2 = PP2.Tangent();
4080 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4081 (D1.Z()+D2.Z())/2 ) );
4082 PP1.SetTangent(Dnew);
4083 fullList.push_back(PP1);
4085 for(; itPP!=firstList.end(); itPP++) {
4086 fullList.push_back( *itPP );
4088 PP1 = fullList.back();
4089 fullList.pop_back();
4091 // if wire not closed
4092 fullList.push_back(PP1);
4096 return EXTR_BAD_PATH_SHAPE;
4099 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4100 theHasRefPoint, theRefPoint, theMakeGroups);
4104 //=======================================================================
4105 //function : ExtrusionAlongTrack
4107 //=======================================================================
4108 SMESH_MeshEditor::Extrusion_Error
4109 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4110 SMESH_Mesh* theTrack,
4111 const SMDS_MeshNode* theN1,
4112 const bool theHasAngles,
4113 list<double>& theAngles,
4114 const bool theLinearVariation,
4115 const bool theHasRefPoint,
4116 const gp_Pnt& theRefPoint,
4117 const bool theMakeGroups)
4119 myLastCreatedElems.Clear();
4120 myLastCreatedNodes.Clear();
4123 std::list<double> aPrms;
4124 TIDSortedElemSet::iterator itElem;
4127 TopoDS_Edge aTrackEdge;
4128 TopoDS_Vertex aV1, aV2;
4130 SMDS_ElemIteratorPtr aItE;
4131 SMDS_NodeIteratorPtr aItN;
4132 SMDSAbs_ElementType aTypeE;
4134 TNodeOfNodeListMap mapNewNodes;
4137 aNbE = theElements.size();
4140 return EXTR_NO_ELEMENTS;
4142 // 1.1 Track Pattern
4145 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4147 aItE = pMeshDS->elementsIterator();
4148 while ( aItE->more() ) {
4149 const SMDS_MeshElement* pE = aItE->next();
4150 aTypeE = pE->GetType();
4151 // Pattern must contain links only
4152 if ( aTypeE != SMDSAbs_Edge )
4153 return EXTR_PATH_NOT_EDGE;
4156 list<SMESH_MeshEditor_PathPoint> fullList;
4158 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4159 // Sub shape for the Pattern must be an Edge or Wire
4160 if( aS.ShapeType() == TopAbs_EDGE ) {
4161 aTrackEdge = TopoDS::Edge( aS );
4162 // the Edge must not be degenerated
4163 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4164 return EXTR_BAD_PATH_SHAPE;
4165 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4166 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4167 const SMDS_MeshNode* aN1 = aItN->next();
4168 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4169 const SMDS_MeshNode* aN2 = aItN->next();
4170 // starting node must be aN1 or aN2
4171 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4172 return EXTR_BAD_STARTING_NODE;
4173 aItN = pMeshDS->nodesIterator();
4174 while ( aItN->more() ) {
4175 const SMDS_MeshNode* pNode = aItN->next();
4176 if( pNode==aN1 || pNode==aN2 ) continue;
4177 const SMDS_EdgePosition* pEPos =
4178 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4179 double aT = pEPos->GetUParameter();
4180 aPrms.push_back( aT );
4182 //Extrusion_Error err =
4183 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4185 else if( aS.ShapeType() == TopAbs_WIRE ) {
4186 list< SMESH_subMesh* > LSM;
4187 TopTools_SequenceOfShape Edges;
4188 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4189 for(; eExp.More(); eExp.Next()) {
4190 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4191 if( BRep_Tool::Degenerated(E) ) continue;
4192 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4198 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4199 int startNid = theN1->GetID();
4200 TColStd_MapOfInteger UsedNums;
4201 int NbEdges = Edges.Length();
4203 for(; i<=NbEdges; i++) {
4205 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4206 for(; itLSM!=LSM.end(); itLSM++) {
4208 if(UsedNums.Contains(k)) continue;
4209 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4210 SMESH_subMesh* locTrack = *itLSM;
4211 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4212 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4213 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4214 const SMDS_MeshNode* aN1 = aItN->next();
4215 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4216 const SMDS_MeshNode* aN2 = aItN->next();
4217 // starting node must be aN1 or aN2
4218 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4219 // 2. Collect parameters on the track edge
4221 aItN = locMeshDS->GetNodes();
4222 while ( aItN->more() ) {
4223 const SMDS_MeshNode* pNode = aItN->next();
4224 const SMDS_EdgePosition* pEPos =
4225 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4226 double aT = pEPos->GetUParameter();
4227 aPrms.push_back( aT );
4229 list<SMESH_MeshEditor_PathPoint> LPP;
4230 //Extrusion_Error err =
4231 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4232 LLPPs.push_back(LPP);
4234 // update startN for search following egde
4235 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4236 else startNid = aN1->GetID();
4240 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4241 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4242 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4243 for(; itPP!=firstList.end(); itPP++) {
4244 fullList.push_back( *itPP );
4246 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4247 fullList.pop_back();
4249 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4250 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4251 itPP = currList.begin();
4252 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4253 gp_Pnt P1 = PP1.Pnt();
4254 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4255 gp_Pnt P2 = PP2.Pnt();
4256 gp_Dir D1 = PP1.Tangent();
4257 gp_Dir D2 = PP2.Tangent();
4258 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4259 (D1.Z()+D2.Z())/2 ) );
4260 PP1.SetTangent(Dnew);
4261 fullList.push_back(PP1);
4263 for(; itPP!=currList.end(); itPP++) {
4264 fullList.push_back( *itPP );
4266 PP1 = fullList.back();
4267 fullList.pop_back();
4269 // if wire not closed
4270 fullList.push_back(PP1);
4274 return EXTR_BAD_PATH_SHAPE;
4277 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4278 theHasRefPoint, theRefPoint, theMakeGroups);
4282 //=======================================================================
4283 //function : MakeEdgePathPoints
4284 //purpose : auxilary for ExtrusionAlongTrack
4285 //=======================================================================
4286 SMESH_MeshEditor::Extrusion_Error
4287 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4288 const TopoDS_Edge& aTrackEdge,
4290 list<SMESH_MeshEditor_PathPoint>& LPP)
4292 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4294 aTolVec2=aTolVec*aTolVec;
4296 TopoDS_Vertex aV1, aV2;
4297 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4298 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4299 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4300 // 2. Collect parameters on the track edge
4301 aPrms.push_front( aT1 );
4302 aPrms.push_back( aT2 );
4305 if( FirstIsStart ) {
4316 SMESH_MeshEditor_PathPoint aPP;
4317 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4318 std::list<double>::iterator aItD = aPrms.begin();
4319 for(; aItD != aPrms.end(); ++aItD) {
4323 aC3D->D1( aT, aP3D, aVec );
4324 aL2 = aVec.SquareMagnitude();
4325 if ( aL2 < aTolVec2 )
4326 return EXTR_CANT_GET_TANGENT;
4327 gp_Dir aTgt( aVec );
4329 aPP.SetTangent( aTgt );
4330 aPP.SetParameter( aT );
4337 //=======================================================================
4338 //function : MakeExtrElements
4339 //purpose : auxilary for ExtrusionAlongTrack
4340 //=======================================================================
4341 SMESH_MeshEditor::Extrusion_Error
4342 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4343 list<SMESH_MeshEditor_PathPoint>& fullList,
4344 const bool theHasAngles,
4345 list<double>& theAngles,
4346 const bool theLinearVariation,
4347 const bool theHasRefPoint,
4348 const gp_Pnt& theRefPoint,
4349 const bool theMakeGroups)
4351 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4352 int aNbTP = fullList.size();
4353 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4355 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4356 LinearAngleVariation(aNbTP-1, theAngles);
4358 vector<double> aAngles( aNbTP );
4360 for(; j<aNbTP; ++j) {
4363 if ( theHasAngles ) {
4365 std::list<double>::iterator aItD = theAngles.begin();
4366 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4368 aAngles[j] = anAngle;
4371 // fill vector of path points with angles
4372 //aPPs.resize(fullList.size());
4374 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4375 for(; itPP!=fullList.end(); itPP++) {
4377 SMESH_MeshEditor_PathPoint PP = *itPP;
4378 PP.SetAngle(aAngles[j]);
4382 TNodeOfNodeListMap mapNewNodes;
4383 TElemOfVecOfNnlmiMap mapElemNewNodes;
4384 TElemOfElemListMap newElemsMap;
4385 TIDSortedElemSet::iterator itElem;
4388 SMDSAbs_ElementType aTypeE;
4389 // source elements for each generated one
4390 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4392 // 3. Center of rotation aV0
4393 gp_Pnt aV0 = theRefPoint;
4395 if ( !theHasRefPoint ) {
4397 aGC.SetCoord( 0.,0.,0. );
4399 itElem = theElements.begin();
4400 for ( ; itElem != theElements.end(); itElem++ ) {
4401 const SMDS_MeshElement* elem = *itElem;
4403 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4404 while ( itN->more() ) {
4405 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4410 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4411 list<const SMDS_MeshNode*> aLNx;
4412 mapNewNodes[node] = aLNx;
4414 gp_XYZ aXYZ( aX, aY, aZ );
4422 } // if (!theHasRefPoint) {
4423 mapNewNodes.clear();
4425 // 4. Processing the elements
4426 SMESHDS_Mesh* aMesh = GetMeshDS();
4428 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4429 // check element type
4430 const SMDS_MeshElement* elem = *itElem;
4431 aTypeE = elem->GetType();
4432 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4435 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4436 newNodesItVec.reserve( elem->NbNodes() );
4438 // loop on elem nodes
4440 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4441 while ( itN->more() )
4444 // check if a node has been already processed
4445 const SMDS_MeshNode* node =
4446 static_cast<const SMDS_MeshNode*>( itN->next() );
4447 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4448 if ( nIt == mapNewNodes.end() ) {
4449 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4450 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4453 aX = node->X(); aY = node->Y(); aZ = node->Z();
4455 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4456 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4457 gp_Ax1 anAx1, anAxT1T0;
4458 gp_Dir aDT1x, aDT0x, aDT1T0;
4463 aPN0.SetCoord(aX, aY, aZ);
4465 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4467 aDT0x= aPP0.Tangent();
4468 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4470 for ( j = 1; j < aNbTP; ++j ) {
4471 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4473 aDT1x = aPP1.Tangent();
4474 aAngle1x = aPP1.Angle();
4476 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4478 gp_Vec aV01x( aP0x, aP1x );
4479 aTrsf.SetTranslation( aV01x );
4482 aV1x = aV0x.Transformed( aTrsf );
4483 aPN1 = aPN0.Transformed( aTrsf );
4485 // rotation 1 [ T1,T0 ]
4486 aAngleT1T0=-aDT1x.Angle( aDT0x );
4487 if (fabs(aAngleT1T0) > aTolAng) {
4489 anAxT1T0.SetLocation( aV1x );
4490 anAxT1T0.SetDirection( aDT1T0 );
4491 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4493 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4497 if ( theHasAngles ) {
4498 anAx1.SetLocation( aV1x );
4499 anAx1.SetDirection( aDT1x );
4500 aTrsfRot.SetRotation( anAx1, aAngle1x );
4502 aPN1 = aPN1.Transformed( aTrsfRot );
4506 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4507 // create additional node
4508 double x = ( aPN1.X() + aPN0.X() )/2.;
4509 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4510 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4511 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4512 myLastCreatedNodes.Append(newNode);
4513 srcNodes.Append( node );
4514 listNewNodes.push_back( newNode );
4519 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4520 myLastCreatedNodes.Append(newNode);
4521 srcNodes.Append( node );
4522 listNewNodes.push_back( newNode );
4532 // if current elem is quadratic and current node is not medium
4533 // we have to check - may be it is needed to insert additional nodes
4534 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4535 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4536 if(listNewNodes.size()==aNbTP-1) {
4537 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4538 gp_XYZ P(node->X(), node->Y(), node->Z());
4539 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4541 for(i=0; i<aNbTP-1; i++) {
4542 const SMDS_MeshNode* N = *it;
4543 double x = ( N->X() + P.X() )/2.;
4544 double y = ( N->Y() + P.Y() )/2.;
4545 double z = ( N->Z() + P.Z() )/2.;
4546 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4547 srcNodes.Append( node );
4548 myLastCreatedNodes.Append(newN);
4551 P = gp_XYZ(N->X(),N->Y(),N->Z());
4553 listNewNodes.clear();
4554 for(i=0; i<2*(aNbTP-1); i++) {
4555 listNewNodes.push_back(aNodes[i]);
4561 newNodesItVec.push_back( nIt );
4563 // make new elements
4564 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4565 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4566 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4569 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4571 if ( theMakeGroups )
4572 generateGroups( srcNodes, srcElems, "extruded");
4578 //=======================================================================
4579 //function : LinearAngleVariation
4580 //purpose : auxilary for ExtrusionAlongTrack
4581 //=======================================================================
4582 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4583 list<double>& Angles)
4585 int nbAngles = Angles.size();
4586 if( nbSteps > nbAngles ) {
4587 vector<double> theAngles(nbAngles);
4588 list<double>::iterator it = Angles.begin();
4590 for(; it!=Angles.end(); it++) {
4592 theAngles[i] = (*it);
4595 double rAn2St = double( nbAngles ) / double( nbSteps );
4596 double angPrev = 0, angle;
4597 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4598 double angCur = rAn2St * ( iSt+1 );
4599 double angCurFloor = floor( angCur );
4600 double angPrevFloor = floor( angPrev );
4601 if ( angPrevFloor == angCurFloor )
4602 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4604 int iP = int( angPrevFloor );
4605 double angPrevCeil = ceil(angPrev);
4606 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4608 int iC = int( angCurFloor );
4609 if ( iC < nbAngles )
4610 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4612 iP = int( angPrevCeil );
4614 angle += theAngles[ iC ];
4616 res.push_back(angle);
4621 for(; it!=res.end(); it++)
4622 Angles.push_back( *it );
4627 //=======================================================================
4628 //function : Transform
4630 //=======================================================================
4632 SMESH_MeshEditor::PGroupIDs
4633 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4634 const gp_Trsf& theTrsf,
4636 const bool theMakeGroups,
4637 SMESH_Mesh* theTargetMesh)
4639 myLastCreatedElems.Clear();
4640 myLastCreatedNodes.Clear();
4642 bool needReverse = false;
4643 string groupPostfix;
4644 switch ( theTrsf.Form() ) {
4649 groupPostfix = "mirrored";
4652 groupPostfix = "rotated";
4654 case gp_Translation:
4655 groupPostfix = "translated";
4658 groupPostfix = "scaled";
4661 needReverse = false;
4662 groupPostfix = "transformed";
4665 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4666 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4667 SMESHDS_Mesh* aMesh = GetMeshDS();
4670 // map old node to new one
4671 TNodeNodeMap nodeMap;
4673 // elements sharing moved nodes; those of them which have all
4674 // nodes mirrored but are not in theElems are to be reversed
4675 TIDSortedElemSet inverseElemSet;
4677 // source elements for each generated one
4678 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4681 TIDSortedElemSet::iterator itElem;
4682 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4683 const SMDS_MeshElement* elem = *itElem;
4687 // loop on elem nodes
4688 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4689 while ( itN->more() ) {
4691 // check if a node has been already transformed
4692 const SMDS_MeshNode* node = cast2Node( itN->next() );
4693 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4694 nodeMap.insert( make_pair ( node, node ));
4695 if ( !n2n_isnew.second )
4699 coord[0] = node->X();
4700 coord[1] = node->Y();
4701 coord[2] = node->Z();
4702 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4703 if ( theTargetMesh ) {
4704 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4705 n2n_isnew.first->second = newNode;
4706 myLastCreatedNodes.Append(newNode);
4707 srcNodes.Append( node );
4709 else if ( theCopy ) {
4710 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4711 n2n_isnew.first->second = newNode;
4712 myLastCreatedNodes.Append(newNode);
4713 srcNodes.Append( node );
4716 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4717 // node position on shape becomes invalid
4718 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4719 ( SMDS_SpacePosition::originSpacePosition() );
4722 // keep inverse elements
4723 if ( !theCopy && !theTargetMesh && needReverse ) {
4724 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4725 while ( invElemIt->more() ) {
4726 const SMDS_MeshElement* iel = invElemIt->next();
4727 inverseElemSet.insert( iel );
4733 // either create new elements or reverse mirrored ones
4734 if ( !theCopy && !needReverse && !theTargetMesh )
4737 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4738 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4739 theElems.insert( *invElemIt );
4741 // replicate or reverse elements
4744 REV_TETRA = 0, // = nbNodes - 4
4745 REV_PYRAMID = 1, // = nbNodes - 4
4746 REV_PENTA = 2, // = nbNodes - 4
4748 REV_HEXA = 4, // = nbNodes - 4
4752 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4753 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4754 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4755 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4756 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4757 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4760 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4762 const SMDS_MeshElement* elem = *itElem;
4763 if ( !elem || elem->GetType() == SMDSAbs_Node )
4766 int nbNodes = elem->NbNodes();
4767 int elemType = elem->GetType();
4769 if (elem->IsPoly()) {
4770 // Polygon or Polyhedral Volume
4771 switch ( elemType ) {
4774 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4776 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4777 while (itN->more()) {
4778 const SMDS_MeshNode* node =
4779 static_cast<const SMDS_MeshNode*>(itN->next());
4780 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4781 if (nodeMapIt == nodeMap.end())
4782 break; // not all nodes transformed
4784 // reverse mirrored faces and volumes
4785 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4787 poly_nodes[iNode] = (*nodeMapIt).second;
4791 if ( iNode != nbNodes )
4792 continue; // not all nodes transformed
4794 if ( theTargetMesh ) {
4795 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4796 srcElems.Append( elem );
4798 else if ( theCopy ) {
4799 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4800 srcElems.Append( elem );
4803 aMesh->ChangePolygonNodes(elem, poly_nodes);
4807 case SMDSAbs_Volume:
4809 // ATTENTION: Reversing is not yet done!!!
4810 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4811 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4813 MESSAGE("Warning: bad volumic element");
4817 vector<const SMDS_MeshNode*> poly_nodes;
4818 vector<int> quantities;
4820 bool allTransformed = true;
4821 int nbFaces = aPolyedre->NbFaces();
4822 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4823 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4824 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4825 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4826 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4827 if (nodeMapIt == nodeMap.end()) {
4828 allTransformed = false; // not all nodes transformed
4830 poly_nodes.push_back((*nodeMapIt).second);
4833 quantities.push_back(nbFaceNodes);
4835 if ( !allTransformed )
4836 continue; // not all nodes transformed
4838 if ( theTargetMesh ) {
4839 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4840 srcElems.Append( elem );
4842 else if ( theCopy ) {
4843 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4844 srcElems.Append( elem );
4847 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4857 int* i = index[ FORWARD ];
4858 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4859 if ( elemType == SMDSAbs_Face )
4860 i = index[ REV_FACE ];
4862 i = index[ nbNodes - 4 ];
4864 if(elem->IsQuadratic()) {
4865 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4868 if(nbNodes==3) { // quadratic edge
4869 static int anIds[] = {1,0,2};
4872 else if(nbNodes==6) { // quadratic triangle
4873 static int anIds[] = {0,2,1,5,4,3};
4876 else if(nbNodes==8) { // quadratic quadrangle
4877 static int anIds[] = {0,3,2,1,7,6,5,4};
4880 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4881 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4884 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4885 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4888 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4889 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4892 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4893 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4899 // find transformed nodes
4900 vector<const SMDS_MeshNode*> nodes(nbNodes);
4902 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4903 while ( itN->more() ) {
4904 const SMDS_MeshNode* node =
4905 static_cast<const SMDS_MeshNode*>( itN->next() );
4906 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4907 if ( nodeMapIt == nodeMap.end() )
4908 break; // not all nodes transformed
4909 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4911 if ( iNode != nbNodes )
4912 continue; // not all nodes transformed
4914 if ( theTargetMesh ) {
4915 if ( SMDS_MeshElement* copy =
4916 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4917 myLastCreatedElems.Append( copy );
4918 srcElems.Append( elem );
4921 else if ( theCopy ) {
4922 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4923 myLastCreatedElems.Append( copy );
4924 srcElems.Append( elem );
4928 // reverse element as it was reversed by transformation
4930 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4934 PGroupIDs newGroupIDs;
4936 if ( theMakeGroups && theCopy ||
4937 theMakeGroups && theTargetMesh )
4938 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4943 //=======================================================================
4945 * \brief Create groups of elements made during transformation
4946 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4947 * \param elemGens - elements making corresponding myLastCreatedElems
4948 * \param postfix - to append to names of new groups
4950 //=======================================================================
4952 SMESH_MeshEditor::PGroupIDs
4953 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4954 const SMESH_SequenceOfElemPtr& elemGens,
4955 const std::string& postfix,
4956 SMESH_Mesh* targetMesh)
4958 PGroupIDs newGroupIDs( new list<int> );
4959 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4961 // Sort existing groups by types and collect their names
4963 // to store an old group and a generated new one
4964 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4965 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4967 set< string > groupNames;
4969 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4970 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4971 while ( groupIt->more() ) {
4972 SMESH_Group * group = groupIt->next();
4973 if ( !group ) continue;
4974 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4975 if ( !groupDS || groupDS->IsEmpty() ) continue;
4976 groupNames.insert( group->GetName() );
4977 groupDS->SetStoreName( group->GetName() );
4978 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4983 // loop on nodes and elements
4984 for ( int isNodes = 0; isNodes < 2; ++isNodes )
4986 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
4987 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4988 if ( gens.Length() != elems.Length() )
4989 throw SALOME_Exception(LOCALIZED("invalid args"));
4991 // loop on created elements
4992 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4994 const SMDS_MeshElement* sourceElem = gens( iElem );
4995 if ( !sourceElem ) {
4996 MESSAGE("generateGroups(): NULL source element");
4999 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5000 if ( groupsOldNew.empty() ) {
5001 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5002 ++iElem; // skip all elements made by sourceElem
5005 // collect all elements made by sourceElem
5006 list< const SMDS_MeshElement* > resultElems;
5007 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5008 if ( resElem != sourceElem )
5009 resultElems.push_back( resElem );
5010 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5011 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5012 if ( resElem != sourceElem )
5013 resultElems.push_back( resElem );
5014 // do not generate element groups from node ones
5015 if ( sourceElem->GetType() == SMDSAbs_Node &&
5016 elems( iElem )->GetType() != SMDSAbs_Node )
5019 // add resultElems to groups made by ones the sourceElem belongs to
5020 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5021 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5023 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5024 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5026 SMDS_MeshGroup* & newGroup = gOldNew->second;
5027 if ( !newGroup )// create a new group
5030 string name = oldGroup->GetStoreName();
5031 if ( !targetMesh ) {
5035 while ( !groupNames.insert( name ).second ) // name exists
5041 TCollection_AsciiString nbStr(nb+1);
5042 name.resize( name.rfind('_')+1 );
5043 name += nbStr.ToCString();
5050 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5052 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5053 newGroup = & groupDS->SMDSGroup();
5054 newGroupIDs->push_back( id );
5057 // fill in a new group
5058 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5059 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5060 newGroup->Add( *resElemIt );
5063 } // loop on created elements
5064 }// loop on nodes and elements
5069 //=======================================================================
5070 //function : FindCoincidentNodes
5071 //purpose : Return list of group of nodes close to each other within theTolerance
5072 // Search among theNodes or in the whole mesh if theNodes is empty using
5073 // an Octree algorithm
5074 //=======================================================================
5076 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5077 const double theTolerance,
5078 TListOfListOfNodes & theGroupsOfNodes)
5080 myLastCreatedElems.Clear();
5081 myLastCreatedNodes.Clear();
5083 set<const SMDS_MeshNode*> nodes;
5084 if ( theNodes.empty() )
5085 { // get all nodes in the mesh
5086 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5087 while ( nIt->more() )
5088 nodes.insert( nodes.end(),nIt->next());
5092 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5096 //=======================================================================
5098 * \brief Implementation of search for the node closest to point
5100 //=======================================================================
5102 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5105 * \brief Constructor
5107 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5109 set<const SMDS_MeshNode*> nodes;
5111 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5112 while ( nIt->more() )
5113 nodes.insert( nodes.end(), nIt->next() );
5115 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5118 * \brief Do it's job
5120 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5122 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5123 list<const SMDS_MeshNode*> nodes;
5124 //const double precision = 1e-6;
5125 //myOctreeNode->NodesAround( &tgtNode, &nodes, precision );
5127 double minSqDist = DBL_MAX;
5129 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5131 // sort leafs by their distance from thePnt
5132 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5133 TDistTreeMap treeMap;
5134 list< SMESH_OctreeNode* > treeList;
5135 list< SMESH_OctreeNode* >::iterator trIt;
5136 treeList.push_back( myOctreeNode );
5137 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5139 SMESH_OctreeNode* tree = *trIt;
5140 if ( !tree->isLeaf() ) { // put children to the queue
5141 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5142 while ( cIt->more() )
5143 treeList.push_back( cIt->next() );
5145 else if ( tree->NbNodes() ) { // put tree to treeMap
5146 tree->getBox( box );
5147 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5148 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5149 if ( !it_in.second ) // not unique distance to box center
5150 treeMap.insert( it_in.first, make_pair( sqDist - 1e-13*treeMap.size(), tree ));
5153 // find distance after which there is no sense to check tree's
5154 double sqLimit = DBL_MAX;
5155 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5156 if ( treeMap.size() > 5 ) {
5157 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5158 closestTree->getBox( box );
5159 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5160 sqLimit = limit * limit;
5162 // get all nodes from trees
5163 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5164 if ( sqDist_tree->first > sqLimit )
5166 SMESH_OctreeNode* tree = sqDist_tree->second;
5167 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5170 // find closest among nodes
5171 minSqDist = DBL_MAX;
5172 const SMDS_MeshNode* closestNode = 0;
5173 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5174 for ( ; nIt != nodes.end(); ++nIt ) {
5175 double sqDist = thePnt.SquareDistance( TNodeXYZ( *nIt ) );
5176 if ( minSqDist > sqDist ) {
5186 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5188 SMESH_OctreeNode* myOctreeNode;
5191 //=======================================================================
5193 * \brief Return SMESH_NodeSearcher
5195 //=======================================================================
5197 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5199 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5202 //=======================================================================
5203 //function : SimplifyFace
5205 //=======================================================================
5206 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5207 vector<const SMDS_MeshNode *>& poly_nodes,
5208 vector<int>& quantities) const
5210 int nbNodes = faceNodes.size();
5215 set<const SMDS_MeshNode*> nodeSet;
5217 // get simple seq of nodes
5218 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5219 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5220 int iSimple = 0, nbUnique = 0;
5222 simpleNodes[iSimple++] = faceNodes[0];
5224 for (int iCur = 1; iCur < nbNodes; iCur++) {
5225 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5226 simpleNodes[iSimple++] = faceNodes[iCur];
5227 if (nodeSet.insert( faceNodes[iCur] ).second)
5231 int nbSimple = iSimple;
5232 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5242 bool foundLoop = (nbSimple > nbUnique);
5245 set<const SMDS_MeshNode*> loopSet;
5246 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5247 const SMDS_MeshNode* n = simpleNodes[iSimple];
5248 if (!loopSet.insert( n ).second) {
5252 int iC = 0, curLast = iSimple;
5253 for (; iC < curLast; iC++) {
5254 if (simpleNodes[iC] == n) break;
5256 int loopLen = curLast - iC;
5258 // create sub-element
5260 quantities.push_back(loopLen);
5261 for (; iC < curLast; iC++) {
5262 poly_nodes.push_back(simpleNodes[iC]);
5265 // shift the rest nodes (place from the first loop position)
5266 for (iC = curLast + 1; iC < nbSimple; iC++) {
5267 simpleNodes[iC - loopLen] = simpleNodes[iC];
5269 nbSimple -= loopLen;
5272 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5273 } // while (foundLoop)
5277 quantities.push_back(iSimple);
5278 for (int i = 0; i < iSimple; i++)
5279 poly_nodes.push_back(simpleNodes[i]);
5285 //=======================================================================
5286 //function : MergeNodes
5287 //purpose : In each group, the cdr of nodes are substituted by the first one
5289 //=======================================================================
5291 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5293 myLastCreatedElems.Clear();
5294 myLastCreatedNodes.Clear();
5296 SMESHDS_Mesh* aMesh = GetMeshDS();
5298 TNodeNodeMap nodeNodeMap; // node to replace - new node
5299 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5300 list< int > rmElemIds, rmNodeIds;
5302 // Fill nodeNodeMap and elems
5304 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5305 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5306 list<const SMDS_MeshNode*>& nodes = *grIt;
5307 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5308 const SMDS_MeshNode* nToKeep = *nIt;
5309 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5310 const SMDS_MeshNode* nToRemove = *nIt;
5311 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5312 if ( nToRemove != nToKeep ) {
5313 rmNodeIds.push_back( nToRemove->GetID() );
5314 AddToSameGroups( nToKeep, nToRemove, aMesh );
5317 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5318 while ( invElemIt->more() ) {
5319 const SMDS_MeshElement* elem = invElemIt->next();
5324 // Change element nodes or remove an element
5326 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5327 for ( ; eIt != elems.end(); eIt++ ) {
5328 const SMDS_MeshElement* elem = *eIt;
5329 int nbNodes = elem->NbNodes();
5330 int aShapeId = FindShape( elem );
5332 set<const SMDS_MeshNode*> nodeSet;
5333 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5334 int iUnique = 0, iCur = 0, nbRepl = 0;
5335 vector<int> iRepl( nbNodes );
5337 // get new seq of nodes
5338 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5339 while ( itN->more() ) {
5340 const SMDS_MeshNode* n =
5341 static_cast<const SMDS_MeshNode*>( itN->next() );
5343 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5344 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5346 // BUG 0020185: begin
5348 bool stopRecur = false;
5349 set<const SMDS_MeshNode*> nodesRecur;
5350 nodesRecur.insert(n);
5351 while (!stopRecur) {
5352 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5353 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5354 n = (*nnIt_i).second;
5355 if (!nodesRecur.insert(n).second) {
5356 // error: recursive dependancy
5365 iRepl[ nbRepl++ ] = iCur;
5367 curNodes[ iCur ] = n;
5368 bool isUnique = nodeSet.insert( n ).second;
5370 uniqueNodes[ iUnique++ ] = n;
5374 // Analyse element topology after replacement
5377 int nbUniqueNodes = nodeSet.size();
5378 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5379 // Polygons and Polyhedral volumes
5380 if (elem->IsPoly()) {
5382 if (elem->GetType() == SMDSAbs_Face) {
5384 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5386 for (; inode < nbNodes; inode++) {
5387 face_nodes[inode] = curNodes[inode];
5390 vector<const SMDS_MeshNode *> polygons_nodes;
5391 vector<int> quantities;
5392 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5396 for (int iface = 0; iface < nbNew - 1; iface++) {
5397 int nbNodes = quantities[iface];
5398 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5399 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5400 poly_nodes[ii] = polygons_nodes[inode];
5402 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5403 myLastCreatedElems.Append(newElem);
5405 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5407 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5410 rmElemIds.push_back(elem->GetID());
5414 else if (elem->GetType() == SMDSAbs_Volume) {
5415 // Polyhedral volume
5416 if (nbUniqueNodes < 4) {
5417 rmElemIds.push_back(elem->GetID());
5420 // each face has to be analized in order to check volume validity
5421 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5422 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5424 int nbFaces = aPolyedre->NbFaces();
5426 vector<const SMDS_MeshNode *> poly_nodes;
5427 vector<int> quantities;
5429 for (int iface = 1; iface <= nbFaces; iface++) {
5430 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5431 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5433 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5434 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5435 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5436 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5437 faceNode = (*nnIt).second;
5439 faceNodes[inode - 1] = faceNode;
5442 SimplifyFace(faceNodes, poly_nodes, quantities);
5445 if (quantities.size() > 3) {
5446 // to be done: remove coincident faces
5449 if (quantities.size() > 3)
5450 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5452 rmElemIds.push_back(elem->GetID());
5456 rmElemIds.push_back(elem->GetID());
5467 switch ( nbNodes ) {
5468 case 2: ///////////////////////////////////// EDGE
5469 isOk = false; break;
5470 case 3: ///////////////////////////////////// TRIANGLE
5471 isOk = false; break;
5473 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5475 else { //////////////////////////////////// QUADRANGLE
5476 if ( nbUniqueNodes < 3 )
5478 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5479 isOk = false; // opposite nodes stick
5482 case 6: ///////////////////////////////////// PENTAHEDRON
5483 if ( nbUniqueNodes == 4 ) {
5484 // ---------------------------------> tetrahedron
5486 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5487 // all top nodes stick: reverse a bottom
5488 uniqueNodes[ 0 ] = curNodes [ 1 ];
5489 uniqueNodes[ 1 ] = curNodes [ 0 ];
5491 else if (nbRepl == 3 &&
5492 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5493 // all bottom nodes stick: set a top before
5494 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5495 uniqueNodes[ 0 ] = curNodes [ 3 ];
5496 uniqueNodes[ 1 ] = curNodes [ 4 ];
5497 uniqueNodes[ 2 ] = curNodes [ 5 ];
5499 else if (nbRepl == 4 &&
5500 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5501 // a lateral face turns into a line: reverse a bottom
5502 uniqueNodes[ 0 ] = curNodes [ 1 ];
5503 uniqueNodes[ 1 ] = curNodes [ 0 ];
5508 else if ( nbUniqueNodes == 5 ) {
5509 // PENTAHEDRON --------------------> 2 tetrahedrons
5510 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
5511 // a bottom node sticks with a linked top one
5513 SMDS_MeshElement* newElem =
5514 aMesh->AddVolume(curNodes[ 3 ],
5517 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
5518 myLastCreatedElems.Append(newElem);
5520 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5521 // 2. : reverse a bottom
5522 uniqueNodes[ 0 ] = curNodes [ 1 ];
5523 uniqueNodes[ 1 ] = curNodes [ 0 ];
5533 if(elem->IsQuadratic()) { // Quadratic quadrangle
5546 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
5547 uniqueNodes[0] = curNodes[0];
5548 uniqueNodes[1] = curNodes[2];
5549 uniqueNodes[2] = curNodes[3];
5550 uniqueNodes[3] = curNodes[5];
5551 uniqueNodes[4] = curNodes[6];
5552 uniqueNodes[5] = curNodes[7];
5555 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
5556 uniqueNodes[0] = curNodes[0];
5557 uniqueNodes[1] = curNodes[1];
5558 uniqueNodes[2] = curNodes[2];
5559 uniqueNodes[3] = curNodes[4];
5560 uniqueNodes[4] = curNodes[5];
5561 uniqueNodes[5] = curNodes[6];
5564 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
5565 uniqueNodes[0] = curNodes[1];
5566 uniqueNodes[1] = curNodes[2];
5567 uniqueNodes[2] = curNodes[3];
5568 uniqueNodes[3] = curNodes[5];
5569 uniqueNodes[4] = curNodes[6];
5570 uniqueNodes[5] = curNodes[0];
5573 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
5574 uniqueNodes[0] = curNodes[0];
5575 uniqueNodes[1] = curNodes[1];
5576 uniqueNodes[2] = curNodes[3];
5577 uniqueNodes[3] = curNodes[4];
5578 uniqueNodes[4] = curNodes[6];
5579 uniqueNodes[5] = curNodes[7];
5582 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
5583 uniqueNodes[0] = curNodes[0];
5584 uniqueNodes[1] = curNodes[2];
5585 uniqueNodes[2] = curNodes[3];
5586 uniqueNodes[3] = curNodes[1];
5587 uniqueNodes[4] = curNodes[6];
5588 uniqueNodes[5] = curNodes[7];
5591 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
5592 uniqueNodes[0] = curNodes[0];
5593 uniqueNodes[1] = curNodes[1];
5594 uniqueNodes[2] = curNodes[2];
5595 uniqueNodes[3] = curNodes[4];
5596 uniqueNodes[4] = curNodes[5];
5597 uniqueNodes[5] = curNodes[7];
5600 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
5601 uniqueNodes[0] = curNodes[0];
5602 uniqueNodes[1] = curNodes[1];
5603 uniqueNodes[2] = curNodes[3];
5604 uniqueNodes[3] = curNodes[4];
5605 uniqueNodes[4] = curNodes[2];
5606 uniqueNodes[5] = curNodes[7];
5609 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
5610 uniqueNodes[0] = curNodes[0];
5611 uniqueNodes[1] = curNodes[1];
5612 uniqueNodes[2] = curNodes[2];
5613 uniqueNodes[3] = curNodes[4];
5614 uniqueNodes[4] = curNodes[5];
5615 uniqueNodes[5] = curNodes[3];
5621 //////////////////////////////////// HEXAHEDRON
5623 SMDS_VolumeTool hexa (elem);
5624 hexa.SetExternalNormal();
5625 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
5626 //////////////////////// ---> tetrahedron
5627 for ( int iFace = 0; iFace < 6; iFace++ ) {
5628 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5629 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5630 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5631 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5632 // one face turns into a point ...
5633 int iOppFace = hexa.GetOppFaceIndex( iFace );
5634 ind = hexa.GetFaceNodesIndices( iOppFace );
5636 iUnique = 2; // reverse a tetrahedron bottom
5637 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
5638 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5640 else if ( iUnique >= 0 )
5641 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5643 if ( nbStick == 1 ) {
5644 // ... and the opposite one - into a triangle.
5646 ind = hexa.GetFaceNodesIndices( iFace );
5647 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
5654 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
5655 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
5656 for ( int iFace = 0; iFace < 6; iFace++ ) {
5657 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5658 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
5659 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
5660 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
5661 // one face turns into a point ...
5662 int iOppFace = hexa.GetOppFaceIndex( iFace );
5663 ind = hexa.GetFaceNodesIndices( iOppFace );
5665 iUnique = 2; // reverse a tetrahedron 1 bottom
5666 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
5667 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
5669 else if ( iUnique >= 0 )
5670 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
5672 if ( nbStick == 0 ) {
5673 // ... and the opposite one is a quadrangle
5675 const int* indTop = hexa.GetFaceNodesIndices( iFace );
5676 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
5679 SMDS_MeshElement* newElem =
5680 aMesh->AddVolume(curNodes[ind[ 0 ]],
5683 curNodes[indTop[ 0 ]]);
5684 myLastCreatedElems.Append(newElem);
5686 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5693 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
5694 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
5695 // find indices of quad and tri faces
5696 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
5697 for ( iFace = 0; iFace < 6; iFace++ ) {
5698 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
5700 for ( iCur = 0; iCur < 4; iCur++ )
5701 nodeSet.insert( curNodes[ind[ iCur ]] );
5702 nbUniqueNodes = nodeSet.size();
5703 if ( nbUniqueNodes == 3 )
5704 iTriFace[ nbTri++ ] = iFace;
5705 else if ( nbUniqueNodes == 4 )
5706 iQuadFace[ nbQuad++ ] = iFace;
5708 if (nbQuad == 2 && nbTri == 4 &&
5709 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
5710 // 2 opposite quadrangles stuck with a diagonal;
5711 // sample groups of merged indices: (0-4)(2-6)
5712 // --------------------------------------------> 2 tetrahedrons
5713 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
5714 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
5715 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
5716 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
5717 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
5718 // stuck with 0-2 diagonal
5726 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
5727 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
5728 // stuck with 1-3 diagonal
5740 uniqueNodes[ 0 ] = curNodes [ i0 ];
5741 uniqueNodes[ 1 ] = curNodes [ i1d ];
5742 uniqueNodes[ 2 ] = curNodes [ i3d ];
5743 uniqueNodes[ 3 ] = curNodes [ i0t ];
5746 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
5750 myLastCreatedElems.Append(newElem);
5752 aMesh->SetMeshElementOnShape( newElem, aShapeId );
5755 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
5756 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
5757 // --------------------------------------------> prism
5758 // find 2 opposite triangles
5760 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
5761 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
5762 // find indices of kept and replaced nodes
5763 // and fill unique nodes of 2 opposite triangles
5764 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
5765 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
5766 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
5767 // fill unique nodes
5770 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
5771 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
5772 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
5774 // iCur of a linked node of the opposite face (make normals co-directed):
5775 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
5776 // check that correspondent corners of triangles are linked
5777 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
5780 uniqueNodes[ iUnique ] = n;
5781 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
5790 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
5796 } // switch ( nbNodes )
5798 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
5801 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
5802 // Change nodes of polyedre
5803 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5804 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5806 int nbFaces = aPolyedre->NbFaces();
5808 vector<const SMDS_MeshNode *> poly_nodes;
5809 vector<int> quantities (nbFaces);
5811 for (int iface = 1; iface <= nbFaces; iface++) {
5812 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5813 quantities[iface - 1] = nbFaceNodes;
5815 for (inode = 1; inode <= nbFaceNodes; inode++) {
5816 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
5818 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
5819 if (nnIt != nodeNodeMap.end()) { // curNode sticks
5820 curNode = (*nnIt).second;
5822 poly_nodes.push_back(curNode);
5825 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
5829 // Change regular element or polygon
5830 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
5834 // Remove invalid regular element or invalid polygon
5835 rmElemIds.push_back( elem->GetID() );
5838 } // loop on elements
5840 // Remove equal nodes and bad elements
5842 Remove( rmNodeIds, true );
5843 Remove( rmElemIds, false );
5848 // ========================================================
5849 // class : SortableElement
5850 // purpose : allow sorting elements basing on their nodes
5851 // ========================================================
5852 class SortableElement : public set <const SMDS_MeshElement*>
5856 SortableElement( const SMDS_MeshElement* theElem )
5859 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
5860 while ( nodeIt->more() )
5861 this->insert( nodeIt->next() );
5864 const SMDS_MeshElement* Get() const
5867 void Set(const SMDS_MeshElement* e) const
5872 mutable const SMDS_MeshElement* myElem;
5875 //=======================================================================
5876 //function : FindEqualElements
5877 //purpose : Return list of group of elements built on the same nodes.
5878 // Search among theElements or in the whole mesh if theElements is empty
5879 //=======================================================================
5880 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
5881 TListOfListOfElementsID & theGroupsOfElementsID)
5883 myLastCreatedElems.Clear();
5884 myLastCreatedNodes.Clear();
5886 typedef set<const SMDS_MeshElement*> TElemsSet;
5887 typedef map< SortableElement, int > TMapOfNodeSet;
5888 typedef list<int> TGroupOfElems;
5891 if ( theElements.empty() )
5892 { // get all elements in the mesh
5893 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
5894 while ( eIt->more() )
5895 elems.insert( elems.end(), eIt->next());
5898 elems = theElements;
5900 vector< TGroupOfElems > arrayOfGroups;
5901 TGroupOfElems groupOfElems;
5902 TMapOfNodeSet mapOfNodeSet;
5904 TElemsSet::iterator elemIt = elems.begin();
5905 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
5906 const SMDS_MeshElement* curElem = *elemIt;
5907 SortableElement SE(curElem);
5910 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
5911 if( !(pp.second) ) {
5912 TMapOfNodeSet::iterator& itSE = pp.first;
5913 ind = (*itSE).second;
5914 arrayOfGroups[ind].push_back(curElem->GetID());
5917 groupOfElems.clear();
5918 groupOfElems.push_back(curElem->GetID());
5919 arrayOfGroups.push_back(groupOfElems);
5924 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
5925 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
5926 groupOfElems = *groupIt;
5927 if ( groupOfElems.size() > 1 ) {
5928 groupOfElems.sort();
5929 theGroupsOfElementsID.push_back(groupOfElems);
5934 //=======================================================================
5935 //function : MergeElements
5936 //purpose : In each given group, substitute all elements by the first one.
5937 //=======================================================================
5939 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
5941 myLastCreatedElems.Clear();
5942 myLastCreatedNodes.Clear();
5944 typedef list<int> TListOfIDs;
5945 TListOfIDs rmElemIds; // IDs of elems to remove
5947 SMESHDS_Mesh* aMesh = GetMeshDS();
5949 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
5950 while ( groupsIt != theGroupsOfElementsID.end() ) {
5951 TListOfIDs& aGroupOfElemID = *groupsIt;
5952 aGroupOfElemID.sort();
5953 int elemIDToKeep = aGroupOfElemID.front();
5954 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
5955 aGroupOfElemID.pop_front();
5956 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
5957 while ( idIt != aGroupOfElemID.end() ) {
5958 int elemIDToRemove = *idIt;
5959 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
5960 // add the kept element in groups of removed one (PAL15188)
5961 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
5962 rmElemIds.push_back( elemIDToRemove );
5968 Remove( rmElemIds, false );
5971 //=======================================================================
5972 //function : MergeEqualElements
5973 //purpose : Remove all but one of elements built on the same nodes.
5974 //=======================================================================
5976 void SMESH_MeshEditor::MergeEqualElements()
5978 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
5979 to merge equal elements in the whole mesh */
5980 TListOfListOfElementsID aGroupsOfElementsID;
5981 FindEqualElements(aMeshElements, aGroupsOfElementsID);
5982 MergeElements(aGroupsOfElementsID);
5985 //=======================================================================
5986 //function : FindFaceInSet
5987 //purpose : Return a face having linked nodes n1 and n2 and which is
5988 // - not in avoidSet,
5989 // - in elemSet provided that !elemSet.empty()
5990 //=======================================================================
5992 const SMDS_MeshElement*
5993 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
5994 const SMDS_MeshNode* n2,
5995 const TIDSortedElemSet& elemSet,
5996 const TIDSortedElemSet& avoidSet)
5999 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6000 while ( invElemIt->more() ) { // loop on inverse elements of n1
6001 const SMDS_MeshElement* elem = invElemIt->next();
6002 if (avoidSet.find( elem ) != avoidSet.end() )
6004 if ( !elemSet.empty() && elemSet.find( elem ) == elemSet.end())
6006 // get face nodes and find index of n1
6007 int i1, nbN = elem->NbNodes(), iNode = 0;
6008 //const SMDS_MeshNode* faceNodes[ nbN ], *n;
6009 vector<const SMDS_MeshNode*> faceNodes( nbN );
6010 const SMDS_MeshNode* n;
6011 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6012 while ( nIt->more() ) {
6013 faceNodes[ iNode ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6014 if ( faceNodes[ iNode++ ] == n1 )
6017 // find a n2 linked to n1
6018 if(!elem->IsQuadratic()) {
6019 for ( iNode = 0; iNode < 2; iNode++ ) {
6020 if ( iNode ) // node before n1
6021 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6022 else // node after n1
6023 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6028 else { // analysis for quadratic elements
6029 bool IsFind = false;
6030 // check using only corner nodes
6031 for ( iNode = 0; iNode < 2; iNode++ ) {
6032 if ( iNode ) // node before n1
6033 n = faceNodes[ i1 == 0 ? nbN/2 - 1 : i1 - 1 ];
6034 else // node after n1
6035 n = faceNodes[ i1 + 1 == nbN/2 ? 0 : i1 + 1 ];
6043 // check using all nodes
6044 const SMDS_QuadraticFaceOfNodes* F =
6045 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6046 // use special nodes iterator
6048 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6049 while ( anIter->more() ) {
6050 faceNodes[iNode] = static_cast<const SMDS_MeshNode*>(anIter->next());
6051 if ( faceNodes[ iNode++ ] == n1 )
6054 for ( iNode = 0; iNode < 2; iNode++ ) {
6055 if ( iNode ) // node before n1
6056 n = faceNodes[ i1 == 0 ? nbN - 1 : i1 - 1 ];
6057 else // node after n1
6058 n = faceNodes[ i1 + 1 == nbN ? 0 : i1 + 1 ];
6064 } // end analysis for quadratic elements
6069 //=======================================================================
6070 //function : findAdjacentFace
6072 //=======================================================================
6074 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6075 const SMDS_MeshNode* n2,
6076 const SMDS_MeshElement* elem)
6078 TIDSortedElemSet elemSet, avoidSet;
6080 avoidSet.insert ( elem );
6081 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6084 //=======================================================================
6085 //function : FindFreeBorder
6087 //=======================================================================
6089 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6091 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6092 const SMDS_MeshNode* theSecondNode,
6093 const SMDS_MeshNode* theLastNode,
6094 list< const SMDS_MeshNode* > & theNodes,
6095 list< const SMDS_MeshElement* >& theFaces)
6097 if ( !theFirstNode || !theSecondNode )
6099 // find border face between theFirstNode and theSecondNode
6100 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6104 theFaces.push_back( curElem );
6105 theNodes.push_back( theFirstNode );
6106 theNodes.push_back( theSecondNode );
6108 //vector<const SMDS_MeshNode*> nodes;
6109 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6110 set < const SMDS_MeshElement* > foundElems;
6111 bool needTheLast = ( theLastNode != 0 );
6113 while ( nStart != theLastNode ) {
6114 if ( nStart == theFirstNode )
6115 return !needTheLast;
6117 // find all free border faces sharing form nStart
6119 list< const SMDS_MeshElement* > curElemList;
6120 list< const SMDS_MeshNode* > nStartList;
6121 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6122 while ( invElemIt->more() ) {
6123 const SMDS_MeshElement* e = invElemIt->next();
6124 if ( e == curElem || foundElems.insert( e ).second ) {
6126 int iNode = 0, nbNodes = e->NbNodes();
6127 //const SMDS_MeshNode* nodes[nbNodes+1];
6128 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6130 if(e->IsQuadratic()) {
6131 const SMDS_QuadraticFaceOfNodes* F =
6132 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6133 // use special nodes iterator
6134 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6135 while( anIter->more() ) {
6136 nodes[ iNode++ ] = anIter->next();
6140 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6141 while ( nIt->more() )
6142 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6144 nodes[ iNode ] = nodes[ 0 ];
6146 for ( iNode = 0; iNode < nbNodes; iNode++ )
6147 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6148 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6149 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6151 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6152 curElemList.push_back( e );
6156 // analyse the found
6158 int nbNewBorders = curElemList.size();
6159 if ( nbNewBorders == 0 ) {
6160 // no free border furthermore
6161 return !needTheLast;
6163 else if ( nbNewBorders == 1 ) {
6164 // one more element found
6166 nStart = nStartList.front();
6167 curElem = curElemList.front();
6168 theFaces.push_back( curElem );
6169 theNodes.push_back( nStart );
6172 // several continuations found
6173 list< const SMDS_MeshElement* >::iterator curElemIt;
6174 list< const SMDS_MeshNode* >::iterator nStartIt;
6175 // check if one of them reached the last node
6176 if ( needTheLast ) {
6177 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6178 curElemIt!= curElemList.end();
6179 curElemIt++, nStartIt++ )
6180 if ( *nStartIt == theLastNode ) {
6181 theFaces.push_back( *curElemIt );
6182 theNodes.push_back( *nStartIt );
6186 // find the best free border by the continuations
6187 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6188 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6189 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6190 curElemIt!= curElemList.end();
6191 curElemIt++, nStartIt++ )
6193 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6194 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6195 // find one more free border
6196 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6200 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6201 // choice: clear a worse one
6202 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6203 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6204 contNodes[ iWorse ].clear();
6205 contFaces[ iWorse ].clear();
6208 if ( contNodes[0].empty() && contNodes[1].empty() )
6211 // append the best free border
6212 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6213 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6214 theNodes.pop_back(); // remove nIgnore
6215 theNodes.pop_back(); // remove nStart
6216 theFaces.pop_back(); // remove curElem
6217 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6218 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6219 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6220 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6223 } // several continuations found
6224 } // while ( nStart != theLastNode )
6229 //=======================================================================
6230 //function : CheckFreeBorderNodes
6231 //purpose : Return true if the tree nodes are on a free border
6232 //=======================================================================
6234 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6235 const SMDS_MeshNode* theNode2,
6236 const SMDS_MeshNode* theNode3)
6238 list< const SMDS_MeshNode* > nodes;
6239 list< const SMDS_MeshElement* > faces;
6240 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6243 //=======================================================================
6244 //function : SewFreeBorder
6246 //=======================================================================
6248 SMESH_MeshEditor::Sew_Error
6249 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6250 const SMDS_MeshNode* theBordSecondNode,
6251 const SMDS_MeshNode* theBordLastNode,
6252 const SMDS_MeshNode* theSideFirstNode,
6253 const SMDS_MeshNode* theSideSecondNode,
6254 const SMDS_MeshNode* theSideThirdNode,
6255 const bool theSideIsFreeBorder,
6256 const bool toCreatePolygons,
6257 const bool toCreatePolyedrs)
6259 myLastCreatedElems.Clear();
6260 myLastCreatedNodes.Clear();
6262 MESSAGE("::SewFreeBorder()");
6263 Sew_Error aResult = SEW_OK;
6265 // ====================================
6266 // find side nodes and elements
6267 // ====================================
6269 list< const SMDS_MeshNode* > nSide[ 2 ];
6270 list< const SMDS_MeshElement* > eSide[ 2 ];
6271 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6272 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6276 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6277 nSide[0], eSide[0])) {
6278 MESSAGE(" Free Border 1 not found " );
6279 aResult = SEW_BORDER1_NOT_FOUND;
6281 if (theSideIsFreeBorder) {
6284 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6285 nSide[1], eSide[1])) {
6286 MESSAGE(" Free Border 2 not found " );
6287 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6290 if ( aResult != SEW_OK )
6293 if (!theSideIsFreeBorder) {
6297 // -------------------------------------------------------------------------
6299 // 1. If nodes to merge are not coincident, move nodes of the free border
6300 // from the coord sys defined by the direction from the first to last
6301 // nodes of the border to the correspondent sys of the side 2
6302 // 2. On the side 2, find the links most co-directed with the correspondent
6303 // links of the free border
6304 // -------------------------------------------------------------------------
6306 // 1. Since sewing may brake if there are volumes to split on the side 2,
6307 // we wont move nodes but just compute new coordinates for them
6308 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6309 TNodeXYZMap nBordXYZ;
6310 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6311 list< const SMDS_MeshNode* >::iterator nBordIt;
6313 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6314 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6315 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6316 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6317 double tol2 = 1.e-8;
6318 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6319 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6320 // Need node movement.
6322 // find X and Z axes to create trsf
6323 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6325 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6327 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6330 gp_Ax3 toBordAx( Pb1, Zb, X );
6331 gp_Ax3 fromSideAx( Ps1, Zs, X );
6332 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6334 gp_Trsf toBordSys, fromSide2Sys;
6335 toBordSys.SetTransformation( toBordAx );
6336 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6337 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6340 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6341 const SMDS_MeshNode* n = *nBordIt;
6342 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6343 toBordSys.Transforms( xyz );
6344 fromSide2Sys.Transforms( xyz );
6345 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6349 // just insert nodes XYZ in the nBordXYZ map
6350 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6351 const SMDS_MeshNode* n = *nBordIt;
6352 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6356 // 2. On the side 2, find the links most co-directed with the correspondent
6357 // links of the free border
6359 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6360 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6361 sideNodes.push_back( theSideFirstNode );
6363 bool hasVolumes = false;
6364 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6365 set<long> foundSideLinkIDs, checkedLinkIDs;
6366 SMDS_VolumeTool volume;
6367 //const SMDS_MeshNode* faceNodes[ 4 ];
6369 const SMDS_MeshNode* sideNode;
6370 const SMDS_MeshElement* sideElem;
6371 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6372 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6373 nBordIt = bordNodes.begin();
6375 // border node position and border link direction to compare with
6376 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6377 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6378 // choose next side node by link direction or by closeness to
6379 // the current border node:
6380 bool searchByDir = ( *nBordIt != theBordLastNode );
6382 // find the next node on the Side 2
6384 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6386 checkedLinkIDs.clear();
6387 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6389 // loop on inverse elements of current node (prevSideNode) on the Side 2
6390 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6391 while ( invElemIt->more() )
6393 const SMDS_MeshElement* elem = invElemIt->next();
6394 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6395 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6396 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6397 bool isVolume = volume.Set( elem );
6398 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6399 if ( isVolume ) // --volume
6401 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6402 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6403 if(elem->IsQuadratic()) {
6404 const SMDS_QuadraticFaceOfNodes* F =
6405 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6406 // use special nodes iterator
6407 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6408 while( anIter->more() ) {
6409 nodes[ iNode ] = anIter->next();
6410 if ( nodes[ iNode++ ] == prevSideNode )
6411 iPrevNode = iNode - 1;
6415 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6416 while ( nIt->more() ) {
6417 nodes[ iNode ] = cast2Node( nIt->next() );
6418 if ( nodes[ iNode++ ] == prevSideNode )
6419 iPrevNode = iNode - 1;
6422 // there are 2 links to check
6427 // loop on links, to be precise, on the second node of links
6428 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6429 const SMDS_MeshNode* n = nodes[ iNode ];
6431 if ( !volume.IsLinked( n, prevSideNode ))
6435 if ( iNode ) // a node before prevSideNode
6436 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6437 else // a node after prevSideNode
6438 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6440 // check if this link was already used
6441 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6442 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6443 if (!isJustChecked &&
6444 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6446 // test a link geometrically
6447 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6448 bool linkIsBetter = false;
6449 double dot = 0.0, dist = 0.0;
6450 if ( searchByDir ) { // choose most co-directed link
6451 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6452 linkIsBetter = ( dot > maxDot );
6454 else { // choose link with the node closest to bordPos
6455 dist = ( nextXYZ - bordPos ).SquareModulus();
6456 linkIsBetter = ( dist < minDist );
6458 if ( linkIsBetter ) {
6467 } // loop on inverse elements of prevSideNode
6470 MESSAGE(" Cant find path by links of the Side 2 ");
6471 return SEW_BAD_SIDE_NODES;
6473 sideNodes.push_back( sideNode );
6474 sideElems.push_back( sideElem );
6475 foundSideLinkIDs.insert ( linkID );
6476 prevSideNode = sideNode;
6478 if ( *nBordIt == theBordLastNode )
6479 searchByDir = false;
6481 // find the next border link to compare with
6482 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6483 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6484 // move to next border node if sideNode is before forward border node (bordPos)
6485 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6486 prevBordNode = *nBordIt;
6488 bordPos = nBordXYZ[ *nBordIt ];
6489 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6490 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6494 while ( sideNode != theSideSecondNode );
6496 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6497 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6498 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6500 } // end nodes search on the side 2
6502 // ============================
6503 // sew the border to the side 2
6504 // ============================
6506 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6507 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6509 TListOfListOfNodes nodeGroupsToMerge;
6510 if ( nbNodes[0] == nbNodes[1] ||
6511 ( theSideIsFreeBorder && !theSideThirdNode)) {
6513 // all nodes are to be merged
6515 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6516 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6517 nIt[0]++, nIt[1]++ )
6519 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6520 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6521 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6526 // insert new nodes into the border and the side to get equal nb of segments
6528 // get normalized parameters of nodes on the borders
6529 //double param[ 2 ][ maxNbNodes ];
6531 param[0] = new double [ maxNbNodes ];
6532 param[1] = new double [ maxNbNodes ];
6534 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6535 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
6536 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
6537 const SMDS_MeshNode* nPrev = *nIt;
6538 double bordLength = 0;
6539 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
6540 const SMDS_MeshNode* nCur = *nIt;
6541 gp_XYZ segment (nCur->X() - nPrev->X(),
6542 nCur->Y() - nPrev->Y(),
6543 nCur->Z() - nPrev->Z());
6544 double segmentLen = segment.Modulus();
6545 bordLength += segmentLen;
6546 param[ iBord ][ iNode ] = bordLength;
6549 // normalize within [0,1]
6550 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
6551 param[ iBord ][ iNode ] /= bordLength;
6555 // loop on border segments
6556 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
6557 int i[ 2 ] = { 0, 0 };
6558 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
6559 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
6561 TElemOfNodeListMap insertMap;
6562 TElemOfNodeListMap::iterator insertMapIt;
6564 // key: elem to insert nodes into
6565 // value: 2 nodes to insert between + nodes to be inserted
6567 bool next[ 2 ] = { false, false };
6569 // find min adjacent segment length after sewing
6570 double nextParam = 10., prevParam = 0;
6571 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6572 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
6573 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
6574 if ( i[ iBord ] > 0 )
6575 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
6577 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6578 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
6579 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
6581 // choose to insert or to merge nodes
6582 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
6583 if ( Abs( du ) <= minSegLen * 0.2 ) {
6586 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6587 const SMDS_MeshNode* n0 = *nIt[0];
6588 const SMDS_MeshNode* n1 = *nIt[1];
6589 nodeGroupsToMerge.back().push_back( n1 );
6590 nodeGroupsToMerge.back().push_back( n0 );
6591 // position of node of the border changes due to merge
6592 param[ 0 ][ i[0] ] += du;
6593 // move n1 for the sake of elem shape evaluation during insertion.
6594 // n1 will be removed by MergeNodes() anyway
6595 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
6596 next[0] = next[1] = true;
6601 int intoBord = ( du < 0 ) ? 0 : 1;
6602 const SMDS_MeshElement* elem = *eIt[ intoBord ];
6603 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
6604 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
6605 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
6606 if ( intoBord == 1 ) {
6607 // move node of the border to be on a link of elem of the side
6608 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
6609 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
6610 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
6611 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
6612 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
6614 insertMapIt = insertMap.find( elem );
6615 bool notFound = ( insertMapIt == insertMap.end() );
6616 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
6618 // insert into another link of the same element:
6619 // 1. perform insertion into the other link of the elem
6620 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6621 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
6622 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
6623 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
6624 // 2. perform insertion into the link of adjacent faces
6626 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
6628 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
6632 if (toCreatePolyedrs) {
6633 // perform insertion into the links of adjacent volumes
6634 UpdateVolumes(n12, n22, nodeList);
6636 // 3. find an element appeared on n1 and n2 after the insertion
6637 insertMap.erase( elem );
6638 elem = findAdjacentFace( n1, n2, 0 );
6640 if ( notFound || otherLink ) {
6641 // add element and nodes of the side into the insertMap
6642 insertMapIt = insertMap.insert
6643 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
6644 (*insertMapIt).second.push_back( n1 );
6645 (*insertMapIt).second.push_back( n2 );
6647 // add node to be inserted into elem
6648 (*insertMapIt).second.push_back( nIns );
6649 next[ 1 - intoBord ] = true;
6652 // go to the next segment
6653 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
6654 if ( next[ iBord ] ) {
6655 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
6657 nPrev[ iBord ] = *nIt[ iBord ];
6658 nIt[ iBord ]++; i[ iBord ]++;
6662 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
6664 // perform insertion of nodes into elements
6666 for (insertMapIt = insertMap.begin();
6667 insertMapIt != insertMap.end();
6670 const SMDS_MeshElement* elem = (*insertMapIt).first;
6671 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
6672 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
6673 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
6675 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
6677 if ( !theSideIsFreeBorder ) {
6678 // look for and insert nodes into the faces adjacent to elem
6680 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
6682 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
6687 if (toCreatePolyedrs) {
6688 // perform insertion into the links of adjacent volumes
6689 UpdateVolumes(n1, n2, nodeList);
6695 } // end: insert new nodes
6697 MergeNodes ( nodeGroupsToMerge );
6702 //=======================================================================
6703 //function : InsertNodesIntoLink
6704 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
6705 // and theBetweenNode2 and split theElement
6706 //=======================================================================
6708 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
6709 const SMDS_MeshNode* theBetweenNode1,
6710 const SMDS_MeshNode* theBetweenNode2,
6711 list<const SMDS_MeshNode*>& theNodesToInsert,
6712 const bool toCreatePoly)
6714 if ( theFace->GetType() != SMDSAbs_Face ) return;
6716 // find indices of 2 link nodes and of the rest nodes
6717 int iNode = 0, il1, il2, i3, i4;
6718 il1 = il2 = i3 = i4 = -1;
6719 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
6720 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
6722 if(theFace->IsQuadratic()) {
6723 const SMDS_QuadraticFaceOfNodes* F =
6724 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6725 // use special nodes iterator
6726 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6727 while( anIter->more() ) {
6728 const SMDS_MeshNode* n = anIter->next();
6729 if ( n == theBetweenNode1 )
6731 else if ( n == theBetweenNode2 )
6737 nodes[ iNode++ ] = n;
6741 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6742 while ( nodeIt->more() ) {
6743 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6744 if ( n == theBetweenNode1 )
6746 else if ( n == theBetweenNode2 )
6752 nodes[ iNode++ ] = n;
6755 if ( il1 < 0 || il2 < 0 || i3 < 0 )
6758 // arrange link nodes to go one after another regarding the face orientation
6759 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
6760 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
6765 aNodesToInsert.reverse();
6767 // check that not link nodes of a quadrangles are in good order
6768 int nbFaceNodes = theFace->NbNodes();
6769 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
6775 if (toCreatePoly || theFace->IsPoly()) {
6778 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
6780 // add nodes of face up to first node of link
6783 if(theFace->IsQuadratic()) {
6784 const SMDS_QuadraticFaceOfNodes* F =
6785 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
6786 // use special nodes iterator
6787 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6788 while( anIter->more() && !isFLN ) {
6789 const SMDS_MeshNode* n = anIter->next();
6790 poly_nodes[iNode++] = n;
6791 if (n == nodes[il1]) {
6795 // add nodes to insert
6796 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6797 for (; nIt != aNodesToInsert.end(); nIt++) {
6798 poly_nodes[iNode++] = *nIt;
6800 // add nodes of face starting from last node of link
6801 while ( anIter->more() ) {
6802 poly_nodes[iNode++] = anIter->next();
6806 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
6807 while ( nodeIt->more() && !isFLN ) {
6808 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6809 poly_nodes[iNode++] = n;
6810 if (n == nodes[il1]) {
6814 // add nodes to insert
6815 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6816 for (; nIt != aNodesToInsert.end(); nIt++) {
6817 poly_nodes[iNode++] = *nIt;
6819 // add nodes of face starting from last node of link
6820 while ( nodeIt->more() ) {
6821 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
6822 poly_nodes[iNode++] = n;
6826 // edit or replace the face
6827 SMESHDS_Mesh *aMesh = GetMeshDS();
6829 if (theFace->IsPoly()) {
6830 aMesh->ChangePolygonNodes(theFace, poly_nodes);
6833 int aShapeId = FindShape( theFace );
6835 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6836 myLastCreatedElems.Append(newElem);
6837 if ( aShapeId && newElem )
6838 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6840 aMesh->RemoveElement(theFace);
6845 if( !theFace->IsQuadratic() ) {
6847 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
6848 int nbLinkNodes = 2 + aNodesToInsert.size();
6849 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
6850 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
6851 linkNodes[ 0 ] = nodes[ il1 ];
6852 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
6853 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
6854 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
6855 linkNodes[ iNode++ ] = *nIt;
6857 // decide how to split a quadrangle: compare possible variants
6858 // and choose which of splits to be a quadrangle
6859 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
6860 if ( nbFaceNodes == 3 ) {
6861 iBestQuad = nbSplits;
6864 else if ( nbFaceNodes == 4 ) {
6865 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
6866 double aBestRate = DBL_MAX;
6867 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
6869 double aBadRate = 0;
6870 // evaluate elements quality
6871 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
6872 if ( iSplit == iQuad ) {
6873 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
6877 aBadRate += getBadRate( &quad, aCrit );
6880 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
6882 nodes[ iSplit < iQuad ? i4 : i3 ]);
6883 aBadRate += getBadRate( &tria, aCrit );
6887 if ( aBadRate < aBestRate ) {
6889 aBestRate = aBadRate;
6894 // create new elements
6895 SMESHDS_Mesh *aMesh = GetMeshDS();
6896 int aShapeId = FindShape( theFace );
6899 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
6900 SMDS_MeshElement* newElem = 0;
6901 if ( iSplit == iBestQuad )
6902 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6907 newElem = aMesh->AddFace (linkNodes[ i1++ ],
6909 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
6910 myLastCreatedElems.Append(newElem);
6911 if ( aShapeId && newElem )
6912 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6915 // change nodes of theFace
6916 const SMDS_MeshNode* newNodes[ 4 ];
6917 newNodes[ 0 ] = linkNodes[ i1 ];
6918 newNodes[ 1 ] = linkNodes[ i2 ];
6919 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
6920 newNodes[ 3 ] = nodes[ i4 ];
6921 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
6922 } // end if(!theFace->IsQuadratic())
6923 else { // theFace is quadratic
6924 // we have to split theFace on simple triangles and one simple quadrangle
6926 int nbshift = tmp*2;
6927 // shift nodes in nodes[] by nbshift
6929 for(i=0; i<nbshift; i++) {
6930 const SMDS_MeshNode* n = nodes[0];
6931 for(j=0; j<nbFaceNodes-1; j++) {
6932 nodes[j] = nodes[j+1];
6934 nodes[nbFaceNodes-1] = n;
6936 il1 = il1 - nbshift;
6937 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
6938 // n0 n1 n2 n0 n1 n2
6939 // +-----+-----+ +-----+-----+
6948 // create new elements
6949 SMESHDS_Mesh *aMesh = GetMeshDS();
6950 int aShapeId = FindShape( theFace );
6953 if(nbFaceNodes==6) { // quadratic triangle
6954 SMDS_MeshElement* newElem =
6955 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6956 myLastCreatedElems.Append(newElem);
6957 if ( aShapeId && newElem )
6958 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6959 if(theFace->IsMediumNode(nodes[il1])) {
6960 // create quadrangle
6961 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
6962 myLastCreatedElems.Append(newElem);
6963 if ( aShapeId && newElem )
6964 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6970 // create quadrangle
6971 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
6972 myLastCreatedElems.Append(newElem);
6973 if ( aShapeId && newElem )
6974 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6980 else { // nbFaceNodes==8 - quadratic quadrangle
6981 SMDS_MeshElement* newElem =
6982 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
6983 myLastCreatedElems.Append(newElem);
6984 if ( aShapeId && newElem )
6985 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6986 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
6987 myLastCreatedElems.Append(newElem);
6988 if ( aShapeId && newElem )
6989 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6990 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
6991 myLastCreatedElems.Append(newElem);
6992 if ( aShapeId && newElem )
6993 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6994 if(theFace->IsMediumNode(nodes[il1])) {
6995 // create quadrangle
6996 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
6997 myLastCreatedElems.Append(newElem);
6998 if ( aShapeId && newElem )
6999 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7005 // create quadrangle
7006 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7007 myLastCreatedElems.Append(newElem);
7008 if ( aShapeId && newElem )
7009 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7015 // create needed triangles using n1,n2,n3 and inserted nodes
7016 int nbn = 2 + aNodesToInsert.size();
7017 //const SMDS_MeshNode* aNodes[nbn];
7018 vector<const SMDS_MeshNode*> aNodes(nbn);
7019 aNodes[0] = nodes[n1];
7020 aNodes[nbn-1] = nodes[n2];
7021 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7022 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7023 aNodes[iNode++] = *nIt;
7025 for(i=1; i<nbn; i++) {
7026 SMDS_MeshElement* newElem =
7027 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7028 myLastCreatedElems.Append(newElem);
7029 if ( aShapeId && newElem )
7030 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7032 // remove old quadratic face
7033 aMesh->RemoveElement(theFace);
7037 //=======================================================================
7038 //function : UpdateVolumes
7040 //=======================================================================
7041 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7042 const SMDS_MeshNode* theBetweenNode2,
7043 list<const SMDS_MeshNode*>& theNodesToInsert)
7045 myLastCreatedElems.Clear();
7046 myLastCreatedNodes.Clear();
7048 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7049 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7050 const SMDS_MeshElement* elem = invElemIt->next();
7052 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7053 SMDS_VolumeTool aVolume (elem);
7054 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7057 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7058 int iface, nbFaces = aVolume.NbFaces();
7059 vector<const SMDS_MeshNode *> poly_nodes;
7060 vector<int> quantities (nbFaces);
7062 for (iface = 0; iface < nbFaces; iface++) {
7063 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7064 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7065 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7067 for (int inode = 0; inode < nbFaceNodes; inode++) {
7068 poly_nodes.push_back(faceNodes[inode]);
7070 if (nbInserted == 0) {
7071 if (faceNodes[inode] == theBetweenNode1) {
7072 if (faceNodes[inode + 1] == theBetweenNode2) {
7073 nbInserted = theNodesToInsert.size();
7075 // add nodes to insert
7076 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7077 for (; nIt != theNodesToInsert.end(); nIt++) {
7078 poly_nodes.push_back(*nIt);
7082 else if (faceNodes[inode] == theBetweenNode2) {
7083 if (faceNodes[inode + 1] == theBetweenNode1) {
7084 nbInserted = theNodesToInsert.size();
7086 // add nodes to insert in reversed order
7087 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7089 for (; nIt != theNodesToInsert.begin(); nIt--) {
7090 poly_nodes.push_back(*nIt);
7092 poly_nodes.push_back(*nIt);
7099 quantities[iface] = nbFaceNodes + nbInserted;
7102 // Replace or update the volume
7103 SMESHDS_Mesh *aMesh = GetMeshDS();
7105 if (elem->IsPoly()) {
7106 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7110 int aShapeId = FindShape( elem );
7112 SMDS_MeshElement* newElem =
7113 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7114 myLastCreatedElems.Append(newElem);
7115 if (aShapeId && newElem)
7116 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7118 aMesh->RemoveElement(elem);
7123 //=======================================================================
7125 * \brief Convert elements contained in a submesh to quadratic
7126 * \retval int - nb of checked elements
7128 //=======================================================================
7130 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7131 SMESH_MesherHelper& theHelper,
7132 const bool theForce3d)
7135 if( !theSm ) return nbElem;
7137 const bool notFromGroups = false;
7138 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7139 while(ElemItr->more())
7142 const SMDS_MeshElement* elem = ElemItr->next();
7143 if( !elem || elem->IsQuadratic() ) continue;
7145 int id = elem->GetID();
7146 int nbNodes = elem->NbNodes();
7147 vector<const SMDS_MeshNode *> aNds (nbNodes);
7149 for(int i = 0; i < nbNodes; i++)
7151 aNds[i] = elem->GetNode(i);
7153 SMDSAbs_ElementType aType = elem->GetType();
7155 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7157 const SMDS_MeshElement* NewElem = 0;
7163 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7171 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7174 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7181 case SMDSAbs_Volume :
7186 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7189 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7192 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7193 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7203 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7205 theSm->AddElement( NewElem );
7210 //=======================================================================
7211 //function : ConvertToQuadratic
7213 //=======================================================================
7214 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7216 SMESHDS_Mesh* meshDS = GetMeshDS();
7218 SMESH_MesherHelper aHelper(*myMesh);
7219 aHelper.SetIsQuadratic( true );
7220 const bool notFromGroups = false;
7222 int nbCheckedElems = 0;
7223 if ( myMesh->HasShapeToMesh() )
7225 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7227 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7228 while ( smIt->more() ) {
7229 SMESH_subMesh* sm = smIt->next();
7230 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7231 aHelper.SetSubShape( sm->GetSubShape() );
7232 if ( !theForce3d) aHelper.SetCheckNodePosition(true);
7233 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7238 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7239 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7241 SMESHDS_SubMesh *smDS = 0;
7242 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7243 while(aEdgeItr->more())
7245 const SMDS_MeshEdge* edge = aEdgeItr->next();
7246 if(edge && !edge->IsQuadratic())
7248 int id = edge->GetID();
7249 const SMDS_MeshNode* n1 = edge->GetNode(0);
7250 const SMDS_MeshNode* n2 = edge->GetNode(1);
7252 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7254 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7255 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7258 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7259 while(aFaceItr->more())
7261 const SMDS_MeshFace* face = aFaceItr->next();
7262 if(!face || face->IsQuadratic() ) continue;
7264 int id = face->GetID();
7265 int nbNodes = face->NbNodes();
7266 vector<const SMDS_MeshNode *> aNds (nbNodes);
7268 for(int i = 0; i < nbNodes; i++)
7270 aNds[i] = face->GetNode(i);
7273 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7275 SMDS_MeshFace * NewFace = 0;
7279 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7282 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7287 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7289 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7290 while(aVolumeItr->more())
7292 const SMDS_MeshVolume* volume = aVolumeItr->next();
7293 if(!volume || volume->IsQuadratic() ) continue;
7295 int id = volume->GetID();
7296 int nbNodes = volume->NbNodes();
7297 vector<const SMDS_MeshNode *> aNds (nbNodes);
7299 for(int i = 0; i < nbNodes; i++)
7301 aNds[i] = volume->GetNode(i);
7304 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7306 SMDS_MeshVolume * NewVolume = 0;
7310 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7311 aNds[3], id, theForce3d );
7314 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7315 aNds[3], aNds[4], aNds[5], id, theForce3d);
7318 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7319 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7324 ReplaceElemInGroups(volume, NewVolume, meshDS);
7327 if ( !theForce3d ) {
7328 aHelper.SetSubShape(0); // apply to the whole mesh
7329 aHelper.FixQuadraticElements();
7333 //=======================================================================
7335 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7336 * \retval int - nb of checked elements
7338 //=======================================================================
7340 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7341 SMDS_ElemIteratorPtr theItr,
7342 const int theShapeID)
7345 SMESHDS_Mesh* meshDS = GetMeshDS();
7346 const bool notFromGroups = false;
7348 while( theItr->more() )
7350 const SMDS_MeshElement* elem = theItr->next();
7352 if( elem && elem->IsQuadratic())
7354 int id = elem->GetID();
7355 int nbNodes = elem->NbNodes();
7356 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7357 aNds.reserve( nbNodes );
7358 mediumNodes.reserve( nbNodes );
7360 for(int i = 0; i < nbNodes; i++)
7362 const SMDS_MeshNode* n = elem->GetNode(i);
7364 if( elem->IsMediumNode( n ) )
7365 mediumNodes.push_back( n );
7367 aNds.push_back( n );
7369 if( aNds.empty() ) continue;
7370 SMDSAbs_ElementType aType = elem->GetType();
7372 //remove old quadratic element
7373 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7375 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7376 ReplaceElemInGroups(elem, NewElem, meshDS);
7377 if( theSm && NewElem )
7378 theSm->AddElement( NewElem );
7380 // remove medium nodes
7381 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7382 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7383 const SMDS_MeshNode* n = *nIt;
7384 if ( n->NbInverseElements() == 0 ) {
7385 if ( n->GetPosition()->GetShapeId() != theShapeID )
7386 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7387 ( n->GetPosition()->GetShapeId() ));
7389 meshDS->RemoveFreeNode( n, theSm );
7397 //=======================================================================
7398 //function : ConvertFromQuadratic
7400 //=======================================================================
7401 bool SMESH_MeshEditor::ConvertFromQuadratic()
7403 int nbCheckedElems = 0;
7404 if ( myMesh->HasShapeToMesh() )
7406 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7408 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7409 while ( smIt->more() ) {
7410 SMESH_subMesh* sm = smIt->next();
7411 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7412 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7418 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7419 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7421 SMESHDS_SubMesh *aSM = 0;
7422 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7428 //=======================================================================
7429 //function : SewSideElements
7431 //=======================================================================
7433 SMESH_MeshEditor::Sew_Error
7434 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7435 TIDSortedElemSet& theSide2,
7436 const SMDS_MeshNode* theFirstNode1,
7437 const SMDS_MeshNode* theFirstNode2,
7438 const SMDS_MeshNode* theSecondNode1,
7439 const SMDS_MeshNode* theSecondNode2)
7441 myLastCreatedElems.Clear();
7442 myLastCreatedNodes.Clear();
7444 MESSAGE ("::::SewSideElements()");
7445 if ( theSide1.size() != theSide2.size() )
7446 return SEW_DIFF_NB_OF_ELEMENTS;
7448 Sew_Error aResult = SEW_OK;
7450 // 1. Build set of faces representing each side
7451 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7452 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7454 // =======================================================================
7455 // 1. Build set of faces representing each side:
7456 // =======================================================================
7457 // a. build set of nodes belonging to faces
7458 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7459 // c. create temporary faces representing side of volumes if correspondent
7460 // face does not exist
7462 SMESHDS_Mesh* aMesh = GetMeshDS();
7463 SMDS_Mesh aTmpFacesMesh;
7464 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7465 set<const SMDS_MeshElement*> volSet1, volSet2;
7466 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7467 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7468 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7469 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7470 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7471 int iSide, iFace, iNode;
7473 for ( iSide = 0; iSide < 2; iSide++ ) {
7474 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7475 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7476 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7477 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7478 set<const SMDS_MeshElement*>::iterator vIt;
7479 TIDSortedElemSet::iterator eIt;
7480 set<const SMDS_MeshNode*>::iterator nIt;
7482 // check that given nodes belong to given elements
7483 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7484 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7485 int firstIndex = -1, secondIndex = -1;
7486 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7487 const SMDS_MeshElement* elem = *eIt;
7488 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7489 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7490 if ( firstIndex > -1 && secondIndex > -1 ) break;
7492 if ( firstIndex < 0 || secondIndex < 0 ) {
7493 // we can simply return until temporary faces created
7494 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7497 // -----------------------------------------------------------
7498 // 1a. Collect nodes of existing faces
7499 // and build set of face nodes in order to detect missing
7500 // faces corresponing to sides of volumes
7501 // -----------------------------------------------------------
7503 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7505 // loop on the given element of a side
7506 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7507 //const SMDS_MeshElement* elem = *eIt;
7508 const SMDS_MeshElement* elem = *eIt;
7509 if ( elem->GetType() == SMDSAbs_Face ) {
7510 faceSet->insert( elem );
7511 set <const SMDS_MeshNode*> faceNodeSet;
7512 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7513 while ( nodeIt->more() ) {
7514 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7515 nodeSet->insert( n );
7516 faceNodeSet.insert( n );
7518 setOfFaceNodeSet.insert( faceNodeSet );
7520 else if ( elem->GetType() == SMDSAbs_Volume )
7521 volSet->insert( elem );
7523 // ------------------------------------------------------------------------------
7524 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
7525 // ------------------------------------------------------------------------------
7527 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7528 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7529 while ( fIt->more() ) { // loop on faces sharing a node
7530 const SMDS_MeshElement* f = fIt->next();
7531 if ( faceSet->find( f ) == faceSet->end() ) {
7532 // check if all nodes are in nodeSet and
7533 // complete setOfFaceNodeSet if they are
7534 set <const SMDS_MeshNode*> faceNodeSet;
7535 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7536 bool allInSet = true;
7537 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7538 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7539 if ( nodeSet->find( n ) == nodeSet->end() )
7542 faceNodeSet.insert( n );
7545 faceSet->insert( f );
7546 setOfFaceNodeSet.insert( faceNodeSet );
7552 // -------------------------------------------------------------------------
7553 // 1c. Create temporary faces representing sides of volumes if correspondent
7554 // face does not exist
7555 // -------------------------------------------------------------------------
7557 if ( !volSet->empty() ) {
7558 //int nodeSetSize = nodeSet->size();
7560 // loop on given volumes
7561 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
7562 SMDS_VolumeTool vol (*vIt);
7563 // loop on volume faces: find free faces
7564 // --------------------------------------
7565 list<const SMDS_MeshElement* > freeFaceList;
7566 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
7567 if ( !vol.IsFreeFace( iFace ))
7569 // check if there is already a face with same nodes in a face set
7570 const SMDS_MeshElement* aFreeFace = 0;
7571 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
7572 int nbNodes = vol.NbFaceNodes( iFace );
7573 set <const SMDS_MeshNode*> faceNodeSet;
7574 vol.GetFaceNodes( iFace, faceNodeSet );
7575 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
7577 // no such a face is given but it still can exist, check it
7578 if ( nbNodes == 3 ) {
7579 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
7581 else if ( nbNodes == 4 ) {
7582 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7585 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7586 aFreeFace = aMesh->FindFace(poly_nodes);
7590 // create a temporary face
7591 if ( nbNodes == 3 ) {
7592 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
7594 else if ( nbNodes == 4 ) {
7595 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
7598 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
7599 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
7603 freeFaceList.push_back( aFreeFace );
7605 } // loop on faces of a volume
7607 // choose one of several free faces
7608 // --------------------------------------
7609 if ( freeFaceList.size() > 1 ) {
7610 // choose a face having max nb of nodes shared by other elems of a side
7611 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
7612 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
7613 while ( fIt != freeFaceList.end() ) { // loop on free faces
7614 int nbSharedNodes = 0;
7615 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7616 while ( nodeIt->more() ) { // loop on free face nodes
7617 const SMDS_MeshNode* n =
7618 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7619 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
7620 while ( invElemIt->more() ) {
7621 const SMDS_MeshElement* e = invElemIt->next();
7622 if ( faceSet->find( e ) != faceSet->end() )
7624 if ( elemSet->find( e ) != elemSet->end() )
7628 if ( nbSharedNodes >= maxNbNodes ) {
7629 maxNbNodes = nbSharedNodes;
7633 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
7635 if ( freeFaceList.size() > 1 )
7637 // could not choose one face, use another way
7638 // choose a face most close to the bary center of the opposite side
7639 gp_XYZ aBC( 0., 0., 0. );
7640 set <const SMDS_MeshNode*> addedNodes;
7641 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
7642 eIt = elemSet2->begin();
7643 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
7644 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
7645 while ( nodeIt->more() ) { // loop on free face nodes
7646 const SMDS_MeshNode* n =
7647 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7648 if ( addedNodes.insert( n ).second )
7649 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
7652 aBC /= addedNodes.size();
7653 double minDist = DBL_MAX;
7654 fIt = freeFaceList.begin();
7655 while ( fIt != freeFaceList.end() ) { // loop on free faces
7657 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
7658 while ( nodeIt->more() ) { // loop on free face nodes
7659 const SMDS_MeshNode* n =
7660 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7661 gp_XYZ p( n->X(),n->Y(),n->Z() );
7662 dist += ( aBC - p ).SquareModulus();
7664 if ( dist < minDist ) {
7666 freeFaceList.erase( freeFaceList.begin(), fIt++ );
7669 fIt = freeFaceList.erase( fIt++ );
7672 } // choose one of several free faces of a volume
7674 if ( freeFaceList.size() == 1 ) {
7675 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
7676 faceSet->insert( aFreeFace );
7677 // complete a node set with nodes of a found free face
7678 // for ( iNode = 0; iNode < ; iNode++ )
7679 // nodeSet->insert( fNodes[ iNode ] );
7682 } // loop on volumes of a side
7684 // // complete a set of faces if new nodes in a nodeSet appeared
7685 // // ----------------------------------------------------------
7686 // if ( nodeSetSize != nodeSet->size() ) {
7687 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
7688 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
7689 // while ( fIt->more() ) { // loop on faces sharing a node
7690 // const SMDS_MeshElement* f = fIt->next();
7691 // if ( faceSet->find( f ) == faceSet->end() ) {
7692 // // check if all nodes are in nodeSet and
7693 // // complete setOfFaceNodeSet if they are
7694 // set <const SMDS_MeshNode*> faceNodeSet;
7695 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
7696 // bool allInSet = true;
7697 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
7698 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7699 // if ( nodeSet->find( n ) == nodeSet->end() )
7700 // allInSet = false;
7702 // faceNodeSet.insert( n );
7704 // if ( allInSet ) {
7705 // faceSet->insert( f );
7706 // setOfFaceNodeSet.insert( faceNodeSet );
7712 } // Create temporary faces, if there are volumes given
7715 if ( faceSet1.size() != faceSet2.size() ) {
7716 // delete temporary faces: they are in reverseElements of actual nodes
7717 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7718 while ( tmpFaceIt->more() )
7719 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7720 MESSAGE("Diff nb of faces");
7721 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7724 // ============================================================
7725 // 2. Find nodes to merge:
7726 // bind a node to remove to a node to put instead
7727 // ============================================================
7729 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
7730 if ( theFirstNode1 != theFirstNode2 )
7731 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
7732 if ( theSecondNode1 != theSecondNode2 )
7733 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
7735 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7736 set< long > linkIdSet; // links to process
7737 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
7739 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
7740 list< NLink > linkList[2];
7741 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
7742 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
7743 // loop on links in linkList; find faces by links and append links
7744 // of the found faces to linkList
7745 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
7746 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
7747 NLink link[] = { *linkIt[0], *linkIt[1] };
7748 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
7749 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
7752 // by links, find faces in the face sets,
7753 // and find indices of link nodes in the found faces;
7754 // in a face set, there is only one or no face sharing a link
7755 // ---------------------------------------------------------------
7757 const SMDS_MeshElement* face[] = { 0, 0 };
7758 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
7759 vector<const SMDS_MeshNode*> fnodes1(9);
7760 vector<const SMDS_MeshNode*> fnodes2(9);
7761 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
7762 vector<const SMDS_MeshNode*> notLinkNodes1(6);
7763 vector<const SMDS_MeshNode*> notLinkNodes2(6);
7764 int iLinkNode[2][2];
7765 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7766 const SMDS_MeshNode* n1 = link[iSide].first;
7767 const SMDS_MeshNode* n2 = link[iSide].second;
7768 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7769 set< const SMDS_MeshElement* > fMap;
7770 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
7771 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
7772 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
7773 while ( fIt->more() ) { // loop on faces sharing a node
7774 const SMDS_MeshElement* f = fIt->next();
7775 if (faceSet->find( f ) != faceSet->end() && // f is in face set
7776 ! fMap.insert( f ).second ) // f encounters twice
7778 if ( face[ iSide ] ) {
7779 MESSAGE( "2 faces per link " );
7780 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
7784 faceSet->erase( f );
7785 // get face nodes and find ones of a link
7790 fnodes1.resize(f->NbNodes()+1);
7791 notLinkNodes1.resize(f->NbNodes()-2);
7794 fnodes2.resize(f->NbNodes()+1);
7795 notLinkNodes2.resize(f->NbNodes()-2);
7798 if(!f->IsQuadratic()) {
7799 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
7800 while ( nIt->more() ) {
7801 const SMDS_MeshNode* n =
7802 static_cast<const SMDS_MeshNode*>( nIt->next() );
7804 iLinkNode[ iSide ][ 0 ] = iNode;
7806 else if ( n == n2 ) {
7807 iLinkNode[ iSide ][ 1 ] = iNode;
7809 //else if ( notLinkNodes[ iSide ][ 0 ] )
7810 // notLinkNodes[ iSide ][ 1 ] = n;
7812 // notLinkNodes[ iSide ][ 0 ] = n;
7816 notLinkNodes1[nbl] = n;
7817 //notLinkNodes1.push_back(n);
7819 notLinkNodes2[nbl] = n;
7820 //notLinkNodes2.push_back(n);
7822 //faceNodes[ iSide ][ iNode++ ] = n;
7824 fnodes1[iNode++] = n;
7827 fnodes2[iNode++] = n;
7831 else { // f->IsQuadratic()
7832 const SMDS_QuadraticFaceOfNodes* F =
7833 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
7834 // use special nodes iterator
7835 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7836 while ( anIter->more() ) {
7837 const SMDS_MeshNode* n =
7838 static_cast<const SMDS_MeshNode*>( anIter->next() );
7840 iLinkNode[ iSide ][ 0 ] = iNode;
7842 else if ( n == n2 ) {
7843 iLinkNode[ iSide ][ 1 ] = iNode;
7848 notLinkNodes1[nbl] = n;
7851 notLinkNodes2[nbl] = n;
7855 fnodes1[iNode++] = n;
7858 fnodes2[iNode++] = n;
7862 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
7864 fnodes1[iNode] = fnodes1[0];
7867 fnodes2[iNode] = fnodes1[0];
7874 // check similarity of elements of the sides
7875 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
7876 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
7877 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
7878 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
7881 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7883 break; // do not return because it s necessary to remove tmp faces
7886 // set nodes to merge
7887 // -------------------
7889 if ( face[0] && face[1] ) {
7890 int nbNodes = face[0]->NbNodes();
7891 if ( nbNodes != face[1]->NbNodes() ) {
7892 MESSAGE("Diff nb of face nodes");
7893 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7894 break; // do not return because it s necessary to remove tmp faces
7896 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
7897 if ( nbNodes == 3 ) {
7898 //nReplaceMap.insert( TNodeNodeMap::value_type
7899 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7900 nReplaceMap.insert( TNodeNodeMap::value_type
7901 ( notLinkNodes1[0], notLinkNodes2[0] ));
7904 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
7905 // analyse link orientation in faces
7906 int i1 = iLinkNode[ iSide ][ 0 ];
7907 int i2 = iLinkNode[ iSide ][ 1 ];
7908 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
7909 // if notLinkNodes are the first and the last ones, then
7910 // their order does not correspond to the link orientation
7911 if (( i1 == 1 && i2 == 2 ) ||
7912 ( i1 == 2 && i2 == 1 ))
7913 reverse[ iSide ] = !reverse[ iSide ];
7915 if ( reverse[0] == reverse[1] ) {
7916 //nReplaceMap.insert( TNodeNodeMap::value_type
7917 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
7918 //nReplaceMap.insert( TNodeNodeMap::value_type
7919 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
7920 for(int nn=0; nn<nbNodes-2; nn++) {
7921 nReplaceMap.insert( TNodeNodeMap::value_type
7922 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
7926 //nReplaceMap.insert( TNodeNodeMap::value_type
7927 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
7928 //nReplaceMap.insert( TNodeNodeMap::value_type
7929 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
7930 for(int nn=0; nn<nbNodes-2; nn++) {
7931 nReplaceMap.insert( TNodeNodeMap::value_type
7932 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
7937 // add other links of the faces to linkList
7938 // -----------------------------------------
7940 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
7941 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7942 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
7943 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
7944 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
7945 if ( !iter_isnew.second ) { // already in a set: no need to process
7946 linkIdSet.erase( iter_isnew.first );
7948 else // new in set == encountered for the first time: add
7950 //const SMDS_MeshNode* n1 = nodes[ iNode ];
7951 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
7952 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
7953 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
7954 linkList[0].push_back ( NLink( n1, n2 ));
7955 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
7959 } // loop on link lists
7961 if ( aResult == SEW_OK &&
7962 ( linkIt[0] != linkList[0].end() ||
7963 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
7964 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
7965 " " << (faceSetPtr[1]->empty()));
7966 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
7969 // ====================================================================
7970 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7971 // ====================================================================
7973 // delete temporary faces: they are in reverseElements of actual nodes
7974 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
7975 while ( tmpFaceIt->more() )
7976 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
7978 if ( aResult != SEW_OK)
7981 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
7982 // loop on nodes replacement map
7983 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
7984 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
7985 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
7986 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
7987 nodeIDsToRemove.push_back( nToRemove->GetID() );
7988 // loop on elements sharing nToRemove
7989 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7990 while ( invElemIt->more() ) {
7991 const SMDS_MeshElement* e = invElemIt->next();
7992 // get a new suite of nodes: make replacement
7993 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
7994 vector< const SMDS_MeshNode*> nodes( nbNodes );
7995 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7996 while ( nIt->more() ) {
7997 const SMDS_MeshNode* n =
7998 static_cast<const SMDS_MeshNode*>( nIt->next() );
7999 nnIt = nReplaceMap.find( n );
8000 if ( nnIt != nReplaceMap.end() ) {
8006 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8007 // elemIDsToRemove.push_back( e->GetID() );
8010 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8014 Remove( nodeIDsToRemove, true );
8019 //================================================================================
8021 * \brief Find corresponding nodes in two sets of faces
8022 * \param theSide1 - first face set
8023 * \param theSide2 - second first face
8024 * \param theFirstNode1 - a boundary node of set 1
8025 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8026 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8027 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8028 * \param nReplaceMap - output map of corresponding nodes
8029 * \retval bool - is a success or not
8031 //================================================================================
8034 //#define DEBUG_MATCHING_NODES
8037 SMESH_MeshEditor::Sew_Error
8038 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8039 set<const SMDS_MeshElement*>& theSide2,
8040 const SMDS_MeshNode* theFirstNode1,
8041 const SMDS_MeshNode* theFirstNode2,
8042 const SMDS_MeshNode* theSecondNode1,
8043 const SMDS_MeshNode* theSecondNode2,
8044 TNodeNodeMap & nReplaceMap)
8046 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8048 nReplaceMap.clear();
8049 if ( theFirstNode1 != theFirstNode2 )
8050 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8051 if ( theSecondNode1 != theSecondNode2 )
8052 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8054 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8055 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8057 list< NLink > linkList[2];
8058 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8059 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8061 // loop on links in linkList; find faces by links and append links
8062 // of the found faces to linkList
8063 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8064 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8065 NLink link[] = { *linkIt[0], *linkIt[1] };
8066 if ( linkSet.find( link[0] ) == linkSet.end() )
8069 // by links, find faces in the face sets,
8070 // and find indices of link nodes in the found faces;
8071 // in a face set, there is only one or no face sharing a link
8072 // ---------------------------------------------------------------
8074 const SMDS_MeshElement* face[] = { 0, 0 };
8075 list<const SMDS_MeshNode*> notLinkNodes[2];
8076 //bool reverse[] = { false, false }; // order of notLinkNodes
8078 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8080 const SMDS_MeshNode* n1 = link[iSide].first;
8081 const SMDS_MeshNode* n2 = link[iSide].second;
8082 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8083 set< const SMDS_MeshElement* > facesOfNode1;
8084 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8086 // during a loop of the first node, we find all faces around n1,
8087 // during a loop of the second node, we find one face sharing both n1 and n2
8088 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8089 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8090 while ( fIt->more() ) { // loop on faces sharing a node
8091 const SMDS_MeshElement* f = fIt->next();
8092 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8093 ! facesOfNode1.insert( f ).second ) // f encounters twice
8095 if ( face[ iSide ] ) {
8096 MESSAGE( "2 faces per link " );
8097 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8100 faceSet->erase( f );
8102 // get not link nodes
8103 int nbN = f->NbNodes();
8104 if ( f->IsQuadratic() )
8106 nbNodes[ iSide ] = nbN;
8107 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8108 int i1 = f->GetNodeIndex( n1 );
8109 int i2 = f->GetNodeIndex( n2 );
8110 int iEnd = nbN, iBeg = -1, iDelta = 1;
8111 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8113 std::swap( iEnd, iBeg ); iDelta = -1;
8118 if ( i == iEnd ) i = iBeg + iDelta;
8119 if ( i == i1 ) break;
8120 nodes.push_back ( f->GetNode( i ) );
8126 // check similarity of elements of the sides
8127 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8128 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8129 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8130 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8133 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8137 // set nodes to merge
8138 // -------------------
8140 if ( face[0] && face[1] ) {
8141 if ( nbNodes[0] != nbNodes[1] ) {
8142 MESSAGE("Diff nb of face nodes");
8143 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8145 #ifdef DEBUG_MATCHING_NODES
8146 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8147 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8148 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8150 int nbN = nbNodes[0];
8152 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8153 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8154 for ( int i = 0 ; i < nbN - 2; ++i ) {
8155 #ifdef DEBUG_MATCHING_NODES
8156 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8158 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8162 // add other links of the face 1 to linkList
8163 // -----------------------------------------
8165 const SMDS_MeshElement* f0 = face[0];
8166 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8167 for ( int i = 0; i < nbN; i++ )
8169 const SMDS_MeshNode* n2 = f0->GetNode( i );
8170 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8171 linkSet.insert( SMESH_TLink( n1, n2 ));
8172 if ( !iter_isnew.second ) { // already in a set: no need to process
8173 linkSet.erase( iter_isnew.first );
8175 else // new in set == encountered for the first time: add
8177 #ifdef DEBUG_MATCHING_NODES
8178 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8179 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8181 linkList[0].push_back ( NLink( n1, n2 ));
8182 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8187 } // loop on link lists
8193 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8194 \param theElems - the list of elements (edges or faces) to be replicated
8195 The nodes for duplication could be found from these elements
8196 \param theNodesNot - list of nodes to NOT replicate
8197 \param theAffectedElems - the list of elements (cells and edges) to which the
8198 replicated nodes should be associated to.
8199 \return TRUE if operation has been completed successfully, FALSE otherwise
8201 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8202 const TIDSortedElemSet& theNodesNot,
8203 const TIDSortedElemSet& theAffectedElems )
8205 myLastCreatedElems.Clear();
8206 myLastCreatedNodes.Clear();
8208 if ( theElems.size() == 0 )
8211 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8216 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8217 // duplicate elements and nodes
8218 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8219 // replce nodes by duplications
8220 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8225 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8226 \param theMeshDS - mesh instance
8227 \param theElems - the elements replicated or modified (nodes should be changed)
8228 \param theNodesNot - nodes to NOT replicate
8229 \param theNodeNodeMap - relation of old node to new created node
8230 \param theIsDoubleElem - flag os to replicate element or modify
8231 \return TRUE if operation has been completed successfully, FALSE otherwise
8233 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
8234 const TIDSortedElemSet& theElems,
8235 const TIDSortedElemSet& theNodesNot,
8236 std::map< const SMDS_MeshNode*,
8237 const SMDS_MeshNode* >& theNodeNodeMap,
8238 const bool theIsDoubleElem )
8240 // iterate on through element and duplicate them (by nodes duplication)
8242 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8243 for ( ; elemItr != theElems.end(); ++elemItr )
8245 const SMDS_MeshElement* anElem = *elemItr;
8249 bool isDuplicate = false;
8250 // duplicate nodes to duplicate element
8251 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8252 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8254 while ( anIter->more() )
8257 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8258 SMDS_MeshNode* aNewNode = aCurrNode;
8259 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8260 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8261 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8264 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8265 theNodeNodeMap[ aCurrNode ] = aNewNode;
8266 myLastCreatedNodes.Append( aNewNode );
8268 isDuplicate |= (aCurrNode == aNewNode);
8269 newNodes[ ind++ ] = aNewNode;
8274 if ( theIsDoubleElem )
8275 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8277 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8285 \brief Check if element located inside shape
8286 \return TRUE if IN or ON shape, FALSE otherwise
8289 static bool isInside(const SMDS_MeshElement* theElem,
8290 BRepClass3d_SolidClassifier& theBsc3d,
8291 const double theTol)
8293 gp_XYZ centerXYZ (0, 0, 0);
8294 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8295 while (aNodeItr->more())
8297 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aNodeItr->next();
8298 centerXYZ += gp_XYZ(aNode->X(), aNode->Y(), aNode->Z());
8300 gp_Pnt aPnt(centerXYZ);
8301 theBsc3d.Perform(aPnt, theTol);
8302 TopAbs_State aState = theBsc3d.State();
8303 return (aState == TopAbs_IN || aState == TopAbs_ON );
8307 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8308 \param theElems - group of of elements (edges or faces) to be replicated
8309 \param theNodesNot - group of nodes not to replicated
8310 \param theShape - shape to detect affected elements (element which geometric center
8311 located on or inside shape).
8312 The replicated nodes should be associated to affected elements.
8313 \return TRUE if operation has been completed successfully, FALSE otherwise
8316 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8317 const TIDSortedElemSet& theNodesNot,
8318 const TopoDS_Shape& theShape )
8320 SMESHDS_Mesh* aMesh = GetMeshDS();
8323 if ( theShape.IsNull() )
8326 const double aTol = Precision::Confusion();
8327 BRepClass3d_SolidClassifier bsc3d(theShape);
8328 bsc3d.PerformInfinitePoint(aTol);
8330 // iterates on indicated elements and get elements by back references from their nodes
8331 TIDSortedElemSet anAffected;
8332 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8333 for ( ; elemItr != theElems.end(); ++elemItr )
8335 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
8339 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
8340 while ( nodeItr->more() )
8342 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>(nodeItr->next());
8343 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
8345 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
8346 while ( backElemItr->more() )
8348 SMDS_MeshElement* curElem = (SMDS_MeshElement*)backElemItr->next();
8349 if ( curElem && theElems.find(curElem) == theElems.end() &&
8350 isInside( curElem, bsc3d, aTol ) )
8351 anAffected.insert( curElem );
8355 return DoubleNodes( theElems, theNodesNot, anAffected );