1 // Copyright (C) 2007-2010 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
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
50 #include "utilities.h"
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepClass3d_SolidClassifier.hxx>
54 #include <BRep_Tool.hxx>
56 #include <Extrema_GenExtPS.hxx>
57 #include <Extrema_POnCurv.hxx>
58 #include <Extrema_POnSurf.hxx>
59 #include <GC_MakeSegment.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <GeomAdaptor_Surface.hxx>
63 #include <Geom_Curve.hxx>
64 #include <Geom_Line.hxx>
65 #include <Geom_Surface.hxx>
66 #include <IntAna_IntConicQuad.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <Precision.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopAbs_State.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_ListIteratorOfListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_SequenceOfShape.hxx>
77 #include <TopoDS_Face.hxx>
83 #include <gp_Trsf.hxx>
95 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
98 using namespace SMESH::Controls;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
101 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
103 //=======================================================================
104 //function : SMESH_MeshEditor
106 //=======================================================================
108 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
109 :myMesh( theMesh ) // theMesh may be NULL
113 //=======================================================================
117 //=======================================================================
120 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
121 const SMDSAbs_ElementType type,
125 SMDS_MeshElement* e = 0;
126 int nbnode = node.size();
127 SMESHDS_Mesh* mesh = GetMeshDS();
129 case SMDSAbs_0DElement:
131 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
132 else e = mesh->Add0DElement (node[0] );
136 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
137 else e = mesh->AddEdge (node[0], node[1] );
138 else if ( nbnode == 3 )
139 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
140 else e = mesh->AddEdge (node[0], node[1], node[2] );
145 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
146 else e = mesh->AddFace (node[0], node[1], node[2] );
147 else if (nbnode == 4)
148 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
149 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
150 else if (nbnode == 6)
151 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
152 node[4], node[5], ID);
153 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
155 else if (nbnode == 8)
156 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7], ID);
158 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
159 node[4], node[5], node[6], node[7] );
161 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
162 else e = mesh->AddPolygonalFace (node );
168 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
170 else if (nbnode == 5)
171 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
175 else if (nbnode == 6)
176 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
177 node[4], node[5], ID);
178 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
180 else if (nbnode == 8)
181 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
182 node[4], node[5], node[6], node[7], ID);
183 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
184 node[4], node[5], node[6], node[7] );
185 else if (nbnode == 10)
186 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7],
188 node[8], node[9], ID);
189 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
190 node[4], node[5], node[6], node[7],
192 else if (nbnode == 13)
193 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7],
195 node[8], node[9], node[10],node[11],
197 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
198 node[4], node[5], node[6], node[7],
199 node[8], node[9], node[10],node[11],
201 else if (nbnode == 15)
202 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
205 node[12],node[13],node[14],ID);
206 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
207 node[4], node[5], node[6], node[7],
208 node[8], node[9], node[10],node[11],
209 node[12],node[13],node[14] );
210 else if (nbnode == 20)
211 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
212 node[4], node[5], node[6], node[7],
213 node[8], node[9], node[10],node[11],
214 node[12],node[13],node[14],node[15],
215 node[16],node[17],node[18],node[19],ID);
216 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
217 node[4], node[5], node[6], node[7],
218 node[8], node[9], node[10],node[11],
219 node[12],node[13],node[14],node[15],
220 node[16],node[17],node[18],node[19] );
226 //=======================================================================
230 //=======================================================================
232 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
233 const SMDSAbs_ElementType type,
237 vector<const SMDS_MeshNode*> nodes;
238 nodes.reserve( nodeIDs.size() );
239 vector<int>::const_iterator id = nodeIDs.begin();
240 while ( id != nodeIDs.end() ) {
241 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
242 nodes.push_back( node );
246 return AddElement( nodes, type, isPoly, ID );
249 //=======================================================================
251 //purpose : Remove a node or an element.
252 // Modify a compute state of sub-meshes which become empty
253 //=======================================================================
255 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
258 myLastCreatedElems.Clear();
259 myLastCreatedNodes.Clear();
261 SMESHDS_Mesh* aMesh = GetMeshDS();
262 set< SMESH_subMesh *> smmap;
264 list<int>::const_iterator it = theIDs.begin();
265 for ( ; it != theIDs.end(); it++ ) {
266 const SMDS_MeshElement * elem;
268 elem = aMesh->FindNode( *it );
270 elem = aMesh->FindElement( *it );
274 // Notify VERTEX sub-meshes about modification
276 const SMDS_MeshNode* node = cast2Node( elem );
277 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
278 if ( int aShapeID = node->GetPosition()->GetShapeId() )
279 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
282 // Find sub-meshes to notify about modification
283 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
284 // while ( nodeIt->more() ) {
285 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
286 // const SMDS_PositionPtr& aPosition = node->GetPosition();
287 // if ( aPosition.get() ) {
288 // if ( int aShapeID = aPosition->GetShapeId() ) {
289 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290 // smmap.insert( sm );
297 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
299 aMesh->RemoveElement( elem );
302 // Notify sub-meshes about modification
303 if ( !smmap.empty() ) {
304 set< SMESH_subMesh *>::iterator smIt;
305 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
306 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
309 // // Check if the whole mesh becomes empty
310 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
311 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
316 //=======================================================================
317 //function : FindShape
318 //purpose : Return an index of the shape theElem is on
319 // or zero if a shape not found
320 //=======================================================================
322 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
324 myLastCreatedElems.Clear();
325 myLastCreatedNodes.Clear();
327 SMESHDS_Mesh * aMesh = GetMeshDS();
328 if ( aMesh->ShapeToMesh().IsNull() )
331 if ( theElem->GetType() == SMDSAbs_Node ) {
332 const SMDS_PositionPtr& aPosition =
333 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
335 return aPosition->GetShapeId();
340 TopoDS_Shape aShape; // the shape a node is on
341 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
342 while ( nodeIt->more() ) {
343 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
344 const SMDS_PositionPtr& aPosition = node->GetPosition();
346 int aShapeID = aPosition->GetShapeId();
347 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
349 if ( sm->Contains( theElem ))
351 if ( aShape.IsNull() )
352 aShape = aMesh->IndexToShape( aShapeID );
355 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
360 // None of nodes is on a proper shape,
361 // find the shape among ancestors of aShape on which a node is
362 if ( aShape.IsNull() ) {
363 //MESSAGE ("::FindShape() - NONE node is on shape")
366 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
367 for ( ; ancIt.More(); ancIt.Next() ) {
368 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
369 if ( sm && sm->Contains( theElem ))
370 return aMesh->ShapeToIndex( ancIt.Value() );
373 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
377 //=======================================================================
378 //function : IsMedium
380 //=======================================================================
382 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
383 const SMDSAbs_ElementType typeToCheck)
385 bool isMedium = false;
386 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
387 while (it->more() && !isMedium ) {
388 const SMDS_MeshElement* elem = it->next();
389 isMedium = elem->IsMediumNode(node);
394 //=======================================================================
395 //function : ShiftNodesQuadTria
397 // Shift nodes in the array corresponded to quadratic triangle
398 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
399 //=======================================================================
400 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
402 const SMDS_MeshNode* nd1 = aNodes[0];
403 aNodes[0] = aNodes[1];
404 aNodes[1] = aNodes[2];
406 const SMDS_MeshNode* nd2 = aNodes[3];
407 aNodes[3] = aNodes[4];
408 aNodes[4] = aNodes[5];
412 //=======================================================================
413 //function : GetNodesFromTwoTria
415 // Shift nodes in the array corresponded to quadratic triangle
416 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
417 //=======================================================================
418 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
419 const SMDS_MeshElement * theTria2,
420 const SMDS_MeshNode* N1[],
421 const SMDS_MeshNode* N2[])
423 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
426 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
429 if(it->more()) return false;
430 it = theTria2->nodesIterator();
433 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
436 if(it->more()) return false;
438 int sames[3] = {-1,-1,-1};
450 if(nbsames!=2) return false;
452 ShiftNodesQuadTria(N1);
454 ShiftNodesQuadTria(N1);
457 i = sames[0] + sames[1] + sames[2];
459 ShiftNodesQuadTria(N2);
461 // now we receive following N1 and N2 (using numeration as above image)
462 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
463 // i.e. first nodes from both arrays determ new diagonal
467 //=======================================================================
468 //function : InverseDiag
469 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
470 // but having other common link.
471 // Return False if args are improper
472 //=======================================================================
474 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
475 const SMDS_MeshElement * theTria2 )
477 myLastCreatedElems.Clear();
478 myLastCreatedNodes.Clear();
480 if (!theTria1 || !theTria2)
483 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
484 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
487 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
488 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
492 // put nodes in array and find out indices of the same ones
493 const SMDS_MeshNode* aNodes [6];
494 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
496 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
497 while ( it->more() ) {
498 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
500 if ( i > 2 ) // theTria2
501 // find same node of theTria1
502 for ( int j = 0; j < 3; j++ )
503 if ( aNodes[ i ] == aNodes[ j ]) {
512 return false; // theTria1 is not a triangle
513 it = theTria2->nodesIterator();
515 if ( i == 6 && it->more() )
516 return false; // theTria2 is not a triangle
519 // find indices of 1,2 and of A,B in theTria1
520 int iA = 0, iB = 0, i1 = 0, i2 = 0;
521 for ( i = 0; i < 6; i++ ) {
522 if ( sameInd [ i ] == 0 )
529 // nodes 1 and 2 should not be the same
530 if ( aNodes[ i1 ] == aNodes[ i2 ] )
534 aNodes[ iA ] = aNodes[ i2 ];
536 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
538 //MESSAGE( theTria1 << theTria2 );
540 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
541 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
543 //MESSAGE( theTria1 << theTria2 );
547 } // end if(F1 && F2)
549 // check case of quadratic faces
550 const SMDS_QuadraticFaceOfNodes* QF1 =
551 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
552 if(!QF1) return false;
553 const SMDS_QuadraticFaceOfNodes* QF2 =
554 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
555 if(!QF2) return false;
558 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
559 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
567 const SMDS_MeshNode* N1 [6];
568 const SMDS_MeshNode* N2 [6];
569 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
571 // now we receive following N1 and N2 (using numeration as above image)
572 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
573 // i.e. first nodes from both arrays determ new diagonal
575 const SMDS_MeshNode* N1new [6];
576 const SMDS_MeshNode* N2new [6];
589 // replaces nodes in faces
590 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
591 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
596 //=======================================================================
597 //function : findTriangles
598 //purpose : find triangles sharing theNode1-theNode2 link
599 //=======================================================================
601 static bool findTriangles(const SMDS_MeshNode * theNode1,
602 const SMDS_MeshNode * theNode2,
603 const SMDS_MeshElement*& theTria1,
604 const SMDS_MeshElement*& theTria2)
606 if ( !theNode1 || !theNode2 ) return false;
608 theTria1 = theTria2 = 0;
610 set< const SMDS_MeshElement* > emap;
611 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
613 const SMDS_MeshElement* elem = it->next();
614 if ( elem->NbNodes() == 3 )
617 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
619 const SMDS_MeshElement* elem = it->next();
620 if ( emap.find( elem ) != emap.end() )
622 // theTria1 must be element with minimum ID
623 if( theTria1->GetID() < elem->GetID() ) {
636 return ( theTria1 && theTria2 );
639 //=======================================================================
640 //function : InverseDiag
641 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
642 // with ones built on the same 4 nodes but having other common link.
643 // Return false if proper faces not found
644 //=======================================================================
646 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
647 const SMDS_MeshNode * theNode2)
649 myLastCreatedElems.Clear();
650 myLastCreatedNodes.Clear();
652 MESSAGE( "::InverseDiag()" );
654 const SMDS_MeshElement *tr1, *tr2;
655 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
658 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
659 //if (!F1) return false;
660 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
661 //if (!F2) return false;
664 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
665 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
669 // put nodes in array
670 // and find indices of 1,2 and of A in tr1 and of B in tr2
671 int i, iA1 = 0, i1 = 0;
672 const SMDS_MeshNode* aNodes1 [3];
673 SMDS_ElemIteratorPtr it;
674 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
675 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
676 if ( aNodes1[ i ] == theNode1 )
677 iA1 = i; // node A in tr1
678 else if ( aNodes1[ i ] != theNode2 )
682 const SMDS_MeshNode* aNodes2 [3];
683 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
684 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
685 if ( aNodes2[ i ] == theNode2 )
686 iB2 = i; // node B in tr2
687 else if ( aNodes2[ i ] != theNode1 )
691 // nodes 1 and 2 should not be the same
692 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
696 aNodes1[ iA1 ] = aNodes2[ i2 ];
698 aNodes2[ iB2 ] = aNodes1[ i1 ];
700 //MESSAGE( tr1 << tr2 );
702 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
703 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
705 //MESSAGE( tr1 << tr2 );
710 // check case of quadratic faces
711 const SMDS_QuadraticFaceOfNodes* QF1 =
712 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
713 if(!QF1) return false;
714 const SMDS_QuadraticFaceOfNodes* QF2 =
715 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
716 if(!QF2) return false;
717 return InverseDiag(tr1,tr2);
720 //=======================================================================
721 //function : getQuadrangleNodes
722 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
723 // fusion of triangles tr1 and tr2 having shared link on
724 // theNode1 and theNode2
725 //=======================================================================
727 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
728 const SMDS_MeshNode * theNode1,
729 const SMDS_MeshNode * theNode2,
730 const SMDS_MeshElement * tr1,
731 const SMDS_MeshElement * tr2 )
733 if( tr1->NbNodes() != tr2->NbNodes() )
735 // find the 4-th node to insert into tr1
736 const SMDS_MeshNode* n4 = 0;
737 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
739 while ( !n4 && i<3 ) {
740 const SMDS_MeshNode * n = cast2Node( it->next() );
742 bool isDiag = ( n == theNode1 || n == theNode2 );
746 // Make an array of nodes to be in a quadrangle
747 int iNode = 0, iFirstDiag = -1;
748 it = tr1->nodesIterator();
751 const SMDS_MeshNode * n = cast2Node( it->next() );
753 bool isDiag = ( n == theNode1 || n == theNode2 );
755 if ( iFirstDiag < 0 )
757 else if ( iNode - iFirstDiag == 1 )
758 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
760 else if ( n == n4 ) {
761 return false; // tr1 and tr2 should not have all the same nodes
763 theQuadNodes[ iNode++ ] = n;
765 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
766 theQuadNodes[ iNode ] = n4;
771 //=======================================================================
772 //function : DeleteDiag
773 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
774 // with a quadrangle built on the same 4 nodes.
775 // Return false if proper faces not found
776 //=======================================================================
778 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
779 const SMDS_MeshNode * theNode2)
781 myLastCreatedElems.Clear();
782 myLastCreatedNodes.Clear();
784 MESSAGE( "::DeleteDiag()" );
786 const SMDS_MeshElement *tr1, *tr2;
787 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
790 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
791 //if (!F1) return false;
792 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
793 //if (!F2) return false;
796 const SMDS_MeshNode* aNodes [ 4 ];
797 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
800 //MESSAGE( endl << tr1 << tr2 );
802 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
803 myLastCreatedElems.Append(tr1);
804 GetMeshDS()->RemoveElement( tr2 );
806 //MESSAGE( endl << tr1 );
811 // check case of quadratic faces
812 const SMDS_QuadraticFaceOfNodes* QF1 =
813 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
814 if(!QF1) return false;
815 const SMDS_QuadraticFaceOfNodes* QF2 =
816 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
817 if(!QF2) return false;
820 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
821 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
829 const SMDS_MeshNode* N1 [6];
830 const SMDS_MeshNode* N2 [6];
831 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
833 // now we receive following N1 and N2 (using numeration as above image)
834 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
835 // i.e. first nodes from both arrays determ new diagonal
837 const SMDS_MeshNode* aNodes[8];
847 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
848 myLastCreatedElems.Append(tr1);
849 GetMeshDS()->RemoveElement( tr2 );
851 // remove middle node (9)
852 GetMeshDS()->RemoveNode( N1[4] );
857 //=======================================================================
858 //function : Reorient
859 //purpose : Reverse theElement orientation
860 //=======================================================================
862 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
864 myLastCreatedElems.Clear();
865 myLastCreatedNodes.Clear();
869 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
870 if ( !it || !it->more() )
873 switch ( theElem->GetType() ) {
877 if(!theElem->IsQuadratic()) {
878 int i = theElem->NbNodes();
879 vector<const SMDS_MeshNode*> aNodes( i );
881 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
882 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
885 // quadratic elements
886 if(theElem->GetType()==SMDSAbs_Edge) {
887 vector<const SMDS_MeshNode*> aNodes(3);
888 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
889 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
890 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
891 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
894 int nbn = theElem->NbNodes();
895 vector<const SMDS_MeshNode*> aNodes(nbn);
896 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
898 for(; i<nbn/2; i++) {
899 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
901 for(i=0; i<nbn/2; i++) {
902 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
904 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
908 case SMDSAbs_Volume: {
909 if (theElem->IsPoly()) {
910 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
911 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
913 MESSAGE("Warning: bad volumic element");
917 int nbFaces = aPolyedre->NbFaces();
918 vector<const SMDS_MeshNode *> poly_nodes;
919 vector<int> quantities (nbFaces);
921 // reverse each face of the polyedre
922 for (int iface = 1; iface <= nbFaces; iface++) {
923 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
924 quantities[iface - 1] = nbFaceNodes;
926 for (inode = nbFaceNodes; inode >= 1; inode--) {
927 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
928 poly_nodes.push_back(curNode);
932 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
936 SMDS_VolumeTool vTool;
937 if ( !vTool.Set( theElem ))
940 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
949 //=======================================================================
950 //function : getBadRate
952 //=======================================================================
954 static double getBadRate (const SMDS_MeshElement* theElem,
955 SMESH::Controls::NumericalFunctorPtr& theCrit)
957 SMESH::Controls::TSequenceOfXYZ P;
958 if ( !theElem || !theCrit->GetPoints( theElem, P ))
960 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
961 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
964 //=======================================================================
965 //function : QuadToTri
966 //purpose : Cut quadrangles into triangles.
967 // theCrit is used to select a diagonal to cut
968 //=======================================================================
970 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
971 SMESH::Controls::NumericalFunctorPtr theCrit)
973 myLastCreatedElems.Clear();
974 myLastCreatedNodes.Clear();
976 MESSAGE( "::QuadToTri()" );
978 if ( !theCrit.get() )
981 SMESHDS_Mesh * aMesh = GetMeshDS();
983 Handle(Geom_Surface) surface;
984 SMESH_MesherHelper helper( *GetMesh() );
986 TIDSortedElemSet::iterator itElem;
987 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
988 const SMDS_MeshElement* elem = *itElem;
989 if ( !elem || elem->GetType() != SMDSAbs_Face )
991 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
994 // retrieve element nodes
995 const SMDS_MeshNode* aNodes [8];
996 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
998 while ( itN->more() )
999 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1001 // compare two sets of possible triangles
1002 double aBadRate1, aBadRate2; // to what extent a set is bad
1003 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1004 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1005 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1007 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1008 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1009 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1011 int aShapeId = FindShape( elem );
1012 const SMDS_MeshElement* newElem = 0;
1014 if( !elem->IsQuadratic() ) {
1016 // split liner quadrangle
1018 if ( aBadRate1 <= aBadRate2 ) {
1019 // tr1 + tr2 is better
1020 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1021 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1024 // tr3 + tr4 is better
1025 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1026 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1031 // split quadratic quadrangle
1033 // get surface elem is on
1034 if ( aShapeId != helper.GetSubShapeID() ) {
1038 shape = aMesh->IndexToShape( aShapeId );
1039 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1040 TopoDS_Face face = TopoDS::Face( shape );
1041 surface = BRep_Tool::Surface( face );
1042 if ( !surface.IsNull() )
1043 helper.SetSubShape( shape );
1047 const SMDS_MeshNode* aNodes [8];
1048 const SMDS_MeshNode* inFaceNode = 0;
1049 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1051 while ( itN->more() ) {
1052 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1053 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1054 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1056 inFaceNode = aNodes[ i-1 ];
1059 // find middle point for (0,1,2,3)
1060 // and create a node in this point;
1062 if ( surface.IsNull() ) {
1064 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1068 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1071 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1073 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1075 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1076 myLastCreatedNodes.Append(newN);
1078 // create a new element
1079 const SMDS_MeshNode* N[6];
1080 if ( aBadRate1 <= aBadRate2 ) {
1087 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1088 aNodes[6], aNodes[7], newN );
1097 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1098 aNodes[7], aNodes[4], newN );
1100 aMesh->ChangeElementNodes( elem, N, 6 );
1104 // care of a new element
1106 myLastCreatedElems.Append(newElem);
1107 AddToSameGroups( newElem, elem, aMesh );
1109 // put a new triangle on the same shape
1111 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1116 //=======================================================================
1117 //function : BestSplit
1118 //purpose : Find better diagonal for cutting.
1119 //=======================================================================
1121 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1122 SMESH::Controls::NumericalFunctorPtr theCrit)
1124 myLastCreatedElems.Clear();
1125 myLastCreatedNodes.Clear();
1130 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1133 if( theQuad->NbNodes()==4 ||
1134 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1136 // retrieve element nodes
1137 const SMDS_MeshNode* aNodes [4];
1138 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1140 //while (itN->more())
1142 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1144 // compare two sets of possible triangles
1145 double aBadRate1, aBadRate2; // to what extent a set is bad
1146 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1147 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1148 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1150 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1151 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1152 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1154 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1155 return 1; // diagonal 1-3
1157 return 2; // diagonal 2-4
1164 // Methods of splitting volumes into tetra
1166 const int theHexTo5_1[5*4+1] =
1168 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1170 const int theHexTo5_2[5*4+1] =
1172 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1174 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1176 const int theHexTo6_1[6*4+1] =
1178 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1
1180 const int theHexTo6_2[6*4+1] =
1182 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1
1184 const int theHexTo6_3[6*4+1] =
1186 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1
1188 const int theHexTo6_4[6*4+1] =
1190 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1
1192 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1194 const int thePyraTo2_1[2*4+1] =
1196 0, 1, 2, 4, 0, 2, 3, 4, -1
1198 const int thePyraTo2_2[2*4+1] =
1200 1, 2, 3, 4, 1, 3, 0, 4, -1
1202 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1204 const int thePentaTo3_1[3*4+1] =
1206 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1208 const int thePentaTo3_2[3*4+1] =
1210 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1212 const int thePentaTo3_3[3*4+1] =
1214 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1216 const int thePentaTo3_4[3*4+1] =
1218 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1220 const int thePentaTo3_5[3*4+1] =
1222 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1224 const int thePentaTo3_6[3*4+1] =
1226 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1228 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1229 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1231 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1234 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1235 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1236 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1241 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1242 bool _baryNode; //!< additional node is to be created at cell barycenter
1243 bool _ownConn; //!< to delete _connectivity in destructor
1245 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1246 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1247 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1248 bool hasFacet( const TTriangleFacet& facet ) const
1250 const int* tetConn = _connectivity;
1251 for ( ; tetConn[0] >= 0; tetConn += 4 )
1252 if (( facet.contains( tetConn[0] ) +
1253 facet.contains( tetConn[1] ) +
1254 facet.contains( tetConn[2] ) +
1255 facet.contains( tetConn[3] )) == 3 )
1261 //=======================================================================
1263 * \brief return TSplitMethod for the given element
1265 //=======================================================================
1267 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1269 int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1271 // Find out how adjacent volumes are split
1273 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1274 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1275 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1277 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1278 maxTetConnSize += 4 * ( nbNodes - 2 );
1279 if ( nbNodes < 4 ) continue;
1281 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1282 const int* nInd = vol.GetFaceNodesIndices( iF );
1285 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1286 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1287 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1288 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1292 int iCom = 0; // common node of triangle faces to split into
1293 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1295 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1296 nInd[ iQ * ( (iCom+1)%nbNodes )],
1297 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1298 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1299 nInd[ iQ * ( (iCom+2)%nbNodes )],
1300 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1301 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1303 triaSplits.push_back( t012 );
1304 triaSplits.push_back( t023 );
1309 if ( !triaSplits.empty() )
1310 hasAdjacentSplits = true;
1313 // Among variants of split method select one compliant with adjacent volumes
1315 TSplitMethod method;
1316 if ( !vol.Element()->IsPoly() )
1318 int nbVariants = 2, nbTet = 0;
1319 const int** connVariants = 0;
1320 switch ( vol.Element()->GetEntityType() )
1322 case SMDSEntity_Hexa:
1323 case SMDSEntity_Quad_Hexa:
1324 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1325 connVariants = theHexTo5, nbTet = 5;
1327 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1329 case SMDSEntity_Pyramid:
1330 case SMDSEntity_Quad_Pyramid:
1331 connVariants = thePyraTo2; nbTet = 2;
1333 case SMDSEntity_Penta:
1334 case SMDSEntity_Quad_Penta:
1335 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1340 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1342 // check method compliancy with adjacent tetras,
1343 // all found splits must be among facets of tetras described by this method
1344 method = TSplitMethod( nbTet, connVariants[variant] );
1345 if ( hasAdjacentSplits && method._nbTetra > 0 )
1347 bool facetCreated = true;
1348 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1350 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1351 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1352 facetCreated = method.hasFacet( *facet );
1354 if ( !facetCreated )
1355 method = TSplitMethod(0); // incompatible method
1359 if ( method._nbTetra < 1 )
1361 // No standard method is applicable, use a generic solution:
1362 // each facet of a volume is split into triangles and
1363 // each of triangles and a volume barycenter form a tetrahedron.
1365 int* connectivity = new int[ maxTetConnSize + 1 ];
1366 method._connectivity = connectivity;
1367 method._ownConn = true;
1368 method._baryNode = true;
1371 int baryCenInd = vol.NbNodes();
1372 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1374 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1375 const int* nInd = vol.GetFaceNodesIndices( iF );
1376 // find common node of triangle facets of tetra to create
1377 int iCommon = 0; // index in linear numeration
1378 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1379 if ( !triaSplits.empty() )
1382 const TTriangleFacet* facet = &triaSplits.front();
1383 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1384 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1385 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1388 else if ( nbNodes > 3 )
1390 // find the best method of splitting into triangles by aspect ratio
1391 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1392 map< double, int > badness2iCommon;
1393 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1394 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1395 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1396 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1398 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1399 nodes[ iQ*((iLast-1)%nbNodes)],
1400 nodes[ iQ*((iLast )%nbNodes)]);
1401 double badness = getBadRate( &tria, aspectRatio );
1402 badness2iCommon.insert( make_pair( badness, iCommon ));
1404 // use iCommon with lowest badness
1405 iCommon = badness2iCommon.begin()->second;
1407 if ( iCommon >= nbNodes )
1408 iCommon = 0; // something wrong
1409 // fill connectivity of tetra
1410 int nbTet = nbNodes - 2;
1411 for ( int i = 0; i < nbTet; ++i )
1413 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1414 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1415 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1416 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1417 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1418 connectivity[ connSize++ ] = baryCenInd;
1422 connectivity[ connSize++ ] = -1;
1426 //================================================================================
1428 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1430 //================================================================================
1432 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1434 // find the tetrahedron including the three nodes of facet
1435 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1436 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1437 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1438 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1439 while ( volIt1->more() )
1441 const SMDS_MeshElement* v = volIt1->next();
1442 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1444 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1445 while ( volIt2->more() )
1446 if ( v != volIt2->next() )
1448 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1449 while ( volIt3->more() )
1450 if ( v == volIt3->next() )
1457 //=======================================================================
1458 //function : SplitVolumesIntoTetra
1459 //purpose : Split volumic elements into tetrahedra.
1460 //=======================================================================
1462 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1463 const int theMethodFlags)
1465 // std-like iterator on coordinates of nodes of mesh element
1466 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1467 NXyzIterator xyzEnd;
1469 SMDS_VolumeTool volTool;
1470 SMESH_MesherHelper helper( *GetMesh());
1472 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1473 SMESHDS_SubMesh* fSubMesh = subMesh;
1475 SMESH_SequenceOfElemPtr newNodes, newElems;
1477 TIDSortedElemSet::const_iterator elem = theElems.begin();
1478 for ( ; elem != theElems.end(); ++elem )
1480 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1481 if ( geomType <= SMDSEntity_Quad_Tetra )
1482 continue; // tetra or face or ...
1484 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1486 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1487 if ( splitMethod._nbTetra < 1 ) continue;
1489 // find submesh to add new tetras in
1490 if ( !subMesh || !subMesh->Contains( *elem ))
1492 int shapeID = FindShape( *elem );
1493 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1494 subMesh = GetMeshDS()->MeshElements( shapeID );
1497 if ( (*elem)->IsQuadratic() )
1500 // add quadratic links to the helper
1501 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1503 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1504 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1505 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1507 helper.SetIsQuadratic( true );
1512 helper.SetIsQuadratic( false );
1514 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1515 if ( splitMethod._baryNode )
1517 // make a node at barycenter
1519 gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1520 SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1521 nodes.push_back( gcNode );
1522 newNodes.Append( gcNode );
1526 helper.SetElementsOnShape( true );
1527 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1528 const int* tetConn = splitMethod._connectivity;
1529 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1530 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1531 nodes[ tetConn[1] ],
1532 nodes[ tetConn[2] ],
1533 nodes[ tetConn[3] ]));
1535 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1537 // Split faces on sides of the split volume
1539 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1540 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1542 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1543 if ( nbNodes < 4 ) continue;
1545 // find an existing face
1546 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1547 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1548 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1550 // among possible triangles create ones discribed by split method
1551 const int* nInd = volTool.GetFaceNodesIndices( iF );
1552 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1553 int iCom = 0; // common node of triangle faces to split into
1554 list< TTriangleFacet > facets;
1555 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1557 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1558 nInd[ iQ * ( (iCom+1)%nbNodes )],
1559 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1560 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1561 nInd[ iQ * ( (iCom+2)%nbNodes )],
1562 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1563 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1565 facets.push_back( t012 );
1566 facets.push_back( t023 );
1567 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1568 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1569 nInd[ iQ * ((iLast-1)%nbNodes )],
1570 nInd[ iQ * ((iLast )%nbNodes )]));
1574 // find submesh to add new faces in
1575 if ( !fSubMesh || !fSubMesh->Contains( face ))
1577 int shapeID = FindShape( face );
1578 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1581 helper.SetElementsOnShape( false );
1582 vector< const SMDS_MeshElement* > triangles;
1583 list< TTriangleFacet >::iterator facet = facets.begin();
1584 for ( ; facet != facets.end(); ++facet )
1586 if ( !volTool.IsFaceExternal( iF ))
1587 swap( facet->_n2, facet->_n3 );
1588 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1589 volNodes[ facet->_n2 ],
1590 volNodes[ facet->_n3 ]));
1591 if ( triangles.back() && fSubMesh )
1592 fSubMesh->AddElement( triangles.back());
1593 newElems.Append( triangles.back() );
1595 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1596 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1599 } // loop on volume faces to split them into triangles
1601 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1603 } // loop on volumes to split
1605 myLastCreatedNodes = newNodes;
1606 myLastCreatedElems = newElems;
1609 //=======================================================================
1610 //function : AddToSameGroups
1611 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1612 //=======================================================================
1614 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1615 const SMDS_MeshElement* elemInGroups,
1616 SMESHDS_Mesh * aMesh)
1618 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1619 if (!groups.empty()) {
1620 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1621 for ( ; grIt != groups.end(); grIt++ ) {
1622 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1623 if ( group && group->Contains( elemInGroups ))
1624 group->SMDSGroup().Add( elemToAdd );
1630 //=======================================================================
1631 //function : RemoveElemFromGroups
1632 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1633 //=======================================================================
1634 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1635 SMESHDS_Mesh * aMesh)
1637 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1638 if (!groups.empty())
1640 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1641 for (; GrIt != groups.end(); GrIt++)
1643 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1644 if (!grp || grp->IsEmpty()) continue;
1645 grp->SMDSGroup().Remove(removeelem);
1650 //================================================================================
1652 * \brief Replace elemToRm by elemToAdd in the all groups
1654 //================================================================================
1656 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1657 const SMDS_MeshElement* elemToAdd,
1658 SMESHDS_Mesh * aMesh)
1660 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1661 if (!groups.empty()) {
1662 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1663 for ( ; grIt != groups.end(); grIt++ ) {
1664 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1665 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1666 group->SMDSGroup().Add( elemToAdd );
1671 //================================================================================
1673 * \brief Replace elemToRm by elemToAdd in the all groups
1675 //================================================================================
1677 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1678 const vector<const SMDS_MeshElement*>& elemToAdd,
1679 SMESHDS_Mesh * aMesh)
1681 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1682 if (!groups.empty())
1684 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1685 for ( ; grIt != groups.end(); grIt++ ) {
1686 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1687 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1688 for ( int i = 0; i < elemToAdd.size(); ++i )
1689 group->SMDSGroup().Add( elemToAdd[ i ] );
1694 //=======================================================================
1695 //function : QuadToTri
1696 //purpose : Cut quadrangles into triangles.
1697 // theCrit is used to select a diagonal to cut
1698 //=======================================================================
1700 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1701 const bool the13Diag)
1703 myLastCreatedElems.Clear();
1704 myLastCreatedNodes.Clear();
1706 MESSAGE( "::QuadToTri()" );
1708 SMESHDS_Mesh * aMesh = GetMeshDS();
1710 Handle(Geom_Surface) surface;
1711 SMESH_MesherHelper helper( *GetMesh() );
1713 TIDSortedElemSet::iterator itElem;
1714 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1715 const SMDS_MeshElement* elem = *itElem;
1716 if ( !elem || elem->GetType() != SMDSAbs_Face )
1718 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1719 if(!isquad) continue;
1721 if(elem->NbNodes()==4) {
1722 // retrieve element nodes
1723 const SMDS_MeshNode* aNodes [4];
1724 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1726 while ( itN->more() )
1727 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1729 int aShapeId = FindShape( elem );
1730 const SMDS_MeshElement* newElem = 0;
1732 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1733 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1736 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1737 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1739 myLastCreatedElems.Append(newElem);
1740 // put a new triangle on the same shape and add to the same groups
1742 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1743 AddToSameGroups( newElem, elem, aMesh );
1746 // Quadratic quadrangle
1748 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1750 // get surface elem is on
1751 int aShapeId = FindShape( elem );
1752 if ( aShapeId != helper.GetSubShapeID() ) {
1756 shape = aMesh->IndexToShape( aShapeId );
1757 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1758 TopoDS_Face face = TopoDS::Face( shape );
1759 surface = BRep_Tool::Surface( face );
1760 if ( !surface.IsNull() )
1761 helper.SetSubShape( shape );
1765 const SMDS_MeshNode* aNodes [8];
1766 const SMDS_MeshNode* inFaceNode = 0;
1767 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1769 while ( itN->more() ) {
1770 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1771 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1772 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1774 inFaceNode = aNodes[ i-1 ];
1778 // find middle point for (0,1,2,3)
1779 // and create a node in this point;
1781 if ( surface.IsNull() ) {
1783 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1787 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1790 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1792 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1794 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1795 myLastCreatedNodes.Append(newN);
1797 // create a new element
1798 const SMDS_MeshElement* newElem = 0;
1799 const SMDS_MeshNode* N[6];
1807 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1808 aNodes[6], aNodes[7], newN );
1817 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1818 aNodes[7], aNodes[4], newN );
1820 myLastCreatedElems.Append(newElem);
1821 aMesh->ChangeElementNodes( elem, N, 6 );
1822 // put a new triangle on the same shape and add to the same groups
1824 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1825 AddToSameGroups( newElem, elem, aMesh );
1832 //=======================================================================
1833 //function : getAngle
1835 //=======================================================================
1837 double getAngle(const SMDS_MeshElement * tr1,
1838 const SMDS_MeshElement * tr2,
1839 const SMDS_MeshNode * n1,
1840 const SMDS_MeshNode * n2)
1842 double angle = 2*PI; // bad angle
1845 SMESH::Controls::TSequenceOfXYZ P1, P2;
1846 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1847 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1850 if(!tr1->IsQuadratic())
1851 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1853 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1854 if ( N1.SquareMagnitude() <= gp::Resolution() )
1856 if(!tr2->IsQuadratic())
1857 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1859 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1860 if ( N2.SquareMagnitude() <= gp::Resolution() )
1863 // find the first diagonal node n1 in the triangles:
1864 // take in account a diagonal link orientation
1865 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1866 for ( int t = 0; t < 2; t++ ) {
1867 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1868 int i = 0, iDiag = -1;
1869 while ( it->more()) {
1870 const SMDS_MeshElement *n = it->next();
1871 if ( n == n1 || n == n2 )
1875 if ( i - iDiag == 1 )
1876 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1884 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1887 angle = N1.Angle( N2 );
1892 // =================================================
1893 // class generating a unique ID for a pair of nodes
1894 // and able to return nodes by that ID
1895 // =================================================
1899 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1900 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1903 long GetLinkID (const SMDS_MeshNode * n1,
1904 const SMDS_MeshNode * n2) const
1906 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1909 bool GetNodes (const long theLinkID,
1910 const SMDS_MeshNode* & theNode1,
1911 const SMDS_MeshNode* & theNode2) const
1913 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1914 if ( !theNode1 ) return false;
1915 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1916 if ( !theNode2 ) return false;
1922 const SMESHDS_Mesh* myMesh;
1927 //=======================================================================
1928 //function : TriToQuad
1929 //purpose : Fuse neighbour triangles into quadrangles.
1930 // theCrit is used to select a neighbour to fuse with.
1931 // theMaxAngle is a max angle between element normals at which
1932 // fusion is still performed.
1933 //=======================================================================
1935 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1936 SMESH::Controls::NumericalFunctorPtr theCrit,
1937 const double theMaxAngle)
1939 myLastCreatedElems.Clear();
1940 myLastCreatedNodes.Clear();
1942 MESSAGE( "::TriToQuad()" );
1944 if ( !theCrit.get() )
1947 SMESHDS_Mesh * aMesh = GetMeshDS();
1949 // Prepare data for algo: build
1950 // 1. map of elements with their linkIDs
1951 // 2. map of linkIDs with their elements
1953 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1954 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1955 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1956 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1958 TIDSortedElemSet::iterator itElem;
1959 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1960 const SMDS_MeshElement* elem = *itElem;
1961 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1962 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1963 if(!IsTria) continue;
1965 // retrieve element nodes
1966 const SMDS_MeshNode* aNodes [4];
1967 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1970 aNodes[ i++ ] = cast2Node( itN->next() );
1971 aNodes[ 3 ] = aNodes[ 0 ];
1974 for ( i = 0; i < 3; i++ ) {
1975 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1976 // check if elements sharing a link can be fused
1977 itLE = mapLi_listEl.find( link );
1978 if ( itLE != mapLi_listEl.end() ) {
1979 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1981 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1982 //if ( FindShape( elem ) != FindShape( elem2 ))
1983 // continue; // do not fuse triangles laying on different shapes
1984 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1985 continue; // avoid making badly shaped quads
1986 (*itLE).second.push_back( elem );
1989 mapLi_listEl[ link ].push_back( elem );
1991 mapEl_setLi [ elem ].insert( link );
1994 // Clean the maps from the links shared by a sole element, ie
1995 // links to which only one element is bound in mapLi_listEl
1997 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1998 int nbElems = (*itLE).second.size();
1999 if ( nbElems < 2 ) {
2000 const SMDS_MeshElement* elem = (*itLE).second.front();
2001 SMESH_TLink link = (*itLE).first;
2002 mapEl_setLi[ elem ].erase( link );
2003 if ( mapEl_setLi[ elem ].empty() )
2004 mapEl_setLi.erase( elem );
2008 // Algo: fuse triangles into quadrangles
2010 while ( ! mapEl_setLi.empty() ) {
2011 // Look for the start element:
2012 // the element having the least nb of shared links
2013 const SMDS_MeshElement* startElem = 0;
2015 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2016 int nbLinks = (*itEL).second.size();
2017 if ( nbLinks < minNbLinks ) {
2018 startElem = (*itEL).first;
2019 minNbLinks = nbLinks;
2020 if ( minNbLinks == 1 )
2025 // search elements to fuse starting from startElem or links of elements
2026 // fused earlyer - startLinks
2027 list< SMESH_TLink > startLinks;
2028 while ( startElem || !startLinks.empty() ) {
2029 while ( !startElem && !startLinks.empty() ) {
2030 // Get an element to start, by a link
2031 SMESH_TLink linkId = startLinks.front();
2032 startLinks.pop_front();
2033 itLE = mapLi_listEl.find( linkId );
2034 if ( itLE != mapLi_listEl.end() ) {
2035 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2036 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2037 for ( ; itE != listElem.end() ; itE++ )
2038 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2040 mapLi_listEl.erase( itLE );
2045 // Get candidates to be fused
2046 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2047 const SMESH_TLink *link12, *link13;
2049 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2050 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2051 ASSERT( !setLi.empty() );
2052 set< SMESH_TLink >::iterator itLi;
2053 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2055 const SMESH_TLink & link = (*itLi);
2056 itLE = mapLi_listEl.find( link );
2057 if ( itLE == mapLi_listEl.end() )
2060 const SMDS_MeshElement* elem = (*itLE).second.front();
2062 elem = (*itLE).second.back();
2063 mapLi_listEl.erase( itLE );
2064 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2075 // add other links of elem to list of links to re-start from
2076 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2077 set< SMESH_TLink >::iterator it;
2078 for ( it = links.begin(); it != links.end(); it++ ) {
2079 const SMESH_TLink& link2 = (*it);
2080 if ( link2 != link )
2081 startLinks.push_back( link2 );
2085 // Get nodes of possible quadrangles
2086 const SMDS_MeshNode *n12 [4], *n13 [4];
2087 bool Ok12 = false, Ok13 = false;
2088 const SMDS_MeshNode *linkNode1, *linkNode2;
2090 linkNode1 = link12->first;
2091 linkNode2 = link12->second;
2092 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2096 linkNode1 = link13->first;
2097 linkNode2 = link13->second;
2098 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2102 // Choose a pair to fuse
2103 if ( Ok12 && Ok13 ) {
2104 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2105 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2106 double aBadRate12 = getBadRate( &quad12, theCrit );
2107 double aBadRate13 = getBadRate( &quad13, theCrit );
2108 if ( aBadRate13 < aBadRate12 )
2115 // and remove fused elems and removed links from the maps
2116 mapEl_setLi.erase( tr1 );
2118 mapEl_setLi.erase( tr2 );
2119 mapLi_listEl.erase( *link12 );
2120 if(tr1->NbNodes()==3) {
2121 if( tr1->GetID() < tr2->GetID() ) {
2122 aMesh->ChangeElementNodes( tr1, n12, 4 );
2123 myLastCreatedElems.Append(tr1);
2124 aMesh->RemoveElement( tr2 );
2127 aMesh->ChangeElementNodes( tr2, n12, 4 );
2128 myLastCreatedElems.Append(tr2);
2129 aMesh->RemoveElement( tr1);
2133 const SMDS_MeshNode* N1 [6];
2134 const SMDS_MeshNode* N2 [6];
2135 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2136 // now we receive following N1 and N2 (using numeration as above image)
2137 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2138 // i.e. first nodes from both arrays determ new diagonal
2139 const SMDS_MeshNode* aNodes[8];
2148 if( tr1->GetID() < tr2->GetID() ) {
2149 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2150 myLastCreatedElems.Append(tr1);
2151 GetMeshDS()->RemoveElement( tr2 );
2154 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2155 myLastCreatedElems.Append(tr2);
2156 GetMeshDS()->RemoveElement( tr1 );
2158 // remove middle node (9)
2159 GetMeshDS()->RemoveNode( N1[4] );
2163 mapEl_setLi.erase( tr3 );
2164 mapLi_listEl.erase( *link13 );
2165 if(tr1->NbNodes()==3) {
2166 if( tr1->GetID() < tr2->GetID() ) {
2167 aMesh->ChangeElementNodes( tr1, n13, 4 );
2168 myLastCreatedElems.Append(tr1);
2169 aMesh->RemoveElement( tr3 );
2172 aMesh->ChangeElementNodes( tr3, n13, 4 );
2173 myLastCreatedElems.Append(tr3);
2174 aMesh->RemoveElement( tr1 );
2178 const SMDS_MeshNode* N1 [6];
2179 const SMDS_MeshNode* N2 [6];
2180 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2181 // now we receive following N1 and N2 (using numeration as above image)
2182 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2183 // i.e. first nodes from both arrays determ new diagonal
2184 const SMDS_MeshNode* aNodes[8];
2193 if( tr1->GetID() < tr2->GetID() ) {
2194 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2195 myLastCreatedElems.Append(tr1);
2196 GetMeshDS()->RemoveElement( tr3 );
2199 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2200 myLastCreatedElems.Append(tr3);
2201 GetMeshDS()->RemoveElement( tr1 );
2203 // remove middle node (9)
2204 GetMeshDS()->RemoveNode( N1[4] );
2208 // Next element to fuse: the rejected one
2210 startElem = Ok12 ? tr3 : tr2;
2212 } // if ( startElem )
2213 } // while ( startElem || !startLinks.empty() )
2214 } // while ( ! mapEl_setLi.empty() )
2220 /*#define DUMPSO(txt) \
2221 // cout << txt << endl;
2222 //=============================================================================
2226 //=============================================================================
2227 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2231 int tmp = idNodes[ i1 ];
2232 idNodes[ i1 ] = idNodes[ i2 ];
2233 idNodes[ i2 ] = tmp;
2234 gp_Pnt Ptmp = P[ i1 ];
2237 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2240 //=======================================================================
2241 //function : SortQuadNodes
2242 //purpose : Set 4 nodes of a quadrangle face in a good order.
2243 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2245 //=======================================================================
2247 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2252 for ( i = 0; i < 4; i++ ) {
2253 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2255 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2258 gp_Vec V1(P[0], P[1]);
2259 gp_Vec V2(P[0], P[2]);
2260 gp_Vec V3(P[0], P[3]);
2262 gp_Vec Cross1 = V1 ^ V2;
2263 gp_Vec Cross2 = V2 ^ V3;
2266 if (Cross1.Dot(Cross2) < 0)
2271 if (Cross1.Dot(Cross2) < 0)
2275 swap ( i, i + 1, idNodes, P );
2277 // for ( int ii = 0; ii < 4; ii++ ) {
2278 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2279 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2285 //=======================================================================
2286 //function : SortHexaNodes
2287 //purpose : Set 8 nodes of a hexahedron in a good order.
2288 // Return success status
2289 //=======================================================================
2291 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2296 DUMPSO( "INPUT: ========================================");
2297 for ( i = 0; i < 8; i++ ) {
2298 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2299 if ( !n ) return false;
2300 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2301 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2303 DUMPSO( "========================================");
2306 set<int> faceNodes; // ids of bottom face nodes, to be found
2307 set<int> checkedId1; // ids of tried 2-nd nodes
2308 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2309 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2310 int iMin, iLoop1 = 0;
2312 // Loop to try the 2-nd nodes
2314 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2316 // Find not checked 2-nd node
2317 for ( i = 1; i < 8; i++ )
2318 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2319 int id1 = idNodes[i];
2320 swap ( 1, i, idNodes, P );
2321 checkedId1.insert ( id1 );
2325 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2326 // ie that all but meybe one (id3 which is on the same face) nodes
2327 // lay on the same side from the triangle plane.
2329 bool manyInPlane = false; // more than 4 nodes lay in plane
2331 while ( ++iLoop2 < 6 ) {
2333 // get 1-2-3 plane coeffs
2334 Standard_Real A, B, C, D;
2335 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2336 if ( N.SquareMagnitude() > gp::Resolution() )
2338 gp_Pln pln ( P[0], N );
2339 pln.Coefficients( A, B, C, D );
2341 // find the node (iMin) closest to pln
2342 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2344 for ( i = 3; i < 8; i++ ) {
2345 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2346 if ( fabs( dist[i] ) < minDist ) {
2347 minDist = fabs( dist[i] );
2350 if ( fabs( dist[i] ) <= tol )
2351 idInPln.insert( idNodes[i] );
2354 // there should not be more than 4 nodes in bottom plane
2355 if ( idInPln.size() > 1 )
2357 DUMPSO( "### idInPln.size() = " << idInPln.size());
2358 // idInPlane does not contain the first 3 nodes
2359 if ( manyInPlane || idInPln.size() == 5)
2360 return false; // all nodes in one plane
2363 // set the 1-st node to be not in plane
2364 for ( i = 3; i < 8; i++ ) {
2365 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2366 DUMPSO( "### Reset 0-th node");
2367 swap( 0, i, idNodes, P );
2372 // reset to re-check second nodes
2373 leastDist = DBL_MAX;
2377 break; // from iLoop2;
2380 // check that the other 4 nodes are on the same side
2381 bool sameSide = true;
2382 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2383 for ( i = 3; sameSide && i < 8; i++ ) {
2385 sameSide = ( isNeg == dist[i] <= 0.);
2388 // keep best solution
2389 if ( sameSide && minDist < leastDist ) {
2390 leastDist = minDist;
2392 faceNodes.insert( idNodes[ 1 ] );
2393 faceNodes.insert( idNodes[ 2 ] );
2394 faceNodes.insert( idNodes[ iMin ] );
2395 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2396 << " leastDist = " << leastDist);
2397 if ( leastDist <= DBL_MIN )
2402 // set next 3-d node to check
2403 int iNext = 2 + iLoop2;
2405 DUMPSO( "Try 2-nd");
2406 swap ( 2, iNext, idNodes, P );
2408 } // while ( iLoop2 < 6 )
2411 if ( faceNodes.empty() ) return false;
2413 // Put the faceNodes in proper places
2414 for ( i = 4; i < 8; i++ ) {
2415 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2416 // find a place to put
2418 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2420 DUMPSO( "Set faceNodes");
2421 swap ( iTo, i, idNodes, P );
2426 // Set nodes of the found bottom face in good order
2427 DUMPSO( " Found bottom face: ");
2428 i = SortQuadNodes( theMesh, idNodes );
2430 gp_Pnt Ptmp = P[ i ];
2435 // for ( int ii = 0; ii < 4; ii++ ) {
2436 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2437 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2440 // Gravity center of the top and bottom faces
2441 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2442 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2444 // Get direction from the bottom to the top face
2445 gp_Vec upDir ( aGCb, aGCt );
2446 Standard_Real upDirSize = upDir.Magnitude();
2447 if ( upDirSize <= gp::Resolution() ) return false;
2450 // Assure that the bottom face normal points up
2451 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2452 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2453 if ( Nb.Dot( upDir ) < 0 ) {
2454 DUMPSO( "Reverse bottom face");
2455 swap( 1, 3, idNodes, P );
2458 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2459 Standard_Real minDist = DBL_MAX;
2460 for ( i = 4; i < 8; i++ ) {
2461 // projection of P[i] to the plane defined by P[0] and upDir
2462 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2463 Standard_Real sqDist = P[0].SquareDistance( Pp );
2464 if ( sqDist < minDist ) {
2469 DUMPSO( "Set 4-th");
2470 swap ( 4, iMin, idNodes, P );
2472 // Set nodes of the top face in good order
2473 DUMPSO( "Sort top face");
2474 i = SortQuadNodes( theMesh, &idNodes[4] );
2477 gp_Pnt Ptmp = P[ i ];
2482 // Assure that direction of the top face normal is from the bottom face
2483 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2484 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2485 if ( Nt.Dot( upDir ) < 0 ) {
2486 DUMPSO( "Reverse top face");
2487 swap( 5, 7, idNodes, P );
2490 // DUMPSO( "OUTPUT: ========================================");
2491 // for ( i = 0; i < 8; i++ ) {
2492 // float *p = ugrid->GetPoint(idNodes[i]);
2493 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2499 //================================================================================
2501 * \brief Return nodes linked to the given one
2502 * \param theNode - the node
2503 * \param linkedNodes - the found nodes
2504 * \param type - the type of elements to check
2506 * Medium nodes are ignored
2508 //================================================================================
2510 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2511 TIDSortedElemSet & linkedNodes,
2512 SMDSAbs_ElementType type )
2514 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2515 while ( elemIt->more() )
2517 const SMDS_MeshElement* elem = elemIt->next();
2518 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2519 if ( elem->GetType() == SMDSAbs_Volume )
2521 SMDS_VolumeTool vol( elem );
2522 while ( nodeIt->more() ) {
2523 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2524 if ( theNode != n && vol.IsLinked( theNode, n ))
2525 linkedNodes.insert( n );
2530 for ( int i = 0; nodeIt->more(); ++i ) {
2531 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2532 if ( n == theNode ) {
2533 int iBefore = i - 1;
2535 if ( elem->IsQuadratic() ) {
2536 int nb = elem->NbNodes() / 2;
2537 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2538 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2540 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2541 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2548 //=======================================================================
2549 //function : laplacianSmooth
2550 //purpose : pulls theNode toward the center of surrounding nodes directly
2551 // connected to that node along an element edge
2552 //=======================================================================
2554 void laplacianSmooth(const SMDS_MeshNode* theNode,
2555 const Handle(Geom_Surface)& theSurface,
2556 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2558 // find surrounding nodes
2560 TIDSortedElemSet nodeSet;
2561 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2563 // compute new coodrs
2565 double coord[] = { 0., 0., 0. };
2566 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2567 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2568 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2569 if ( theSurface.IsNull() ) { // smooth in 3D
2570 coord[0] += node->X();
2571 coord[1] += node->Y();
2572 coord[2] += node->Z();
2574 else { // smooth in 2D
2575 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2576 gp_XY* uv = theUVMap[ node ];
2577 coord[0] += uv->X();
2578 coord[1] += uv->Y();
2581 int nbNodes = nodeSet.size();
2584 coord[0] /= nbNodes;
2585 coord[1] /= nbNodes;
2587 if ( !theSurface.IsNull() ) {
2588 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2589 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2590 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2596 coord[2] /= nbNodes;
2600 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2603 //=======================================================================
2604 //function : centroidalSmooth
2605 //purpose : pulls theNode toward the element-area-weighted centroid of the
2606 // surrounding elements
2607 //=======================================================================
2609 void centroidalSmooth(const SMDS_MeshNode* theNode,
2610 const Handle(Geom_Surface)& theSurface,
2611 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2613 gp_XYZ aNewXYZ(0.,0.,0.);
2614 SMESH::Controls::Area anAreaFunc;
2615 double totalArea = 0.;
2620 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2621 while ( elemIt->more() )
2623 const SMDS_MeshElement* elem = elemIt->next();
2626 gp_XYZ elemCenter(0.,0.,0.);
2627 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2628 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2629 int nn = elem->NbNodes();
2630 if(elem->IsQuadratic()) nn = nn/2;
2632 //while ( itN->more() ) {
2634 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2636 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2637 aNodePoints.push_back( aP );
2638 if ( !theSurface.IsNull() ) { // smooth in 2D
2639 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2640 gp_XY* uv = theUVMap[ aNode ];
2641 aP.SetCoord( uv->X(), uv->Y(), 0. );
2645 double elemArea = anAreaFunc.GetValue( aNodePoints );
2646 totalArea += elemArea;
2648 aNewXYZ += elemCenter * elemArea;
2650 aNewXYZ /= totalArea;
2651 if ( !theSurface.IsNull() ) {
2652 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2653 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2658 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2661 //=======================================================================
2662 //function : getClosestUV
2663 //purpose : return UV of closest projection
2664 //=======================================================================
2666 static bool getClosestUV (Extrema_GenExtPS& projector,
2667 const gp_Pnt& point,
2670 projector.Perform( point );
2671 if ( projector.IsDone() ) {
2672 double u, v, minVal = DBL_MAX;
2673 for ( int i = projector.NbExt(); i > 0; i-- )
2674 if ( projector.Value( i ) < minVal ) {
2675 minVal = projector.Value( i );
2676 projector.Point( i ).Parameter( u, v );
2678 result.SetCoord( u, v );
2684 //=======================================================================
2686 //purpose : Smooth theElements during theNbIterations or until a worst
2687 // element has aspect ratio <= theTgtAspectRatio.
2688 // Aspect Ratio varies in range [1.0, inf].
2689 // If theElements is empty, the whole mesh is smoothed.
2690 // theFixedNodes contains additionally fixed nodes. Nodes built
2691 // on edges and boundary nodes are always fixed.
2692 //=======================================================================
2694 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2695 set<const SMDS_MeshNode*> & theFixedNodes,
2696 const SmoothMethod theSmoothMethod,
2697 const int theNbIterations,
2698 double theTgtAspectRatio,
2701 myLastCreatedElems.Clear();
2702 myLastCreatedNodes.Clear();
2704 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2706 if ( theTgtAspectRatio < 1.0 )
2707 theTgtAspectRatio = 1.0;
2709 const double disttol = 1.e-16;
2711 SMESH::Controls::AspectRatio aQualityFunc;
2713 SMESHDS_Mesh* aMesh = GetMeshDS();
2715 if ( theElems.empty() ) {
2716 // add all faces to theElems
2717 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2718 while ( fIt->more() ) {
2719 const SMDS_MeshElement* face = fIt->next();
2720 theElems.insert( face );
2723 // get all face ids theElems are on
2724 set< int > faceIdSet;
2725 TIDSortedElemSet::iterator itElem;
2727 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2728 int fId = FindShape( *itElem );
2729 // check that corresponding submesh exists and a shape is face
2731 faceIdSet.find( fId ) == faceIdSet.end() &&
2732 aMesh->MeshElements( fId )) {
2733 TopoDS_Shape F = aMesh->IndexToShape( fId );
2734 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2735 faceIdSet.insert( fId );
2738 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2740 // ===============================================
2741 // smooth elements on each TopoDS_Face separately
2742 // ===============================================
2744 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2745 for ( ; fId != faceIdSet.rend(); ++fId ) {
2746 // get face surface and submesh
2747 Handle(Geom_Surface) surface;
2748 SMESHDS_SubMesh* faceSubMesh = 0;
2750 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2751 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2752 bool isUPeriodic = false, isVPeriodic = false;
2754 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2755 surface = BRep_Tool::Surface( face );
2756 faceSubMesh = aMesh->MeshElements( *fId );
2757 fToler2 = BRep_Tool::Tolerance( face );
2758 fToler2 *= fToler2 * 10.;
2759 isUPeriodic = surface->IsUPeriodic();
2761 vPeriod = surface->UPeriod();
2762 isVPeriodic = surface->IsVPeriodic();
2764 uPeriod = surface->VPeriod();
2765 surface->Bounds( u1, u2, v1, v2 );
2767 // ---------------------------------------------------------
2768 // for elements on a face, find movable and fixed nodes and
2769 // compute UV for them
2770 // ---------------------------------------------------------
2771 bool checkBoundaryNodes = false;
2772 bool isQuadratic = false;
2773 set<const SMDS_MeshNode*> setMovableNodes;
2774 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2775 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2776 list< const SMDS_MeshElement* > elemsOnFace;
2778 Extrema_GenExtPS projector;
2779 GeomAdaptor_Surface surfAdaptor;
2780 if ( !surface.IsNull() ) {
2781 surfAdaptor.Load( surface );
2782 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2784 int nbElemOnFace = 0;
2785 itElem = theElems.begin();
2786 // loop on not yet smoothed elements: look for elems on a face
2787 while ( itElem != theElems.end() ) {
2788 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2789 break; // all elements found
2791 const SMDS_MeshElement* elem = *itElem;
2792 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2793 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2797 elemsOnFace.push_back( elem );
2798 theElems.erase( itElem++ );
2802 isQuadratic = elem->IsQuadratic();
2804 // get movable nodes of elem
2805 const SMDS_MeshNode* node;
2806 SMDS_TypeOfPosition posType;
2807 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2808 int nn = 0, nbn = elem->NbNodes();
2809 if(elem->IsQuadratic())
2811 while ( nn++ < nbn ) {
2812 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2813 const SMDS_PositionPtr& pos = node->GetPosition();
2814 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2815 if (posType != SMDS_TOP_EDGE &&
2816 posType != SMDS_TOP_VERTEX &&
2817 theFixedNodes.find( node ) == theFixedNodes.end())
2819 // check if all faces around the node are on faceSubMesh
2820 // because a node on edge may be bound to face
2821 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2823 if ( faceSubMesh ) {
2824 while ( eIt->more() && all ) {
2825 const SMDS_MeshElement* e = eIt->next();
2826 all = faceSubMesh->Contains( e );
2830 setMovableNodes.insert( node );
2832 checkBoundaryNodes = true;
2834 if ( posType == SMDS_TOP_3DSPACE )
2835 checkBoundaryNodes = true;
2838 if ( surface.IsNull() )
2841 // get nodes to check UV
2842 list< const SMDS_MeshNode* > uvCheckNodes;
2843 itN = elem->nodesIterator();
2844 nn = 0; nbn = elem->NbNodes();
2845 if(elem->IsQuadratic())
2847 while ( nn++ < nbn ) {
2848 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2849 if ( uvMap.find( node ) == uvMap.end() )
2850 uvCheckNodes.push_back( node );
2851 // add nodes of elems sharing node
2852 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2853 // while ( eIt->more() ) {
2854 // const SMDS_MeshElement* e = eIt->next();
2855 // if ( e != elem ) {
2856 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2857 // while ( nIt->more() ) {
2858 // const SMDS_MeshNode* n =
2859 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2860 // if ( uvMap.find( n ) == uvMap.end() )
2861 // uvCheckNodes.push_back( n );
2867 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2868 for ( ; n != uvCheckNodes.end(); ++n ) {
2871 const SMDS_PositionPtr& pos = node->GetPosition();
2872 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2874 switch ( posType ) {
2875 case SMDS_TOP_FACE: {
2876 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
2877 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2880 case SMDS_TOP_EDGE: {
2881 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2882 Handle(Geom2d_Curve) pcurve;
2883 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2884 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2885 if ( !pcurve.IsNull() ) {
2886 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
2887 uv = pcurve->Value( u ).XY();
2891 case SMDS_TOP_VERTEX: {
2892 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2893 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2894 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2899 // check existing UV
2900 bool project = true;
2901 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2902 double dist1 = DBL_MAX, dist2 = 0;
2903 if ( posType != SMDS_TOP_3DSPACE ) {
2904 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2905 project = dist1 > fToler2;
2907 if ( project ) { // compute new UV
2909 if ( !getClosestUV( projector, pNode, newUV )) {
2910 MESSAGE("Node Projection Failed " << node);
2914 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2916 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2918 if ( posType != SMDS_TOP_3DSPACE )
2919 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2920 if ( dist2 < dist1 )
2924 // store UV in the map
2925 listUV.push_back( uv );
2926 uvMap.insert( make_pair( node, &listUV.back() ));
2928 } // loop on not yet smoothed elements
2930 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2931 checkBoundaryNodes = true;
2933 // fix nodes on mesh boundary
2935 if ( checkBoundaryNodes ) {
2936 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2937 map< NLink, int >::iterator link_nb;
2938 // put all elements links to linkNbMap
2939 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2940 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2941 const SMDS_MeshElement* elem = (*elemIt);
2942 int nbn = elem->NbNodes();
2943 if(elem->IsQuadratic())
2945 // loop on elem links: insert them in linkNbMap
2946 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2947 for ( int iN = 0; iN < nbn; ++iN ) {
2948 curNode = elem->GetNode( iN );
2950 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2951 else link = make_pair( prevNode , curNode );
2953 link_nb = linkNbMap.find( link );
2954 if ( link_nb == linkNbMap.end() )
2955 linkNbMap.insert( make_pair ( link, 1 ));
2960 // remove nodes that are in links encountered only once from setMovableNodes
2961 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2962 if ( link_nb->second == 1 ) {
2963 setMovableNodes.erase( link_nb->first.first );
2964 setMovableNodes.erase( link_nb->first.second );
2969 // -----------------------------------------------------
2970 // for nodes on seam edge, compute one more UV ( uvMap2 );
2971 // find movable nodes linked to nodes on seam and which
2972 // are to be smoothed using the second UV ( uvMap2 )
2973 // -----------------------------------------------------
2975 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2976 if ( !surface.IsNull() ) {
2977 TopExp_Explorer eExp( face, TopAbs_EDGE );
2978 for ( ; eExp.More(); eExp.Next() ) {
2979 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2980 if ( !BRep_Tool::IsClosed( edge, face ))
2982 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2983 if ( !sm ) continue;
2984 // find out which parameter varies for a node on seam
2987 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2988 if ( pcurve.IsNull() ) continue;
2989 uv1 = pcurve->Value( f );
2991 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2992 if ( pcurve.IsNull() ) continue;
2993 uv2 = pcurve->Value( f );
2994 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2996 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2997 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2999 // get nodes on seam and its vertices
3000 list< const SMDS_MeshNode* > seamNodes;
3001 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3002 while ( nSeamIt->more() ) {
3003 const SMDS_MeshNode* node = nSeamIt->next();
3004 if ( !isQuadratic || !IsMedium( node ))
3005 seamNodes.push_back( node );
3007 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3008 for ( ; vExp.More(); vExp.Next() ) {
3009 sm = aMesh->MeshElements( vExp.Current() );
3011 nSeamIt = sm->GetNodes();
3012 while ( nSeamIt->more() )
3013 seamNodes.push_back( nSeamIt->next() );
3016 // loop on nodes on seam
3017 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3018 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3019 const SMDS_MeshNode* nSeam = *noSeIt;
3020 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3021 if ( n_uv == uvMap.end() )
3024 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3025 // set the second UV
3026 listUV.push_back( *n_uv->second );
3027 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3028 if ( uvMap2.empty() )
3029 uvMap2 = uvMap; // copy the uvMap contents
3030 uvMap2[ nSeam ] = &listUV.back();
3032 // collect movable nodes linked to ones on seam in nodesNearSeam
3033 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3034 while ( eIt->more() ) {
3035 const SMDS_MeshElement* e = eIt->next();
3036 int nbUseMap1 = 0, nbUseMap2 = 0;
3037 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3038 int nn = 0, nbn = e->NbNodes();
3039 if(e->IsQuadratic()) nbn = nbn/2;
3040 while ( nn++ < nbn )
3042 const SMDS_MeshNode* n =
3043 static_cast<const SMDS_MeshNode*>( nIt->next() );
3045 setMovableNodes.find( n ) == setMovableNodes.end() )
3047 // add only nodes being closer to uv2 than to uv1
3048 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3049 0.5 * ( n->Y() + nSeam->Y() ),
3050 0.5 * ( n->Z() + nSeam->Z() ));
3052 getClosestUV( projector, pMid, uv );
3053 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3054 nodesNearSeam.insert( n );
3060 // for centroidalSmooth all element nodes must
3061 // be on one side of a seam
3062 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3063 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3065 while ( nn++ < nbn ) {
3066 const SMDS_MeshNode* n =
3067 static_cast<const SMDS_MeshNode*>( nIt->next() );
3068 setMovableNodes.erase( n );
3072 } // loop on nodes on seam
3073 } // loop on edge of a face
3074 } // if ( !face.IsNull() )
3076 if ( setMovableNodes.empty() ) {
3077 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3078 continue; // goto next face
3086 double maxRatio = -1., maxDisplacement = -1.;
3087 set<const SMDS_MeshNode*>::iterator nodeToMove;
3088 for ( it = 0; it < theNbIterations; it++ ) {
3089 maxDisplacement = 0.;
3090 nodeToMove = setMovableNodes.begin();
3091 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3092 const SMDS_MeshNode* node = (*nodeToMove);
3093 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3096 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3097 if ( theSmoothMethod == LAPLACIAN )
3098 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3100 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3102 // node displacement
3103 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3104 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3105 if ( aDispl > maxDisplacement )
3106 maxDisplacement = aDispl;
3108 // no node movement => exit
3109 //if ( maxDisplacement < 1.e-16 ) {
3110 if ( maxDisplacement < disttol ) {
3111 MESSAGE("-- no node movement --");
3115 // check elements quality
3117 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3118 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3119 const SMDS_MeshElement* elem = (*elemIt);
3120 if ( !elem || elem->GetType() != SMDSAbs_Face )
3122 SMESH::Controls::TSequenceOfXYZ aPoints;
3123 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3124 double aValue = aQualityFunc.GetValue( aPoints );
3125 if ( aValue > maxRatio )
3129 if ( maxRatio <= theTgtAspectRatio ) {
3130 MESSAGE("-- quality achived --");
3133 if (it+1 == theNbIterations) {
3134 MESSAGE("-- Iteration limit exceeded --");
3136 } // smoothing iterations
3138 MESSAGE(" Face id: " << *fId <<
3139 " Nb iterstions: " << it <<
3140 " Displacement: " << maxDisplacement <<
3141 " Aspect Ratio " << maxRatio);
3143 // ---------------------------------------
3144 // new nodes positions are computed,
3145 // record movement in DS and set new UV
3146 // ---------------------------------------
3147 nodeToMove = setMovableNodes.begin();
3148 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3149 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3150 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3151 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3152 if ( node_uv != uvMap.end() ) {
3153 gp_XY* uv = node_uv->second;
3155 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3159 // move medium nodes of quadratic elements
3162 SMESH_MesherHelper helper( *GetMesh() );
3163 if ( !face.IsNull() )
3164 helper.SetSubShape( face );
3165 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3166 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3167 const SMDS_QuadraticFaceOfNodes* QF =
3168 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3170 vector<const SMDS_MeshNode*> Ns;
3171 Ns.reserve(QF->NbNodes()+1);
3172 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3173 while ( anIter->more() )
3174 Ns.push_back( anIter->next() );
3175 Ns.push_back( Ns[0] );
3177 for(int i=0; i<QF->NbNodes(); i=i+2) {
3178 if ( !surface.IsNull() ) {
3179 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3180 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3181 gp_XY uv = ( uv1 + uv2 ) / 2.;
3182 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3183 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3186 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3187 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3188 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3190 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3191 fabs( Ns[i+1]->Y() - y ) > disttol ||
3192 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3193 // we have to move i+1 node
3194 aMesh->MoveNode( Ns[i+1], x, y, z );
3201 } // loop on face ids
3205 //=======================================================================
3206 //function : isReverse
3207 //purpose : Return true if normal of prevNodes is not co-directied with
3208 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3209 // iNotSame is where prevNodes and nextNodes are different
3210 //=======================================================================
3212 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3213 vector<const SMDS_MeshNode*> nextNodes,
3217 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3218 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3220 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3221 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3222 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3223 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3225 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3226 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3227 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3228 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3230 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3232 return (vA ^ vB) * vN < 0.0;
3235 //=======================================================================
3237 * \brief Create elements by sweeping an element
3238 * \param elem - element to sweep
3239 * \param newNodesItVec - nodes generated from each node of the element
3240 * \param newElems - generated elements
3241 * \param nbSteps - number of sweeping steps
3242 * \param srcElements - to append elem for each generated element
3244 //=======================================================================
3246 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3247 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3248 list<const SMDS_MeshElement*>& newElems,
3250 SMESH_SequenceOfElemPtr& srcElements)
3252 SMESHDS_Mesh* aMesh = GetMeshDS();
3254 // Loop on elem nodes:
3255 // find new nodes and detect same nodes indices
3256 int nbNodes = elem->NbNodes();
3257 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3258 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3259 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3260 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3262 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3263 vector<int> sames(nbNodes);
3264 vector<bool> issimple(nbNodes);
3266 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3267 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3268 const SMDS_MeshNode* node = nnIt->first;
3269 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3270 if ( listNewNodes.empty() ) {
3274 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3276 itNN[ iNode ] = listNewNodes.begin();
3277 prevNod[ iNode ] = node;
3278 nextNod[ iNode ] = listNewNodes.front();
3279 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3280 if ( prevNod[ iNode ] != nextNod [ iNode ])
3281 iNotSameNode = iNode;
3285 sames[nbSame++] = iNode;
3290 //cout<<" nbSame = "<<nbSame<<endl;
3291 if ( nbSame == nbNodes || nbSame > 2) {
3292 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3293 //INFOS( " Too many same nodes of element " << elem->GetID() );
3297 // if( elem->IsQuadratic() && nbSame>0 ) {
3298 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3302 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3303 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3305 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3306 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3307 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3311 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3312 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3313 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3314 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3316 // check element orientation
3318 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3319 //MESSAGE("Reversed elem " << elem );
3323 std::swap( iBeforeSame, iAfterSame );
3326 // make new elements
3327 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3329 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3330 if(issimple[iNode]) {
3331 nextNod[ iNode ] = *itNN[ iNode ];
3335 if( elem->GetType()==SMDSAbs_Node ) {
3336 // we have to use two nodes
3337 midlNod[ iNode ] = *itNN[ iNode ];
3339 nextNod[ iNode ] = *itNN[ iNode ];
3342 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3343 // we have to use each second node
3345 nextNod[ iNode ] = *itNN[ iNode ];
3349 // we have to use two nodes
3350 midlNod[ iNode ] = *itNN[ iNode ];
3352 nextNod[ iNode ] = *itNN[ iNode ];
3357 SMDS_MeshElement* aNewElem = 0;
3358 if(!elem->IsPoly()) {
3359 switch ( nbNodes ) {
3363 if ( nbSame == 0 ) {
3365 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3367 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3373 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3374 nextNod[ 1 ], nextNod[ 0 ] );
3376 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3377 nextNod[ iNotSameNode ] );
3381 case 3: { // TRIANGLE or quadratic edge
3382 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3384 if ( nbSame == 0 ) // --- pentahedron
3385 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3386 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3388 else if ( nbSame == 1 ) // --- pyramid
3389 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3390 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3391 nextNod[ iSameNode ]);
3393 else // 2 same nodes: --- tetrahedron
3394 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3395 nextNod[ iNotSameNode ]);
3397 else { // quadratic edge
3398 if(nbSame==0) { // quadratic quadrangle
3399 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3400 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3402 else if(nbSame==1) { // quadratic triangle
3404 return; // medium node on axis
3406 else if(sames[0]==0) {
3407 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3408 nextNod[2], midlNod[1], prevNod[2]);
3410 else { // sames[0]==1
3411 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3412 midlNod[0], nextNod[2], prevNod[2]);
3421 case 4: { // QUADRANGLE
3423 if ( nbSame == 0 ) // --- hexahedron
3424 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3425 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3427 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3428 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3429 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3430 nextNod[ iSameNode ]);
3431 newElems.push_back( aNewElem );
3432 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3433 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3434 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3436 else if ( nbSame == 2 ) { // pentahedron
3437 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3438 // iBeforeSame is same too
3439 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3440 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3441 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3443 // iAfterSame is same too
3444 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3445 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3446 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3450 case 6: { // quadratic triangle
3451 // create pentahedron with 15 nodes
3453 if(i0>0) { // reversed case
3454 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3455 nextNod[0], nextNod[2], nextNod[1],
3456 prevNod[5], prevNod[4], prevNod[3],
3457 nextNod[5], nextNod[4], nextNod[3],
3458 midlNod[0], midlNod[2], midlNod[1]);
3460 else { // not reversed case
3461 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3462 nextNod[0], nextNod[1], nextNod[2],
3463 prevNod[3], prevNod[4], prevNod[5],
3464 nextNod[3], nextNod[4], nextNod[5],
3465 midlNod[0], midlNod[1], midlNod[2]);
3468 else if(nbSame==1) {
3469 // 2d order pyramid of 13 nodes
3470 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3471 // int n12,int n23,int n34,int n41,
3472 // int n15,int n25,int n35,int n45, int ID);
3474 int n1,n4,n41,n15,n45;
3475 if(i0>0) { // reversed case
3476 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3477 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3483 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3484 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3489 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3490 nextNod[n4], prevNod[n4], prevNod[n5],
3491 midlNod[n1], nextNod[n41],
3492 midlNod[n4], prevNod[n41],
3493 prevNod[n15], nextNod[n15],
3494 nextNod[n45], prevNod[n45]);
3496 else if(nbSame==2) {
3497 // 2d order tetrahedron of 10 nodes
3498 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3499 // int n12,int n23,int n31,
3500 // int n14,int n24,int n34, int ID);
3501 int n1 = iNotSameNode;
3502 int n2,n3,n12,n23,n31;
3503 if(i0>0) { // reversed case
3504 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3505 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3511 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3512 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3517 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3518 prevNod[n12], prevNod[n23], prevNod[n31],
3519 midlNod[n1], nextNod[n12], nextNod[n31]);
3523 case 8: { // quadratic quadrangle
3525 // create hexahedron with 20 nodes
3526 if(i0>0) { // reversed case
3527 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3528 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3529 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3530 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3531 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3533 else { // not reversed case
3534 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3535 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3536 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3537 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3538 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3541 else if(nbSame==1) {
3542 // --- pyramid + pentahedron - can not be created since it is needed
3543 // additional middle node ot the center of face
3544 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3547 else if(nbSame==2) {
3548 // 2d order Pentahedron with 15 nodes
3549 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3550 // int n12,int n23,int n31,int n45,int n56,int n64,
3551 // int n14,int n25,int n36, int ID);
3553 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3554 // iBeforeSame is same too
3561 // iAfterSame is same too
3567 int n12,n45,n14,n25;
3568 if(i0>0) { //reversed case
3580 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3581 prevNod[n4], prevNod[n5], nextNod[n5],
3582 prevNod[n12], midlNod[n2], nextNod[n12],
3583 prevNod[n45], midlNod[n5], nextNod[n45],
3584 prevNod[n14], prevNod[n25], nextNod[n25]);
3589 // realized for extrusion only
3590 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3591 //vector<int> quantities (nbNodes + 2);
3593 //quantities[0] = nbNodes; // bottom of prism
3594 //for (int inode = 0; inode < nbNodes; inode++) {
3595 // polyedre_nodes[inode] = prevNod[inode];
3598 //quantities[1] = nbNodes; // top of prism
3599 //for (int inode = 0; inode < nbNodes; inode++) {
3600 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3603 //for (int iface = 0; iface < nbNodes; iface++) {
3604 // quantities[iface + 2] = 4;
3605 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3606 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3607 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3608 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3609 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3611 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3618 // realized for extrusion only
3619 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3620 vector<int> quantities (nbNodes + 2);
3622 quantities[0] = nbNodes; // bottom of prism
3623 for (int inode = 0; inode < nbNodes; inode++) {
3624 polyedre_nodes[inode] = prevNod[inode];
3627 quantities[1] = nbNodes; // top of prism
3628 for (int inode = 0; inode < nbNodes; inode++) {
3629 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3632 for (int iface = 0; iface < nbNodes; iface++) {
3633 quantities[iface + 2] = 4;
3634 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3635 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3636 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3637 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3638 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3640 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3644 newElems.push_back( aNewElem );
3645 myLastCreatedElems.Append(aNewElem);
3646 srcElements.Append( elem );
3649 // set new prev nodes
3650 for ( iNode = 0; iNode < nbNodes; iNode++ )
3651 prevNod[ iNode ] = nextNod[ iNode ];
3656 //=======================================================================
3658 * \brief Create 1D and 2D elements around swept elements
3659 * \param mapNewNodes - source nodes and ones generated from them
3660 * \param newElemsMap - source elements and ones generated from them
3661 * \param elemNewNodesMap - nodes generated from each node of each element
3662 * \param elemSet - all swept elements
3663 * \param nbSteps - number of sweeping steps
3664 * \param srcElements - to append elem for each generated element
3666 //=======================================================================
3668 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3669 TElemOfElemListMap & newElemsMap,
3670 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3671 TIDSortedElemSet& elemSet,
3673 SMESH_SequenceOfElemPtr& srcElements)
3675 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3676 SMESHDS_Mesh* aMesh = GetMeshDS();
3678 // Find nodes belonging to only one initial element - sweep them to get edges.
3680 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3681 for ( ; nList != mapNewNodes.end(); nList++ ) {
3682 const SMDS_MeshNode* node =
3683 static_cast<const SMDS_MeshNode*>( nList->first );
3684 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3685 int nbInitElems = 0;
3686 const SMDS_MeshElement* el = 0;
3687 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3688 while ( eIt->more() && nbInitElems < 2 ) {
3690 SMDSAbs_ElementType type = el->GetType();
3691 if ( type == SMDSAbs_Volume || type < highType ) continue;
3692 if ( type > highType ) {
3696 if ( elemSet.find(el) != elemSet.end() )
3699 if ( nbInitElems < 2 ) {
3700 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3701 if(!NotCreateEdge) {
3702 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3703 list<const SMDS_MeshElement*> newEdges;
3704 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3709 // Make a ceiling for each element ie an equal element of last new nodes.
3710 // Find free links of faces - make edges and sweep them into faces.
3712 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3713 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3714 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3715 const SMDS_MeshElement* elem = itElem->first;
3716 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3718 if ( elem->GetType() == SMDSAbs_Edge ) {
3719 // create a ceiling edge
3720 if (!elem->IsQuadratic()) {
3721 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3722 vecNewNodes[ 1 ]->second.back())) {
3723 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3724 vecNewNodes[ 1 ]->second.back()));
3725 srcElements.Append( myLastCreatedElems.Last() );
3729 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3730 vecNewNodes[ 1 ]->second.back(),
3731 vecNewNodes[ 2 ]->second.back())) {
3732 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3733 vecNewNodes[ 1 ]->second.back(),
3734 vecNewNodes[ 2 ]->second.back()));
3735 srcElements.Append( myLastCreatedElems.Last() );
3739 if ( elem->GetType() != SMDSAbs_Face )
3742 if(itElem->second.size()==0) continue;
3744 bool hasFreeLinks = false;
3746 TIDSortedElemSet avoidSet;
3747 avoidSet.insert( elem );
3749 set<const SMDS_MeshNode*> aFaceLastNodes;
3750 int iNode, nbNodes = vecNewNodes.size();
3751 if(!elem->IsQuadratic()) {
3752 // loop on the face nodes
3753 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3754 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3755 // look for free links of the face
3756 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3757 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3758 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3759 // check if a link is free
3760 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3761 hasFreeLinks = true;
3762 // make an edge and a ceiling for a new edge
3763 if ( !aMesh->FindEdge( n1, n2 )) {
3764 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3765 srcElements.Append( myLastCreatedElems.Last() );
3767 n1 = vecNewNodes[ iNode ]->second.back();
3768 n2 = vecNewNodes[ iNext ]->second.back();
3769 if ( !aMesh->FindEdge( n1, n2 )) {
3770 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3771 srcElements.Append( myLastCreatedElems.Last() );
3776 else { // elem is quadratic face
3777 int nbn = nbNodes/2;
3778 for ( iNode = 0; iNode < nbn; iNode++ ) {
3779 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3780 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3781 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3782 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3783 // check if a link is free
3784 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3785 hasFreeLinks = true;
3786 // make an edge and a ceiling for a new edge
3788 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3789 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3790 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3791 srcElements.Append( myLastCreatedElems.Last() );
3793 n1 = vecNewNodes[ iNode ]->second.back();
3794 n2 = vecNewNodes[ iNext ]->second.back();
3795 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3796 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3797 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3798 srcElements.Append( myLastCreatedElems.Last() );
3802 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3803 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3807 // sweep free links into faces
3809 if ( hasFreeLinks ) {
3810 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3811 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3813 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3814 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3815 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3816 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3818 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3819 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3821 while ( iVol++ < volNb ) v++;
3822 // find indices of free faces of a volume and their source edges
3823 list< int > freeInd;
3824 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3825 SMDS_VolumeTool vTool( *v );
3826 int iF, nbF = vTool.NbFaces();
3827 for ( iF = 0; iF < nbF; iF ++ ) {
3828 if (vTool.IsFreeFace( iF ) &&
3829 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3830 initNodeSet != faceNodeSet) // except an initial face
3832 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3834 freeInd.push_back( iF );
3835 // find source edge of a free face iF
3836 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3837 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3838 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3839 initNodeSet.begin(), initNodeSet.end(),
3840 commonNodes.begin());
3841 if ( (*v)->IsQuadratic() )
3842 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3844 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3846 if ( !srcEdges.back() )
3848 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3849 << iF << " of volume #" << vTool.ID() << endl;
3854 if ( freeInd.empty() )
3857 // create faces for all steps;
3858 // if such a face has been already created by sweep of edge,
3859 // assure that its orientation is OK
3860 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3862 vTool.SetExternalNormal();
3863 list< int >::iterator ind = freeInd.begin();
3864 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3865 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3867 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3868 int nbn = vTool.NbFaceNodes( *ind );
3870 case 3: { ///// triangle
3871 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3873 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3874 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3875 aMesh->ChangeElementNodes( f, nodes, nbn );
3878 case 4: { ///// quadrangle
3879 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3881 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3882 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3883 aMesh->ChangeElementNodes( f, nodes, nbn );
3887 if( (*v)->IsQuadratic() ) {
3888 if(nbn==6) { /////// quadratic triangle
3889 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3890 nodes[1], nodes[3], nodes[5] );
3892 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3893 nodes[1], nodes[3], nodes[5]));
3895 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3896 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3897 tmpnodes[0] = nodes[0];
3898 tmpnodes[1] = nodes[2];
3899 tmpnodes[2] = nodes[4];
3900 tmpnodes[3] = nodes[1];
3901 tmpnodes[4] = nodes[3];
3902 tmpnodes[5] = nodes[5];
3903 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3906 else { /////// quadratic quadrangle
3907 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3908 nodes[1], nodes[3], nodes[5], nodes[7] );
3910 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3911 nodes[1], nodes[3], nodes[5], nodes[7]));
3913 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3914 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3915 tmpnodes[0] = nodes[0];
3916 tmpnodes[1] = nodes[2];
3917 tmpnodes[2] = nodes[4];
3918 tmpnodes[3] = nodes[6];
3919 tmpnodes[4] = nodes[1];
3920 tmpnodes[5] = nodes[3];
3921 tmpnodes[6] = nodes[5];
3922 tmpnodes[7] = nodes[7];
3923 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3927 else { //////// polygon
3928 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3929 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3931 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3932 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3933 aMesh->ChangeElementNodes( f, nodes, nbn );
3936 while ( srcElements.Length() < myLastCreatedElems.Length() )
3937 srcElements.Append( *srcEdge );
3939 } // loop on free faces
3941 // go to the next volume
3943 while ( iVol++ < nbVolumesByStep ) v++;
3946 } // sweep free links into faces
3948 // Make a ceiling face with a normal external to a volume
3950 SMDS_VolumeTool lastVol( itElem->second.back() );
3952 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3954 lastVol.SetExternalNormal();
3955 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3956 int nbn = lastVol.NbFaceNodes( iF );
3959 if (!hasFreeLinks ||
3960 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3961 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3964 if (!hasFreeLinks ||
3965 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3966 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3969 if(itElem->second.back()->IsQuadratic()) {
3971 if (!hasFreeLinks ||
3972 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3973 nodes[1], nodes[3], nodes[5]) ) {
3974 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3975 nodes[1], nodes[3], nodes[5]));
3979 if (!hasFreeLinks ||
3980 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3981 nodes[1], nodes[3], nodes[5], nodes[7]) )
3982 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3983 nodes[1], nodes[3], nodes[5], nodes[7]));
3987 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3988 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3989 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3993 while ( srcElements.Length() < myLastCreatedElems.Length() )
3994 srcElements.Append( myLastCreatedElems.Last() );
3996 } // loop on swept elements
3999 //=======================================================================
4000 //function : RotationSweep
4002 //=======================================================================
4004 SMESH_MeshEditor::PGroupIDs
4005 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4006 const gp_Ax1& theAxis,
4007 const double theAngle,
4008 const int theNbSteps,
4009 const double theTol,
4010 const bool theMakeGroups,
4011 const bool theMakeWalls)
4013 myLastCreatedElems.Clear();
4014 myLastCreatedNodes.Clear();
4016 // source elements for each generated one
4017 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4019 MESSAGE( "RotationSweep()");
4021 aTrsf.SetRotation( theAxis, theAngle );
4023 aTrsf2.SetRotation( theAxis, theAngle/2. );
4025 gp_Lin aLine( theAxis );
4026 double aSqTol = theTol * theTol;
4028 SMESHDS_Mesh* aMesh = GetMeshDS();
4030 TNodeOfNodeListMap mapNewNodes;
4031 TElemOfVecOfNnlmiMap mapElemNewNodes;
4032 TElemOfElemListMap newElemsMap;
4035 TIDSortedElemSet::iterator itElem;
4036 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4037 const SMDS_MeshElement* elem = *itElem;
4038 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4040 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4041 newNodesItVec.reserve( elem->NbNodes() );
4043 // loop on elem nodes
4044 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4045 while ( itN->more() ) {
4046 // check if a node has been already sweeped
4047 const SMDS_MeshNode* node = cast2Node( itN->next() );
4049 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4051 aXYZ.Coord( coord[0], coord[1], coord[2] );
4052 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4054 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4055 if ( nIt == mapNewNodes.end() ) {
4056 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4057 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4060 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4062 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4063 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4064 const SMDS_MeshNode * newNode = node;
4065 for ( int i = 0; i < theNbSteps; i++ ) {
4067 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4069 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4070 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4071 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4072 myLastCreatedNodes.Append(newNode);
4073 srcNodes.Append( node );
4074 listNewNodes.push_back( newNode );
4075 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4076 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4079 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4081 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4082 myLastCreatedNodes.Append(newNode);
4083 srcNodes.Append( node );
4084 listNewNodes.push_back( newNode );
4087 listNewNodes.push_back( newNode );
4088 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4089 listNewNodes.push_back( newNode );
4096 // if current elem is quadratic and current node is not medium
4097 // we have to check - may be it is needed to insert additional nodes
4098 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4099 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4100 if(listNewNodes.size()==theNbSteps) {
4101 listNewNodes.clear();
4103 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4105 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4106 const SMDS_MeshNode * newNode = node;
4108 for(int i = 0; i<theNbSteps; i++) {
4109 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4110 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4111 cout<<" 3 AddNode: "<<newNode;
4112 myLastCreatedNodes.Append(newNode);
4113 listNewNodes.push_back( newNode );
4114 srcNodes.Append( node );
4115 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4116 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4117 cout<<" 4 AddNode: "<<newNode;
4118 myLastCreatedNodes.Append(newNode);
4119 srcNodes.Append( node );
4120 listNewNodes.push_back( newNode );
4124 listNewNodes.push_back( newNode );
4130 newNodesItVec.push_back( nIt );
4132 // make new elements
4133 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4137 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4139 PGroupIDs newGroupIDs;
4140 if ( theMakeGroups )
4141 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4147 //=======================================================================
4148 //function : CreateNode
4150 //=======================================================================
4151 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4154 const double tolnode,
4155 SMESH_SequenceOfNode& aNodes)
4157 myLastCreatedElems.Clear();
4158 myLastCreatedNodes.Clear();
4161 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4163 // try to search in sequence of existing nodes
4164 // if aNodes.Length()>0 we 'nave to use given sequence
4165 // else - use all nodes of mesh
4166 if(aNodes.Length()>0) {
4168 for(i=1; i<=aNodes.Length(); i++) {
4169 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4170 if(P1.Distance(P2)<tolnode)
4171 return aNodes.Value(i);
4175 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4176 while(itn->more()) {
4177 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4178 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4179 if(P1.Distance(P2)<tolnode)
4184 // create new node and return it
4185 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4186 myLastCreatedNodes.Append(NewNode);
4191 //=======================================================================
4192 //function : ExtrusionSweep
4194 //=======================================================================
4196 SMESH_MeshEditor::PGroupIDs
4197 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4198 const gp_Vec& theStep,
4199 const int theNbSteps,
4200 TElemOfElemListMap& newElemsMap,
4201 const bool theMakeGroups,
4203 const double theTolerance)
4205 ExtrusParam aParams;
4206 aParams.myDir = gp_Dir(theStep);
4207 aParams.myNodes.Clear();
4208 aParams.mySteps = new TColStd_HSequenceOfReal;
4210 for(i=1; i<=theNbSteps; i++)
4211 aParams.mySteps->Append(theStep.Magnitude());
4214 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4218 //=======================================================================
4219 //function : ExtrusionSweep
4221 //=======================================================================
4223 SMESH_MeshEditor::PGroupIDs
4224 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4225 ExtrusParam& theParams,
4226 TElemOfElemListMap& newElemsMap,
4227 const bool theMakeGroups,
4229 const double theTolerance)
4231 myLastCreatedElems.Clear();
4232 myLastCreatedNodes.Clear();
4234 // source elements for each generated one
4235 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4237 SMESHDS_Mesh* aMesh = GetMeshDS();
4239 int nbsteps = theParams.mySteps->Length();
4241 TNodeOfNodeListMap mapNewNodes;
4242 //TNodeOfNodeVecMap mapNewNodes;
4243 TElemOfVecOfNnlmiMap mapElemNewNodes;
4244 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4247 TIDSortedElemSet::iterator itElem;
4248 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4249 // check element type
4250 const SMDS_MeshElement* elem = *itElem;
4251 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4254 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4255 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4256 newNodesItVec.reserve( elem->NbNodes() );
4258 // loop on elem nodes
4259 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4260 while ( itN->more() )
4262 // check if a node has been already sweeped
4263 const SMDS_MeshNode* node = cast2Node( itN->next() );
4264 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4265 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4266 if ( nIt == mapNewNodes.end() ) {
4267 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4268 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4269 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4270 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4271 //vecNewNodes.reserve(nbsteps);
4274 double coord[] = { node->X(), node->Y(), node->Z() };
4275 //int nbsteps = theParams.mySteps->Length();
4276 for ( int i = 0; i < nbsteps; i++ ) {
4277 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4278 // create additional node
4279 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4280 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4281 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4282 if( theFlags & EXTRUSION_FLAG_SEW ) {
4283 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4284 theTolerance, theParams.myNodes);
4285 listNewNodes.push_back( newNode );
4288 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4289 myLastCreatedNodes.Append(newNode);
4290 srcNodes.Append( node );
4291 listNewNodes.push_back( newNode );
4294 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4295 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4296 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4297 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4298 if( theFlags & EXTRUSION_FLAG_SEW ) {
4299 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4300 theTolerance, theParams.myNodes);
4301 listNewNodes.push_back( newNode );
4302 //vecNewNodes[i]=newNode;
4305 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4306 myLastCreatedNodes.Append(newNode);
4307 srcNodes.Append( node );
4308 listNewNodes.push_back( newNode );
4309 //vecNewNodes[i]=newNode;
4314 // if current elem is quadratic and current node is not medium
4315 // we have to check - may be it is needed to insert additional nodes
4316 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4317 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4318 if(listNewNodes.size()==nbsteps) {
4319 listNewNodes.clear();
4320 double coord[] = { node->X(), node->Y(), node->Z() };
4321 for ( int i = 0; i < nbsteps; i++ ) {
4322 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4323 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4324 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4325 if( theFlags & EXTRUSION_FLAG_SEW ) {
4326 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4327 theTolerance, theParams.myNodes);
4328 listNewNodes.push_back( newNode );
4331 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4332 myLastCreatedNodes.Append(newNode);
4333 srcNodes.Append( node );
4334 listNewNodes.push_back( newNode );
4336 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4337 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4338 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4339 if( theFlags & EXTRUSION_FLAG_SEW ) {
4340 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4341 theTolerance, theParams.myNodes);
4342 listNewNodes.push_back( newNode );
4345 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4346 myLastCreatedNodes.Append(newNode);
4347 srcNodes.Append( node );
4348 listNewNodes.push_back( newNode );
4354 newNodesItVec.push_back( nIt );
4356 // make new elements
4357 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4360 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4361 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4363 PGroupIDs newGroupIDs;
4364 if ( theMakeGroups )
4365 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4371 //=======================================================================
4372 //class : SMESH_MeshEditor_PathPoint
4373 //purpose : auxiliary class
4374 //=======================================================================
4375 class SMESH_MeshEditor_PathPoint {
4377 SMESH_MeshEditor_PathPoint() {
4378 myPnt.SetCoord(99., 99., 99.);
4379 myTgt.SetCoord(1.,0.,0.);
4383 void SetPnt(const gp_Pnt& aP3D){
4386 void SetTangent(const gp_Dir& aTgt){
4389 void SetAngle(const double& aBeta){
4392 void SetParameter(const double& aPrm){
4395 const gp_Pnt& Pnt()const{
4398 const gp_Dir& Tangent()const{
4401 double Angle()const{
4404 double Parameter()const{
4416 //=======================================================================
4417 //function : ExtrusionAlongTrack
4419 //=======================================================================
4420 SMESH_MeshEditor::Extrusion_Error
4421 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4422 SMESH_subMesh* theTrack,
4423 const SMDS_MeshNode* theN1,
4424 const bool theHasAngles,
4425 list<double>& theAngles,
4426 const bool theLinearVariation,
4427 const bool theHasRefPoint,
4428 const gp_Pnt& theRefPoint,
4429 const bool theMakeGroups)
4431 myLastCreatedElems.Clear();
4432 myLastCreatedNodes.Clear();
4435 std::list<double> aPrms;
4436 TIDSortedElemSet::iterator itElem;
4439 TopoDS_Edge aTrackEdge;
4440 TopoDS_Vertex aV1, aV2;
4442 SMDS_ElemIteratorPtr aItE;
4443 SMDS_NodeIteratorPtr aItN;
4444 SMDSAbs_ElementType aTypeE;
4446 TNodeOfNodeListMap mapNewNodes;
4449 aNbE = theElements.size();
4452 return EXTR_NO_ELEMENTS;
4454 // 1.1 Track Pattern
4457 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4459 aItE = pSubMeshDS->GetElements();
4460 while ( aItE->more() ) {
4461 const SMDS_MeshElement* pE = aItE->next();
4462 aTypeE = pE->GetType();
4463 // Pattern must contain links only
4464 if ( aTypeE != SMDSAbs_Edge )
4465 return EXTR_PATH_NOT_EDGE;
4468 list<SMESH_MeshEditor_PathPoint> fullList;
4470 const TopoDS_Shape& aS = theTrack->GetSubShape();
4471 // Sub shape for the Pattern must be an Edge or Wire
4472 if( aS.ShapeType() == TopAbs_EDGE ) {
4473 aTrackEdge = TopoDS::Edge( aS );
4474 // the Edge must not be degenerated
4475 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4476 return EXTR_BAD_PATH_SHAPE;
4477 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4478 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4479 const SMDS_MeshNode* aN1 = aItN->next();
4480 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4481 const SMDS_MeshNode* aN2 = aItN->next();
4482 // starting node must be aN1 or aN2
4483 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4484 return EXTR_BAD_STARTING_NODE;
4485 aItN = pSubMeshDS->GetNodes();
4486 while ( aItN->more() ) {
4487 const SMDS_MeshNode* pNode = aItN->next();
4488 const SMDS_EdgePosition* pEPos =
4489 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4490 double aT = pEPos->GetUParameter();
4491 aPrms.push_back( aT );
4493 //Extrusion_Error err =
4494 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4496 else if( aS.ShapeType() == TopAbs_WIRE ) {
4497 list< SMESH_subMesh* > LSM;
4498 TopTools_SequenceOfShape Edges;
4499 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4500 while(itSM->more()) {
4501 SMESH_subMesh* SM = itSM->next();
4503 const TopoDS_Shape& aS = SM->GetSubShape();
4506 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4507 int startNid = theN1->GetID();
4508 TColStd_MapOfInteger UsedNums;
4509 int NbEdges = Edges.Length();
4511 for(; i<=NbEdges; i++) {
4513 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4514 for(; itLSM!=LSM.end(); itLSM++) {
4516 if(UsedNums.Contains(k)) continue;
4517 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4518 SMESH_subMesh* locTrack = *itLSM;
4519 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4520 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4521 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4522 const SMDS_MeshNode* aN1 = aItN->next();
4523 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4524 const SMDS_MeshNode* aN2 = aItN->next();
4525 // starting node must be aN1 or aN2
4526 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4527 // 2. Collect parameters on the track edge
4529 aItN = locMeshDS->GetNodes();
4530 while ( aItN->more() ) {
4531 const SMDS_MeshNode* pNode = aItN->next();
4532 const SMDS_EdgePosition* pEPos =
4533 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4534 double aT = pEPos->GetUParameter();
4535 aPrms.push_back( aT );
4537 list<SMESH_MeshEditor_PathPoint> LPP;
4538 //Extrusion_Error err =
4539 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4540 LLPPs.push_back(LPP);
4542 // update startN for search following egde
4543 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4544 else startNid = aN1->GetID();
4548 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4549 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4550 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4551 for(; itPP!=firstList.end(); itPP++) {
4552 fullList.push_back( *itPP );
4554 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4555 fullList.pop_back();
4557 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4558 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4559 itPP = currList.begin();
4560 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4561 gp_Dir D1 = PP1.Tangent();
4562 gp_Dir D2 = PP2.Tangent();
4563 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4564 (D1.Z()+D2.Z())/2 ) );
4565 PP1.SetTangent(Dnew);
4566 fullList.push_back(PP1);
4568 for(; itPP!=firstList.end(); itPP++) {
4569 fullList.push_back( *itPP );
4571 PP1 = fullList.back();
4572 fullList.pop_back();
4574 // if wire not closed
4575 fullList.push_back(PP1);
4579 return EXTR_BAD_PATH_SHAPE;
4582 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4583 theHasRefPoint, theRefPoint, theMakeGroups);
4587 //=======================================================================
4588 //function : ExtrusionAlongTrack
4590 //=======================================================================
4591 SMESH_MeshEditor::Extrusion_Error
4592 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4593 SMESH_Mesh* theTrack,
4594 const SMDS_MeshNode* theN1,
4595 const bool theHasAngles,
4596 list<double>& theAngles,
4597 const bool theLinearVariation,
4598 const bool theHasRefPoint,
4599 const gp_Pnt& theRefPoint,
4600 const bool theMakeGroups)
4602 myLastCreatedElems.Clear();
4603 myLastCreatedNodes.Clear();
4606 std::list<double> aPrms;
4607 TIDSortedElemSet::iterator itElem;
4610 TopoDS_Edge aTrackEdge;
4611 TopoDS_Vertex aV1, aV2;
4613 SMDS_ElemIteratorPtr aItE;
4614 SMDS_NodeIteratorPtr aItN;
4615 SMDSAbs_ElementType aTypeE;
4617 TNodeOfNodeListMap mapNewNodes;
4620 aNbE = theElements.size();
4623 return EXTR_NO_ELEMENTS;
4625 // 1.1 Track Pattern
4628 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4630 aItE = pMeshDS->elementsIterator();
4631 while ( aItE->more() ) {
4632 const SMDS_MeshElement* pE = aItE->next();
4633 aTypeE = pE->GetType();
4634 // Pattern must contain links only
4635 if ( aTypeE != SMDSAbs_Edge )
4636 return EXTR_PATH_NOT_EDGE;
4639 list<SMESH_MeshEditor_PathPoint> fullList;
4641 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4642 // Sub shape for the Pattern must be an Edge or Wire
4643 if( aS.ShapeType() == TopAbs_EDGE ) {
4644 aTrackEdge = TopoDS::Edge( aS );
4645 // the Edge must not be degenerated
4646 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4647 return EXTR_BAD_PATH_SHAPE;
4648 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4649 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4650 const SMDS_MeshNode* aN1 = aItN->next();
4651 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4652 const SMDS_MeshNode* aN2 = aItN->next();
4653 // starting node must be aN1 or aN2
4654 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4655 return EXTR_BAD_STARTING_NODE;
4656 aItN = pMeshDS->nodesIterator();
4657 while ( aItN->more() ) {
4658 const SMDS_MeshNode* pNode = aItN->next();
4659 if( pNode==aN1 || pNode==aN2 ) continue;
4660 const SMDS_EdgePosition* pEPos =
4661 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4662 double aT = pEPos->GetUParameter();
4663 aPrms.push_back( aT );
4665 //Extrusion_Error err =
4666 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4668 else if( aS.ShapeType() == TopAbs_WIRE ) {
4669 list< SMESH_subMesh* > LSM;
4670 TopTools_SequenceOfShape Edges;
4671 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4672 for(; eExp.More(); eExp.Next()) {
4673 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4674 if( BRep_Tool::Degenerated(E) ) continue;
4675 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4681 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4682 int startNid = theN1->GetID();
4683 TColStd_MapOfInteger UsedNums;
4684 int NbEdges = Edges.Length();
4686 for(; i<=NbEdges; i++) {
4688 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4689 for(; itLSM!=LSM.end(); itLSM++) {
4691 if(UsedNums.Contains(k)) continue;
4692 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4693 SMESH_subMesh* locTrack = *itLSM;
4694 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4695 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4696 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4697 const SMDS_MeshNode* aN1 = aItN->next();
4698 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4699 const SMDS_MeshNode* aN2 = aItN->next();
4700 // starting node must be aN1 or aN2
4701 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4702 // 2. Collect parameters on the track edge
4704 aItN = locMeshDS->GetNodes();
4705 while ( aItN->more() ) {
4706 const SMDS_MeshNode* pNode = aItN->next();
4707 const SMDS_EdgePosition* pEPos =
4708 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4709 double aT = pEPos->GetUParameter();
4710 aPrms.push_back( aT );
4712 list<SMESH_MeshEditor_PathPoint> LPP;
4713 //Extrusion_Error err =
4714 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4715 LLPPs.push_back(LPP);
4717 // update startN for search following egde
4718 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4719 else startNid = aN1->GetID();
4723 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4724 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4725 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4726 for(; itPP!=firstList.end(); itPP++) {
4727 fullList.push_back( *itPP );
4729 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4730 fullList.pop_back();
4732 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4733 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4734 itPP = currList.begin();
4735 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4736 gp_Pnt P1 = PP1.Pnt();
4737 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4738 gp_Pnt P2 = PP2.Pnt();
4739 gp_Dir D1 = PP1.Tangent();
4740 gp_Dir D2 = PP2.Tangent();
4741 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4742 (D1.Z()+D2.Z())/2 ) );
4743 PP1.SetTangent(Dnew);
4744 fullList.push_back(PP1);
4746 for(; itPP!=currList.end(); itPP++) {
4747 fullList.push_back( *itPP );
4749 PP1 = fullList.back();
4750 fullList.pop_back();
4752 // if wire not closed
4753 fullList.push_back(PP1);
4757 return EXTR_BAD_PATH_SHAPE;
4760 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4761 theHasRefPoint, theRefPoint, theMakeGroups);
4765 //=======================================================================
4766 //function : MakeEdgePathPoints
4767 //purpose : auxilary for ExtrusionAlongTrack
4768 //=======================================================================
4769 SMESH_MeshEditor::Extrusion_Error
4770 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4771 const TopoDS_Edge& aTrackEdge,
4773 list<SMESH_MeshEditor_PathPoint>& LPP)
4775 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4777 aTolVec2=aTolVec*aTolVec;
4779 TopoDS_Vertex aV1, aV2;
4780 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4781 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4782 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4783 // 2. Collect parameters on the track edge
4784 aPrms.push_front( aT1 );
4785 aPrms.push_back( aT2 );
4788 if( FirstIsStart ) {
4799 SMESH_MeshEditor_PathPoint aPP;
4800 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4801 std::list<double>::iterator aItD = aPrms.begin();
4802 for(; aItD != aPrms.end(); ++aItD) {
4806 aC3D->D1( aT, aP3D, aVec );
4807 aL2 = aVec.SquareMagnitude();
4808 if ( aL2 < aTolVec2 )
4809 return EXTR_CANT_GET_TANGENT;
4810 gp_Dir aTgt( aVec );
4812 aPP.SetTangent( aTgt );
4813 aPP.SetParameter( aT );
4820 //=======================================================================
4821 //function : MakeExtrElements
4822 //purpose : auxilary for ExtrusionAlongTrack
4823 //=======================================================================
4824 SMESH_MeshEditor::Extrusion_Error
4825 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4826 list<SMESH_MeshEditor_PathPoint>& fullList,
4827 const bool theHasAngles,
4828 list<double>& theAngles,
4829 const bool theLinearVariation,
4830 const bool theHasRefPoint,
4831 const gp_Pnt& theRefPoint,
4832 const bool theMakeGroups)
4834 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4835 int aNbTP = fullList.size();
4836 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4838 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4839 LinearAngleVariation(aNbTP-1, theAngles);
4841 vector<double> aAngles( aNbTP );
4843 for(; j<aNbTP; ++j) {
4846 if ( theHasAngles ) {
4848 std::list<double>::iterator aItD = theAngles.begin();
4849 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4851 aAngles[j] = anAngle;
4854 // fill vector of path points with angles
4855 //aPPs.resize(fullList.size());
4857 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4858 for(; itPP!=fullList.end(); itPP++) {
4860 SMESH_MeshEditor_PathPoint PP = *itPP;
4861 PP.SetAngle(aAngles[j]);
4865 TNodeOfNodeListMap mapNewNodes;
4866 TElemOfVecOfNnlmiMap mapElemNewNodes;
4867 TElemOfElemListMap newElemsMap;
4868 TIDSortedElemSet::iterator itElem;
4871 SMDSAbs_ElementType aTypeE;
4872 // source elements for each generated one
4873 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4875 // 3. Center of rotation aV0
4876 gp_Pnt aV0 = theRefPoint;
4878 if ( !theHasRefPoint ) {
4880 aGC.SetCoord( 0.,0.,0. );
4882 itElem = theElements.begin();
4883 for ( ; itElem != theElements.end(); itElem++ ) {
4884 const SMDS_MeshElement* elem = *itElem;
4886 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4887 while ( itN->more() ) {
4888 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4893 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4894 list<const SMDS_MeshNode*> aLNx;
4895 mapNewNodes[node] = aLNx;
4897 gp_XYZ aXYZ( aX, aY, aZ );
4905 } // if (!theHasRefPoint) {
4906 mapNewNodes.clear();
4908 // 4. Processing the elements
4909 SMESHDS_Mesh* aMesh = GetMeshDS();
4911 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4912 // check element type
4913 const SMDS_MeshElement* elem = *itElem;
4914 aTypeE = elem->GetType();
4915 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4918 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4919 newNodesItVec.reserve( elem->NbNodes() );
4921 // loop on elem nodes
4923 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4924 while ( itN->more() )
4927 // check if a node has been already processed
4928 const SMDS_MeshNode* node =
4929 static_cast<const SMDS_MeshNode*>( itN->next() );
4930 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4931 if ( nIt == mapNewNodes.end() ) {
4932 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4933 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4936 aX = node->X(); aY = node->Y(); aZ = node->Z();
4938 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4939 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4940 gp_Ax1 anAx1, anAxT1T0;
4941 gp_Dir aDT1x, aDT0x, aDT1T0;
4946 aPN0.SetCoord(aX, aY, aZ);
4948 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4950 aDT0x= aPP0.Tangent();
4951 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4953 for ( j = 1; j < aNbTP; ++j ) {
4954 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4956 aDT1x = aPP1.Tangent();
4957 aAngle1x = aPP1.Angle();
4959 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4961 gp_Vec aV01x( aP0x, aP1x );
4962 aTrsf.SetTranslation( aV01x );
4965 aV1x = aV0x.Transformed( aTrsf );
4966 aPN1 = aPN0.Transformed( aTrsf );
4968 // rotation 1 [ T1,T0 ]
4969 aAngleT1T0=-aDT1x.Angle( aDT0x );
4970 if (fabs(aAngleT1T0) > aTolAng) {
4972 anAxT1T0.SetLocation( aV1x );
4973 anAxT1T0.SetDirection( aDT1T0 );
4974 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4976 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4980 if ( theHasAngles ) {
4981 anAx1.SetLocation( aV1x );
4982 anAx1.SetDirection( aDT1x );
4983 aTrsfRot.SetRotation( anAx1, aAngle1x );
4985 aPN1 = aPN1.Transformed( aTrsfRot );
4989 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4990 // create additional node
4991 double x = ( aPN1.X() + aPN0.X() )/2.;
4992 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4993 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4994 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4995 myLastCreatedNodes.Append(newNode);
4996 srcNodes.Append( node );
4997 listNewNodes.push_back( newNode );
5002 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5003 myLastCreatedNodes.Append(newNode);
5004 srcNodes.Append( node );
5005 listNewNodes.push_back( newNode );
5015 // if current elem is quadratic and current node is not medium
5016 // we have to check - may be it is needed to insert additional nodes
5017 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5018 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5019 if(listNewNodes.size()==aNbTP-1) {
5020 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5021 gp_XYZ P(node->X(), node->Y(), node->Z());
5022 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5024 for(i=0; i<aNbTP-1; i++) {
5025 const SMDS_MeshNode* N = *it;
5026 double x = ( N->X() + P.X() )/2.;
5027 double y = ( N->Y() + P.Y() )/2.;
5028 double z = ( N->Z() + P.Z() )/2.;
5029 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5030 srcNodes.Append( node );
5031 myLastCreatedNodes.Append(newN);
5034 P = gp_XYZ(N->X(),N->Y(),N->Z());
5036 listNewNodes.clear();
5037 for(i=0; i<2*(aNbTP-1); i++) {
5038 listNewNodes.push_back(aNodes[i]);
5044 newNodesItVec.push_back( nIt );
5046 // make new elements
5047 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5048 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5049 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5052 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5054 if ( theMakeGroups )
5055 generateGroups( srcNodes, srcElems, "extruded");
5061 //=======================================================================
5062 //function : LinearAngleVariation
5063 //purpose : auxilary for ExtrusionAlongTrack
5064 //=======================================================================
5065 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5066 list<double>& Angles)
5068 int nbAngles = Angles.size();
5069 if( nbSteps > nbAngles ) {
5070 vector<double> theAngles(nbAngles);
5071 list<double>::iterator it = Angles.begin();
5073 for(; it!=Angles.end(); it++) {
5075 theAngles[i] = (*it);
5078 double rAn2St = double( nbAngles ) / double( nbSteps );
5079 double angPrev = 0, angle;
5080 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5081 double angCur = rAn2St * ( iSt+1 );
5082 double angCurFloor = floor( angCur );
5083 double angPrevFloor = floor( angPrev );
5084 if ( angPrevFloor == angCurFloor )
5085 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5087 int iP = int( angPrevFloor );
5088 double angPrevCeil = ceil(angPrev);
5089 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5091 int iC = int( angCurFloor );
5092 if ( iC < nbAngles )
5093 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5095 iP = int( angPrevCeil );
5097 angle += theAngles[ iC ];
5099 res.push_back(angle);
5104 for(; it!=res.end(); it++)
5105 Angles.push_back( *it );
5110 //=======================================================================
5111 //function : Transform
5113 //=======================================================================
5115 SMESH_MeshEditor::PGroupIDs
5116 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5117 const gp_Trsf& theTrsf,
5119 const bool theMakeGroups,
5120 SMESH_Mesh* theTargetMesh)
5122 myLastCreatedElems.Clear();
5123 myLastCreatedNodes.Clear();
5125 bool needReverse = false;
5126 string groupPostfix;
5127 switch ( theTrsf.Form() ) {
5132 groupPostfix = "mirrored";
5135 groupPostfix = "rotated";
5137 case gp_Translation:
5138 groupPostfix = "translated";
5141 groupPostfix = "scaled";
5144 needReverse = false;
5145 groupPostfix = "transformed";
5148 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5149 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5150 SMESHDS_Mesh* aMesh = GetMeshDS();
5153 // map old node to new one
5154 TNodeNodeMap nodeMap;
5156 // elements sharing moved nodes; those of them which have all
5157 // nodes mirrored but are not in theElems are to be reversed
5158 TIDSortedElemSet inverseElemSet;
5160 // source elements for each generated one
5161 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5164 TIDSortedElemSet::iterator itElem;
5165 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5166 const SMDS_MeshElement* elem = *itElem;
5170 // loop on elem nodes
5171 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5172 while ( itN->more() ) {
5174 // check if a node has been already transformed
5175 const SMDS_MeshNode* node = cast2Node( itN->next() );
5176 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5177 nodeMap.insert( make_pair ( node, node ));
5178 if ( !n2n_isnew.second )
5182 coord[0] = node->X();
5183 coord[1] = node->Y();
5184 coord[2] = node->Z();
5185 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5186 if ( theTargetMesh ) {
5187 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5188 n2n_isnew.first->second = newNode;
5189 myLastCreatedNodes.Append(newNode);
5190 srcNodes.Append( node );
5192 else if ( theCopy ) {
5193 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5194 n2n_isnew.first->second = newNode;
5195 myLastCreatedNodes.Append(newNode);
5196 srcNodes.Append( node );
5199 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5200 // node position on shape becomes invalid
5201 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5202 ( SMDS_SpacePosition::originSpacePosition() );
5205 // keep inverse elements
5206 if ( !theCopy && !theTargetMesh && needReverse ) {
5207 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5208 while ( invElemIt->more() ) {
5209 const SMDS_MeshElement* iel = invElemIt->next();
5210 inverseElemSet.insert( iel );
5216 // either create new elements or reverse mirrored ones
5217 if ( !theCopy && !needReverse && !theTargetMesh )
5220 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5221 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5222 theElems.insert( *invElemIt );
5224 // replicate or reverse elements
5227 REV_TETRA = 0, // = nbNodes - 4
5228 REV_PYRAMID = 1, // = nbNodes - 4
5229 REV_PENTA = 2, // = nbNodes - 4
5231 REV_HEXA = 4, // = nbNodes - 4
5235 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5236 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5237 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5238 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5239 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5240 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5243 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5245 const SMDS_MeshElement* elem = *itElem;
5246 if ( !elem || elem->GetType() == SMDSAbs_Node )
5249 int nbNodes = elem->NbNodes();
5250 int elemType = elem->GetType();
5252 if (elem->IsPoly()) {
5253 // Polygon or Polyhedral Volume
5254 switch ( elemType ) {
5257 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5259 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5260 while (itN->more()) {
5261 const SMDS_MeshNode* node =
5262 static_cast<const SMDS_MeshNode*>(itN->next());
5263 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5264 if (nodeMapIt == nodeMap.end())
5265 break; // not all nodes transformed
5267 // reverse mirrored faces and volumes
5268 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5270 poly_nodes[iNode] = (*nodeMapIt).second;
5274 if ( iNode != nbNodes )
5275 continue; // not all nodes transformed
5277 if ( theTargetMesh ) {
5278 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5279 srcElems.Append( elem );
5281 else if ( theCopy ) {
5282 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5283 srcElems.Append( elem );
5286 aMesh->ChangePolygonNodes(elem, poly_nodes);
5290 case SMDSAbs_Volume:
5292 // ATTENTION: Reversing is not yet done!!!
5293 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5294 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5296 MESSAGE("Warning: bad volumic element");
5300 vector<const SMDS_MeshNode*> poly_nodes;
5301 vector<int> quantities;
5303 bool allTransformed = true;
5304 int nbFaces = aPolyedre->NbFaces();
5305 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5306 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5307 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5308 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5309 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5310 if (nodeMapIt == nodeMap.end()) {
5311 allTransformed = false; // not all nodes transformed
5313 poly_nodes.push_back((*nodeMapIt).second);
5316 quantities.push_back(nbFaceNodes);
5318 if ( !allTransformed )
5319 continue; // not all nodes transformed
5321 if ( theTargetMesh ) {
5322 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5323 srcElems.Append( elem );
5325 else if ( theCopy ) {
5326 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5327 srcElems.Append( elem );
5330 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5340 int* i = index[ FORWARD ];
5341 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5342 if ( elemType == SMDSAbs_Face )
5343 i = index[ REV_FACE ];
5345 i = index[ nbNodes - 4 ];
5347 if(elem->IsQuadratic()) {
5348 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5351 if(nbNodes==3) { // quadratic edge
5352 static int anIds[] = {1,0,2};
5355 else if(nbNodes==6) { // quadratic triangle
5356 static int anIds[] = {0,2,1,5,4,3};
5359 else if(nbNodes==8) { // quadratic quadrangle
5360 static int anIds[] = {0,3,2,1,7,6,5,4};
5363 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5364 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5367 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5368 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5371 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5372 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5375 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5376 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5382 // find transformed nodes
5383 vector<const SMDS_MeshNode*> nodes(nbNodes);
5385 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5386 while ( itN->more() ) {
5387 const SMDS_MeshNode* node =
5388 static_cast<const SMDS_MeshNode*>( itN->next() );
5389 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5390 if ( nodeMapIt == nodeMap.end() )
5391 break; // not all nodes transformed
5392 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5394 if ( iNode != nbNodes )
5395 continue; // not all nodes transformed
5397 if ( theTargetMesh ) {
5398 if ( SMDS_MeshElement* copy =
5399 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5400 myLastCreatedElems.Append( copy );
5401 srcElems.Append( elem );
5404 else if ( theCopy ) {
5405 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5406 myLastCreatedElems.Append( copy );
5407 srcElems.Append( elem );
5411 // reverse element as it was reversed by transformation
5413 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5417 PGroupIDs newGroupIDs;
5419 if ( theMakeGroups && theCopy ||
5420 theMakeGroups && theTargetMesh )
5421 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5427 //=======================================================================
5430 //=======================================================================
5432 SMESH_MeshEditor::PGroupIDs
5433 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5434 const gp_Pnt& thePoint,
5435 const std::list<double>& theScaleFact,
5437 const bool theMakeGroups,
5438 SMESH_Mesh* theTargetMesh)
5440 myLastCreatedElems.Clear();
5441 myLastCreatedNodes.Clear();
5443 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5444 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5445 SMESHDS_Mesh* aMesh = GetMeshDS();
5447 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5448 std::list<double>::const_iterator itS = theScaleFact.begin();
5450 if(theScaleFact.size()==1) {
5454 if(theScaleFact.size()==2) {
5459 if(theScaleFact.size()>2) {
5466 // map old node to new one
5467 TNodeNodeMap nodeMap;
5469 // elements sharing moved nodes; those of them which have all
5470 // nodes mirrored but are not in theElems are to be reversed
5471 TIDSortedElemSet inverseElemSet;
5473 // source elements for each generated one
5474 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5477 TIDSortedElemSet::iterator itElem;
5478 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5479 const SMDS_MeshElement* elem = *itElem;
5483 // loop on elem nodes
5484 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5485 while ( itN->more() ) {
5487 // check if a node has been already transformed
5488 const SMDS_MeshNode* node = cast2Node( itN->next() );
5489 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5490 nodeMap.insert( make_pair ( node, node ));
5491 if ( !n2n_isnew.second )
5495 //coord[0] = node->X();
5496 //coord[1] = node->Y();
5497 //coord[2] = node->Z();
5498 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5499 double dx = (node->X() - thePoint.X()) * scaleX;
5500 double dy = (node->Y() - thePoint.Y()) * scaleY;
5501 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5502 if ( theTargetMesh ) {
5503 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5504 const SMDS_MeshNode * newNode =
5505 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5506 n2n_isnew.first->second = newNode;
5507 myLastCreatedNodes.Append(newNode);
5508 srcNodes.Append( node );
5510 else if ( theCopy ) {
5511 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5512 const SMDS_MeshNode * newNode =
5513 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5514 n2n_isnew.first->second = newNode;
5515 myLastCreatedNodes.Append(newNode);
5516 srcNodes.Append( node );
5519 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5520 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5521 // node position on shape becomes invalid
5522 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5523 ( SMDS_SpacePosition::originSpacePosition() );
5526 // keep inverse elements
5527 //if ( !theCopy && !theTargetMesh && needReverse ) {
5528 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5529 // while ( invElemIt->more() ) {
5530 // const SMDS_MeshElement* iel = invElemIt->next();
5531 // inverseElemSet.insert( iel );
5537 // either create new elements or reverse mirrored ones
5538 //if ( !theCopy && !needReverse && !theTargetMesh )
5539 if ( !theCopy && !theTargetMesh )
5542 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5543 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5544 theElems.insert( *invElemIt );
5546 // replicate or reverse elements
5549 REV_TETRA = 0, // = nbNodes - 4
5550 REV_PYRAMID = 1, // = nbNodes - 4
5551 REV_PENTA = 2, // = nbNodes - 4
5553 REV_HEXA = 4, // = nbNodes - 4
5557 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5558 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5559 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5560 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5561 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5562 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5565 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5567 const SMDS_MeshElement* elem = *itElem;
5568 if ( !elem || elem->GetType() == SMDSAbs_Node )
5571 int nbNodes = elem->NbNodes();
5572 int elemType = elem->GetType();
5574 if (elem->IsPoly()) {
5575 // Polygon or Polyhedral Volume
5576 switch ( elemType ) {
5579 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5581 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5582 while (itN->more()) {
5583 const SMDS_MeshNode* node =
5584 static_cast<const SMDS_MeshNode*>(itN->next());
5585 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5586 if (nodeMapIt == nodeMap.end())
5587 break; // not all nodes transformed
5588 //if (needReverse) {
5589 // // reverse mirrored faces and volumes
5590 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5592 poly_nodes[iNode] = (*nodeMapIt).second;
5596 if ( iNode != nbNodes )
5597 continue; // not all nodes transformed
5599 if ( theTargetMesh ) {
5600 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5601 srcElems.Append( elem );
5603 else if ( theCopy ) {
5604 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5605 srcElems.Append( elem );
5608 aMesh->ChangePolygonNodes(elem, poly_nodes);
5612 case SMDSAbs_Volume:
5614 // ATTENTION: Reversing is not yet done!!!
5615 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5616 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5618 MESSAGE("Warning: bad volumic element");
5622 vector<const SMDS_MeshNode*> poly_nodes;
5623 vector<int> quantities;
5625 bool allTransformed = true;
5626 int nbFaces = aPolyedre->NbFaces();
5627 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5628 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5629 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5630 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5631 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5632 if (nodeMapIt == nodeMap.end()) {
5633 allTransformed = false; // not all nodes transformed
5635 poly_nodes.push_back((*nodeMapIt).second);
5638 quantities.push_back(nbFaceNodes);
5640 if ( !allTransformed )
5641 continue; // not all nodes transformed
5643 if ( theTargetMesh ) {
5644 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5645 srcElems.Append( elem );
5647 else if ( theCopy ) {
5648 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5649 srcElems.Append( elem );
5652 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5662 int* i = index[ FORWARD ];
5663 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5664 // if ( elemType == SMDSAbs_Face )
5665 // i = index[ REV_FACE ];
5667 // i = index[ nbNodes - 4 ];
5669 if(elem->IsQuadratic()) {
5670 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5673 // if(nbNodes==3) { // quadratic edge
5674 // static int anIds[] = {1,0,2};
5677 // else if(nbNodes==6) { // quadratic triangle
5678 // static int anIds[] = {0,2,1,5,4,3};
5681 // else if(nbNodes==8) { // quadratic quadrangle
5682 // static int anIds[] = {0,3,2,1,7,6,5,4};
5685 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5686 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5689 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5690 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5693 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5694 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5697 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5698 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5704 // find transformed nodes
5705 vector<const SMDS_MeshNode*> nodes(nbNodes);
5707 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5708 while ( itN->more() ) {
5709 const SMDS_MeshNode* node =
5710 static_cast<const SMDS_MeshNode*>( itN->next() );
5711 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5712 if ( nodeMapIt == nodeMap.end() )
5713 break; // not all nodes transformed
5714 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5716 if ( iNode != nbNodes )
5717 continue; // not all nodes transformed
5719 if ( theTargetMesh ) {
5720 if ( SMDS_MeshElement* copy =
5721 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5722 myLastCreatedElems.Append( copy );
5723 srcElems.Append( elem );
5726 else if ( theCopy ) {
5727 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5728 myLastCreatedElems.Append( copy );
5729 srcElems.Append( elem );
5733 // reverse element as it was reversed by transformation
5735 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5739 PGroupIDs newGroupIDs;
5741 if ( theMakeGroups && theCopy ||
5742 theMakeGroups && theTargetMesh ) {
5743 string groupPostfix = "scaled";
5744 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5751 //=======================================================================
5753 * \brief Create groups of elements made during transformation
5754 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5755 * \param elemGens - elements making corresponding myLastCreatedElems
5756 * \param postfix - to append to names of new groups
5758 //=======================================================================
5760 SMESH_MeshEditor::PGroupIDs
5761 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5762 const SMESH_SequenceOfElemPtr& elemGens,
5763 const std::string& postfix,
5764 SMESH_Mesh* targetMesh)
5766 PGroupIDs newGroupIDs( new list<int> );
5767 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5769 // Sort existing groups by types and collect their names
5771 // to store an old group and a generated new one
5772 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5773 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5775 set< string > groupNames;
5777 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5778 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5779 while ( groupIt->more() ) {
5780 SMESH_Group * group = groupIt->next();
5781 if ( !group ) continue;
5782 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5783 if ( !groupDS || groupDS->IsEmpty() ) continue;
5784 groupNames.insert( group->GetName() );
5785 groupDS->SetStoreName( group->GetName() );
5786 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5791 // loop on nodes and elements
5792 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5794 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5795 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5796 if ( gens.Length() != elems.Length() )
5797 throw SALOME_Exception(LOCALIZED("invalid args"));
5799 // loop on created elements
5800 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5802 const SMDS_MeshElement* sourceElem = gens( iElem );
5803 if ( !sourceElem ) {
5804 MESSAGE("generateGroups(): NULL source element");
5807 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5808 if ( groupsOldNew.empty() ) {
5809 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5810 ++iElem; // skip all elements made by sourceElem
5813 // collect all elements made by sourceElem
5814 list< const SMDS_MeshElement* > resultElems;
5815 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5816 if ( resElem != sourceElem )
5817 resultElems.push_back( resElem );
5818 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5819 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5820 if ( resElem != sourceElem )
5821 resultElems.push_back( resElem );
5822 // do not generate element groups from node ones
5823 if ( sourceElem->GetType() == SMDSAbs_Node &&
5824 elems( iElem )->GetType() != SMDSAbs_Node )
5827 // add resultElems to groups made by ones the sourceElem belongs to
5828 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5829 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5831 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5832 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5834 SMDS_MeshGroup* & newGroup = gOldNew->second;
5835 if ( !newGroup )// create a new group
5838 string name = oldGroup->GetStoreName();
5839 if ( !targetMesh ) {
5843 while ( !groupNames.insert( name ).second ) // name exists
5849 TCollection_AsciiString nbStr(nb+1);
5850 name.resize( name.rfind('_')+1 );
5851 name += nbStr.ToCString();
5858 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5860 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5861 newGroup = & groupDS->SMDSGroup();
5862 newGroupIDs->push_back( id );
5865 // fill in a new group
5866 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5867 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5868 newGroup->Add( *resElemIt );
5871 } // loop on created elements
5872 }// loop on nodes and elements
5877 //================================================================================
5879 * \brief Return list of group of nodes close to each other within theTolerance
5880 * Search among theNodes or in the whole mesh if theNodes is empty using
5881 * an Octree algorithm
5883 //================================================================================
5885 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5886 const double theTolerance,
5887 TListOfListOfNodes & theGroupsOfNodes)
5889 myLastCreatedElems.Clear();
5890 myLastCreatedNodes.Clear();
5892 set<const SMDS_MeshNode*> nodes;
5893 if ( theNodes.empty() )
5894 { // get all nodes in the mesh
5895 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5896 while ( nIt->more() )
5897 nodes.insert( nodes.end(),nIt->next());
5902 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5906 //=======================================================================
5908 * \brief Implementation of search for the node closest to point
5910 //=======================================================================
5912 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5914 //---------------------------------------------------------------------
5916 * \brief Constructor
5918 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5920 myMesh = ( SMESHDS_Mesh* ) theMesh;
5922 set<const SMDS_MeshNode*> nodes;
5924 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5925 while ( nIt->more() )
5926 nodes.insert( nodes.end(), nIt->next() );
5928 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5930 // get max size of a leaf box
5931 SMESH_OctreeNode* tree = myOctreeNode;
5932 while ( !tree->isLeaf() )
5934 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5938 myHalfLeafSize = tree->maxSize() / 2.;
5941 //---------------------------------------------------------------------
5943 * \brief Move node and update myOctreeNode accordingly
5945 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5947 myOctreeNode->UpdateByMoveNode( node, toPnt );
5948 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5951 //---------------------------------------------------------------------
5953 * \brief Do it's job
5955 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5957 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5958 map<double, const SMDS_MeshNode*> dist2Nodes;
5959 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5960 if ( !dist2Nodes.empty() )
5961 return dist2Nodes.begin()->second;
5962 list<const SMDS_MeshNode*> nodes;
5963 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5965 double minSqDist = DBL_MAX;
5966 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5968 // sort leafs by their distance from thePnt
5969 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5970 TDistTreeMap treeMap;
5971 list< SMESH_OctreeNode* > treeList;
5972 list< SMESH_OctreeNode* >::iterator trIt;
5973 treeList.push_back( myOctreeNode );
5975 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5976 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5978 SMESH_OctreeNode* tree = *trIt;
5979 if ( !tree->isLeaf() ) // put children to the queue
5981 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5982 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5983 while ( cIt->more() )
5984 treeList.push_back( cIt->next() );
5986 else if ( tree->NbNodes() ) // put a tree to the treeMap
5988 const Bnd_B3d& box = tree->getBox();
5989 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5990 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5991 if ( !it_in.second ) // not unique distance to box center
5992 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5995 // find distance after which there is no sense to check tree's
5996 double sqLimit = DBL_MAX;
5997 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5998 if ( treeMap.size() > 5 ) {
5999 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6000 const Bnd_B3d& box = closestTree->getBox();
6001 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6002 sqLimit = limit * limit;
6004 // get all nodes from trees
6005 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6006 if ( sqDist_tree->first > sqLimit )
6008 SMESH_OctreeNode* tree = sqDist_tree->second;
6009 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6012 // find closest among nodes
6013 minSqDist = DBL_MAX;
6014 const SMDS_MeshNode* closestNode = 0;
6015 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6016 for ( ; nIt != nodes.end(); ++nIt ) {
6017 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6018 if ( minSqDist > sqDist ) {
6026 //---------------------------------------------------------------------
6030 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6032 //---------------------------------------------------------------------
6034 * \brief Return the node tree
6036 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6039 SMESH_OctreeNode* myOctreeNode;
6040 SMESHDS_Mesh* myMesh;
6041 double myHalfLeafSize; // max size of a leaf box
6044 //=======================================================================
6046 * \brief Return SMESH_NodeSearcher
6048 //=======================================================================
6050 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6052 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6055 // ========================================================================
6056 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6058 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6059 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6060 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6062 //=======================================================================
6064 * \brief Octal tree of bounding boxes of elements
6066 //=======================================================================
6068 class ElementBndBoxTree : public SMESH_Octree
6072 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6073 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6074 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6075 ~ElementBndBoxTree();
6078 ElementBndBoxTree() {}
6079 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6080 void buildChildrenData();
6081 Bnd_B3d* buildRootBox();
6083 //!< Bounding box of element
6084 struct ElementBox : public Bnd_B3d
6086 const SMDS_MeshElement* _element;
6087 int _refCount; // an ElementBox can be included in several tree branches
6088 ElementBox(const SMDS_MeshElement* elem);
6090 vector< ElementBox* > _elements;
6093 //================================================================================
6095 * \brief ElementBndBoxTree creation
6097 //================================================================================
6099 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6100 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6102 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6103 _elements.reserve( nbElems );
6105 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6106 while ( elemIt->more() )
6107 _elements.push_back( new ElementBox( elemIt->next() ));
6109 if ( _elements.size() > MaxNbElemsInLeaf )
6115 //================================================================================
6119 //================================================================================
6121 ElementBndBoxTree::~ElementBndBoxTree()
6123 for ( int i = 0; i < _elements.size(); ++i )
6124 if ( --_elements[i]->_refCount <= 0 )
6125 delete _elements[i];
6128 //================================================================================
6130 * \brief Return the maximal box
6132 //================================================================================
6134 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6136 Bnd_B3d* box = new Bnd_B3d;
6137 for ( int i = 0; i < _elements.size(); ++i )
6138 box->Add( *_elements[i] );
6142 //================================================================================
6144 * \brief Redistrubute element boxes among children
6146 //================================================================================
6148 void ElementBndBoxTree::buildChildrenData()
6150 for ( int i = 0; i < _elements.size(); ++i )
6152 for (int j = 0; j < 8; j++)
6154 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6156 _elements[i]->_refCount++;
6157 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6160 _elements[i]->_refCount--;
6164 for (int j = 0; j < 8; j++)
6166 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6167 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6168 child->myIsLeaf = true;
6170 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6171 child->_elements.resize( child->_elements.size() ); // compact
6175 //================================================================================
6177 * \brief Return elements which can include the point
6179 //================================================================================
6181 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6182 TIDSortedElemSet& foundElems)
6184 if ( level() && getBox().IsOut( point.XYZ() ))
6189 for ( int i = 0; i < _elements.size(); ++i )
6190 if ( !_elements[i]->IsOut( point.XYZ() ))
6191 foundElems.insert( _elements[i]->_element );
6195 for (int i = 0; i < 8; i++)
6196 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6200 //================================================================================
6202 * \brief Return elements which can be intersected by the line
6204 //================================================================================
6206 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6207 TIDSortedElemSet& foundElems)
6209 if ( level() && getBox().IsOut( line ))
6214 for ( int i = 0; i < _elements.size(); ++i )
6215 if ( !_elements[i]->IsOut( line ))
6216 foundElems.insert( _elements[i]->_element );
6220 for (int i = 0; i < 8; i++)
6221 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6225 //================================================================================
6227 * \brief Construct the element box
6229 //================================================================================
6231 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6235 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6236 while ( nIt->more() )
6237 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6238 Enlarge( NodeRadius );
6243 //=======================================================================
6245 * \brief Implementation of search for the elements by point and
6246 * of classification of point in 2D mesh
6248 //=======================================================================
6250 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6252 SMESHDS_Mesh* _mesh;
6253 ElementBndBoxTree* _ebbTree;
6254 SMESH_NodeSearcherImpl* _nodeSearcher;
6255 SMDSAbs_ElementType _elementType;
6257 bool _outerFacesFound;
6258 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6260 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6261 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6262 ~SMESH_ElementSearcherImpl()
6264 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6265 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6267 virtual int FindElementsByPoint(const gp_Pnt& point,
6268 SMDSAbs_ElementType type,
6269 vector< const SMDS_MeshElement* >& foundElements);
6270 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6272 double getTolerance();
6273 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6274 const double tolerance, double & param);
6275 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6276 bool isOuterBoundary(const SMDS_MeshElement* face) const
6278 return _outerFaces.empty() || _outerFaces.count(face);
6280 struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6282 const SMDS_MeshElement* _face;
6284 bool _coincides; //!< the line lays in face plane
6285 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6286 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6288 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6291 TIDSortedElemSet _faces;
6292 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6293 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6297 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6299 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6300 << ", _coincides="<<i._coincides << ")";
6303 //=======================================================================
6305 * \brief define tolerance for search
6307 //=======================================================================
6309 double SMESH_ElementSearcherImpl::getTolerance()
6311 if ( _tolerance < 0 )
6313 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6316 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6318 double boxSize = _nodeSearcher->getTree()->maxSize();
6319 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6321 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6323 double boxSize = _ebbTree->maxSize();
6324 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6326 if ( _tolerance == 0 )
6328 // define tolerance by size of a most complex element
6329 int complexType = SMDSAbs_Volume;
6330 while ( complexType > SMDSAbs_All &&
6331 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6333 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6336 if ( complexType == int( SMDSAbs_Node ))
6338 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6340 if ( meshInfo.NbNodes() > 2 )
6341 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6345 const SMDS_MeshElement* elem =
6346 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6347 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6348 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6349 while ( nodeIt->more() )
6351 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6352 elemSize = max( dist, elemSize );
6355 _tolerance = 1e-6 * elemSize;
6361 //================================================================================
6363 * \brief Find intersection of the line and an edge of face and return parameter on line
6365 //================================================================================
6367 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6368 const SMDS_MeshElement* face,
6375 GeomAPI_ExtremaCurveCurve anExtCC;
6376 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6378 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6379 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6381 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6382 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6383 anExtCC.Init( lineCurve, edge);
6384 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6386 Quantity_Parameter pl, pe;
6387 anExtCC.LowerDistanceParameters( pl, pe );
6389 if ( ++nbInts == 2 )
6393 if ( nbInts > 0 ) param /= nbInts;
6396 //================================================================================
6398 * \brief Find all faces belonging to the outer boundary of mesh
6400 //================================================================================
6402 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6404 if ( _outerFacesFound ) return;
6406 // Collect all outer faces by passing from one outer face to another via their links
6407 // and BTW find out if there are internal faces at all.
6409 // checked links and links where outer boundary meets internal one
6410 set< SMESH_TLink > visitedLinks, seamLinks;
6412 // links to treat with already visited faces sharing them
6413 list < TFaceLink > startLinks;
6415 // load startLinks with the first outerFace
6416 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6417 _outerFaces.insert( outerFace );
6419 TIDSortedElemSet emptySet;
6420 while ( !startLinks.empty() )
6422 const SMESH_TLink& link = startLinks.front()._link;
6423 TIDSortedElemSet& faces = startLinks.front()._faces;
6425 outerFace = *faces.begin();
6426 // find other faces sharing the link
6427 const SMDS_MeshElement* f;
6428 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6431 // select another outer face among the found
6432 const SMDS_MeshElement* outerFace2 = 0;
6433 if ( faces.size() == 2 )
6435 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6437 else if ( faces.size() > 2 )
6439 seamLinks.insert( link );
6441 // link direction within the outerFace
6442 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6443 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6444 int i1 = outerFace->GetNodeIndex( link.node1() );
6445 int i2 = outerFace->GetNodeIndex( link.node2() );
6446 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6447 if ( rev ) n1n2.Reverse();
6449 gp_XYZ ofNorm, fNorm;
6450 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6452 // direction from the link inside outerFace
6453 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6454 // sort all other faces by angle with the dirInOF
6455 map< double, const SMDS_MeshElement* > angle2Face;
6456 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6457 for ( ; face != faces.end(); ++face )
6459 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6461 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6462 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6463 if ( angle < 0 ) angle += 2*PI;
6464 angle2Face.insert( make_pair( angle, *face ));
6466 if ( !angle2Face.empty() )
6467 outerFace2 = angle2Face.begin()->second;
6470 // store the found outer face and add its links to continue seaching from
6473 _outerFaces.insert( outerFace );
6474 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6475 for ( int i = 0; i < nbNodes; ++i )
6477 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6478 if ( visitedLinks.insert( link2 ).second )
6479 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6482 startLinks.pop_front();
6484 _outerFacesFound = true;
6486 if ( !seamLinks.empty() )
6488 // There are internal boundaries touching the outher one,
6489 // find all faces of internal boundaries in order to find
6490 // faces of boundaries of holes, if any.
6495 _outerFaces.clear();
6499 //=======================================================================
6501 * \brief Find elements of given type where the given point is IN or ON.
6502 * Returns nb of found elements and elements them-selves.
6504 * 'ALL' type means elements of any type excluding nodes and 0D elements
6506 //=======================================================================
6508 int SMESH_ElementSearcherImpl::
6509 FindElementsByPoint(const gp_Pnt& point,
6510 SMDSAbs_ElementType type,
6511 vector< const SMDS_MeshElement* >& foundElements)
6513 foundElements.clear();
6515 double tolerance = getTolerance();
6517 // =================================================================================
6518 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6520 if ( !_nodeSearcher )
6521 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6523 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6524 if ( !closeNode ) return foundElements.size();
6526 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6527 return foundElements.size(); // to far from any node
6529 if ( type == SMDSAbs_Node )
6531 foundElements.push_back( closeNode );
6535 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6536 while ( elemIt->more() )
6537 foundElements.push_back( elemIt->next() );
6540 // =================================================================================
6541 else // elements more complex than 0D
6543 if ( !_ebbTree || _elementType != type )
6545 if ( _ebbTree ) delete _ebbTree;
6546 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6548 TIDSortedElemSet suspectElems;
6549 _ebbTree->getElementsNearPoint( point, suspectElems );
6550 TIDSortedElemSet::iterator elem = suspectElems.begin();
6551 for ( ; elem != suspectElems.end(); ++elem )
6552 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6553 foundElements.push_back( *elem );
6555 return foundElements.size();
6558 //================================================================================
6560 * \brief Classify the given point in the closed 2D mesh
6562 //================================================================================
6564 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6566 double tolerance = getTolerance();
6567 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6569 if ( _ebbTree ) delete _ebbTree;
6570 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6572 // Algo: analyse transition of a line starting at the point through mesh boundary;
6573 // try three lines parallel to axis of the coordinate system and perform rough
6574 // analysis. If solution is not clear perform thorough analysis.
6576 const int nbAxes = 3;
6577 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6578 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6579 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6580 multimap< int, int > nbInt2Axis; // to find the simplest case
6581 for ( int axis = 0; axis < nbAxes; ++axis )
6583 gp_Ax1 lineAxis( point, axisDir[axis]);
6584 gp_Lin line ( lineAxis );
6586 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6587 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6589 // Intersect faces with the line
6591 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6592 TIDSortedElemSet::iterator face = suspectFaces.begin();
6593 for ( ; face != suspectFaces.end(); ++face )
6597 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6598 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6600 // perform intersection
6601 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6602 if ( !intersection.IsDone() )
6604 if ( intersection.IsInQuadric() )
6606 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6608 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6610 gp_Pnt intersectionPoint = intersection.Point(1);
6611 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6612 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6615 // Analyse intersections roughly
6617 int nbInter = u2inters.size();
6621 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6622 if ( nbInter == 1 ) // not closed mesh
6623 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6625 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6628 if ( (f<0) == (l<0) )
6631 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6632 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6633 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6636 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6638 if ( _outerFacesFound ) break; // pass to thorough analysis
6640 } // three attempts - loop on CS axes
6642 // Analyse intersections thoroughly.
6643 // We make two loops maximum, on the first one we only exclude touching intersections,
6644 // on the second, if situation is still unclear, we gather and use information on
6645 // position of faces (internal or outer). If faces position is already gathered,
6646 // we make the second loop right away.
6648 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6650 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6651 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6653 int axis = nb_axis->second;
6654 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6656 gp_Ax1 lineAxis( point, axisDir[axis]);
6657 gp_Lin line ( lineAxis );
6659 // add tangent intersections to u2inters
6661 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6662 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6663 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6664 u2inters.insert(make_pair( param, *tgtInt ));
6665 tangentInters[ axis ].clear();
6667 // Count intersections before and after the point excluding touching ones.
6668 // If hasPositionInfo we count intersections of outer boundary only
6670 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6671 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6672 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6673 bool ok = ! u_int1->second._coincides;
6674 while ( ok && u_int1 != u2inters.end() )
6676 double u = u_int1->first;
6677 bool touchingInt = false;
6678 if ( ++u_int2 != u2inters.end() )
6680 // skip intersections at the same point (if the line passes through edge or node)
6682 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6688 // skip tangent intersections
6690 const SMDS_MeshElement* prevFace = u_int1->second._face;
6691 while ( ok && u_int2->second._coincides )
6693 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6699 ok = ( u_int2 != u2inters.end() );
6704 // skip intersections at the same point after tangent intersections
6707 double u2 = u_int2->first;
6709 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6715 // decide if we skipped a touching intersection
6716 if ( nbSamePnt + nbTgt > 0 )
6718 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6719 map< double, TInters >::iterator u_int = u_int1;
6720 for ( ; u_int != u_int2; ++u_int )
6722 if ( u_int->second._coincides ) continue;
6723 double dot = u_int->second._faceNorm * line.Direction();
6724 if ( dot > maxDot ) maxDot = dot;
6725 if ( dot < minDot ) minDot = dot;
6727 touchingInt = ( minDot*maxDot < 0 );
6732 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6743 u_int1 = u_int2; // to next intersection
6745 } // loop on intersections with one line
6749 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6752 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6755 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6756 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6758 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6761 if ( (f<0) == (l<0) )
6764 if ( hasPositionInfo )
6765 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6767 } // loop on intersections of the tree lines - thorough analysis
6769 if ( !hasPositionInfo )
6771 // gather info on faces position - is face in the outer boundary or not
6772 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6773 findOuterBoundary( u2inters.begin()->second._face );
6776 } // two attempts - with and w/o faces position info in the mesh
6778 return TopAbs_UNKNOWN;
6781 //=======================================================================
6783 * \brief Return SMESH_ElementSearcher
6785 //=======================================================================
6787 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6789 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6792 //=======================================================================
6794 * \brief Return true if the point is IN or ON of the element
6796 //=======================================================================
6798 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6800 if ( element->GetType() == SMDSAbs_Volume)
6802 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6805 // get ordered nodes
6807 vector< gp_XYZ > xyz;
6809 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6810 if ( element->IsQuadratic() )
6811 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6812 nodeIt = f->interlacedNodesElemIterator();
6813 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6814 nodeIt = e->interlacedNodesElemIterator();
6816 while ( nodeIt->more() )
6817 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6819 int i, nbNodes = element->NbNodes();
6821 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6823 // compute face normal
6824 gp_Vec faceNorm(0,0,0);
6825 xyz.push_back( xyz.front() );
6826 for ( i = 0; i < nbNodes; ++i )
6828 gp_Vec edge1( xyz[i+1], xyz[i]);
6829 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6830 faceNorm += edge1 ^ edge2;
6832 double normSize = faceNorm.Magnitude();
6833 if ( normSize <= tol )
6835 // degenerated face: point is out if it is out of all face edges
6836 for ( i = 0; i < nbNodes; ++i )
6838 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6839 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6840 SMDS_LinearEdge edge( &n1, &n2 );
6841 if ( !isOut( &edge, point, tol ))
6846 faceNorm /= normSize;
6848 // check if the point lays on face plane
6849 gp_Vec n2p( xyz[0], point );
6850 if ( fabs( n2p * faceNorm ) > tol )
6851 return true; // not on face plane
6853 // check if point is out of face boundary:
6854 // define it by closest transition of a ray point->infinity through face boundary
6855 // on the face plane.
6856 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6857 // to find intersections of the ray with the boundary.
6859 gp_Vec plnNorm = ray ^ faceNorm;
6860 normSize = plnNorm.Magnitude();
6861 if ( normSize <= tol ) return false; // point coincides with the first node
6862 plnNorm /= normSize;
6863 // for each node of the face, compute its signed distance to the plane
6864 vector<double> dist( nbNodes + 1);
6865 for ( i = 0; i < nbNodes; ++i )
6867 gp_Vec n2p( xyz[i], point );
6868 dist[i] = n2p * plnNorm;
6870 dist.back() = dist.front();
6871 // find the closest intersection
6873 double rClosest, distClosest = 1e100;;
6875 for ( i = 0; i < nbNodes; ++i )
6878 if ( fabs( dist[i]) < tol )
6880 else if ( fabs( dist[i+1]) < tol )
6882 else if ( dist[i] * dist[i+1] < 0 )
6883 r = dist[i] / ( dist[i] - dist[i+1] );
6885 continue; // no intersection
6886 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6887 gp_Vec p2int ( point, pInt);
6888 if ( p2int * ray > -tol ) // right half-space
6890 double intDist = p2int.SquareMagnitude();
6891 if ( intDist < distClosest )
6896 distClosest = intDist;
6901 return true; // no intesections - out
6903 // analyse transition
6904 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6905 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6906 gp_Vec p2int ( point, pClosest );
6907 bool out = (edgeNorm * p2int) < -tol;
6908 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6911 // ray pass through a face node; analyze transition through an adjacent edge
6912 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6913 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6914 gp_Vec edgeAdjacent( p1, p2 );
6915 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6916 bool out2 = (edgeNorm2 * p2int) < -tol;
6918 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6919 return covexCorner ? (out || out2) : (out && out2);
6921 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6923 // point is out of edge if it is NOT ON any straight part of edge
6924 // (we consider quadratic edge as being composed of two straight parts)
6925 for ( i = 1; i < nbNodes; ++i )
6927 gp_Vec edge( xyz[i-1], xyz[i]);
6928 gp_Vec n1p ( xyz[i-1], point);
6929 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6932 gp_Vec n2p( xyz[i], point );
6933 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6935 return false; // point is ON this part
6939 // Node or 0D element -------------------------------------------------------------------------
6941 gp_Vec n2p ( xyz[0], point );
6942 return n2p.Magnitude() <= tol;
6947 //=======================================================================
6948 //function : SimplifyFace
6950 //=======================================================================
6951 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6952 vector<const SMDS_MeshNode *>& poly_nodes,
6953 vector<int>& quantities) const
6955 int nbNodes = faceNodes.size();
6960 set<const SMDS_MeshNode*> nodeSet;
6962 // get simple seq of nodes
6963 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6964 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6965 int iSimple = 0, nbUnique = 0;
6967 simpleNodes[iSimple++] = faceNodes[0];
6969 for (int iCur = 1; iCur < nbNodes; iCur++) {
6970 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6971 simpleNodes[iSimple++] = faceNodes[iCur];
6972 if (nodeSet.insert( faceNodes[iCur] ).second)
6976 int nbSimple = iSimple;
6977 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6987 bool foundLoop = (nbSimple > nbUnique);
6990 set<const SMDS_MeshNode*> loopSet;
6991 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6992 const SMDS_MeshNode* n = simpleNodes[iSimple];
6993 if (!loopSet.insert( n ).second) {
6997 int iC = 0, curLast = iSimple;
6998 for (; iC < curLast; iC++) {
6999 if (simpleNodes[iC] == n) break;
7001 int loopLen = curLast - iC;
7003 // create sub-element
7005 quantities.push_back(loopLen);
7006 for (; iC < curLast; iC++) {
7007 poly_nodes.push_back(simpleNodes[iC]);
7010 // shift the rest nodes (place from the first loop position)
7011 for (iC = curLast + 1; iC < nbSimple; iC++) {
7012 simpleNodes[iC - loopLen] = simpleNodes[iC];
7014 nbSimple -= loopLen;
7017 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7018 } // while (foundLoop)
7022 quantities.push_back(iSimple);
7023 for (int i = 0; i < iSimple; i++)
7024 poly_nodes.push_back(simpleNodes[i]);
7030 //=======================================================================
7031 //function : MergeNodes
7032 //purpose : In each group, the cdr of nodes are substituted by the first one
7034 //=======================================================================
7036 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7038 myLastCreatedElems.Clear();
7039 myLastCreatedNodes.Clear();
7041 SMESHDS_Mesh* aMesh = GetMeshDS();
7043 TNodeNodeMap nodeNodeMap; // node to replace - new node
7044 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7045 list< int > rmElemIds, rmNodeIds;
7047 // Fill nodeNodeMap and elems
7049 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7050 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7051 list<const SMDS_MeshNode*>& nodes = *grIt;
7052 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7053 const SMDS_MeshNode* nToKeep = *nIt;
7054 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7055 const SMDS_MeshNode* nToRemove = *nIt;
7056 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7057 if ( nToRemove != nToKeep ) {
7058 rmNodeIds.push_back( nToRemove->GetID() );
7059 AddToSameGroups( nToKeep, nToRemove, aMesh );
7062 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7063 while ( invElemIt->more() ) {
7064 const SMDS_MeshElement* elem = invElemIt->next();
7069 // Change element nodes or remove an element
7071 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7072 for ( ; eIt != elems.end(); eIt++ ) {
7073 const SMDS_MeshElement* elem = *eIt;
7074 int nbNodes = elem->NbNodes();
7075 int aShapeId = FindShape( elem );
7077 set<const SMDS_MeshNode*> nodeSet;
7078 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7079 int iUnique = 0, iCur = 0, nbRepl = 0;
7080 vector<int> iRepl( nbNodes );
7082 // get new seq of nodes
7083 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7084 while ( itN->more() ) {
7085 const SMDS_MeshNode* n =
7086 static_cast<const SMDS_MeshNode*>( itN->next() );
7088 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7089 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7091 // BUG 0020185: begin
7093 bool stopRecur = false;
7094 set<const SMDS_MeshNode*> nodesRecur;
7095 nodesRecur.insert(n);
7096 while (!stopRecur) {
7097 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7098 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7099 n = (*nnIt_i).second;
7100 if (!nodesRecur.insert(n).second) {
7101 // error: recursive dependancy
7110 iRepl[ nbRepl++ ] = iCur;
7112 curNodes[ iCur ] = n;
7113 bool isUnique = nodeSet.insert( n ).second;
7115 uniqueNodes[ iUnique++ ] = n;
7119 // Analyse element topology after replacement
7122 int nbUniqueNodes = nodeSet.size();
7123 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7124 // Polygons and Polyhedral volumes
7125 if (elem->IsPoly()) {
7127 if (elem->GetType() == SMDSAbs_Face) {
7129 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7131 for (; inode < nbNodes; inode++) {
7132 face_nodes[inode] = curNodes[inode];
7135 vector<const SMDS_MeshNode *> polygons_nodes;
7136 vector<int> quantities;
7137 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7141 for (int iface = 0; iface < nbNew - 1; iface++) {
7142 int nbNodes = quantities[iface];
7143 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7144 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7145 poly_nodes[ii] = polygons_nodes[inode];
7147 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7148 myLastCreatedElems.Append(newElem);
7150 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7152 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7155 rmElemIds.push_back(elem->GetID());
7159 else if (elem->GetType() == SMDSAbs_Volume) {
7160 // Polyhedral volume
7161 if (nbUniqueNodes < 4) {
7162 rmElemIds.push_back(elem->GetID());
7165 // each face has to be analized in order to check volume validity
7166 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7167 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7169 int nbFaces = aPolyedre->NbFaces();
7171 vector<const SMDS_MeshNode *> poly_nodes;
7172 vector<int> quantities;
7174 for (int iface = 1; iface <= nbFaces; iface++) {
7175 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7176 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7178 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7179 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7180 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7181 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7182 faceNode = (*nnIt).second;
7184 faceNodes[inode - 1] = faceNode;
7187 SimplifyFace(faceNodes, poly_nodes, quantities);
7190 if (quantities.size() > 3) {
7191 // to be done: remove coincident faces
7194 if (quantities.size() > 3)
7195 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7197 rmElemIds.push_back(elem->GetID());
7201 rmElemIds.push_back(elem->GetID());
7212 switch ( nbNodes ) {
7213 case 2: ///////////////////////////////////// EDGE
7214 isOk = false; break;
7215 case 3: ///////////////////////////////////// TRIANGLE
7216 isOk = false; break;
7218 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7220 else { //////////////////////////////////// QUADRANGLE
7221 if ( nbUniqueNodes < 3 )
7223 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7224 isOk = false; // opposite nodes stick
7227 case 6: ///////////////////////////////////// PENTAHEDRON
7228 if ( nbUniqueNodes == 4 ) {
7229 // ---------------------------------> tetrahedron
7231 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7232 // all top nodes stick: reverse a bottom
7233 uniqueNodes[ 0 ] = curNodes [ 1 ];
7234 uniqueNodes[ 1 ] = curNodes [ 0 ];
7236 else if (nbRepl == 3 &&
7237 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7238 // all bottom nodes stick: set a top before
7239 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7240 uniqueNodes[ 0 ] = curNodes [ 3 ];
7241 uniqueNodes[ 1 ] = curNodes [ 4 ];
7242 uniqueNodes[ 2 ] = curNodes [ 5 ];
7244 else if (nbRepl == 4 &&
7245 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7246 // a lateral face turns into a line: reverse a bottom
7247 uniqueNodes[ 0 ] = curNodes [ 1 ];
7248 uniqueNodes[ 1 ] = curNodes [ 0 ];
7253 else if ( nbUniqueNodes == 5 ) {
7254 // PENTAHEDRON --------------------> 2 tetrahedrons
7255 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7256 // a bottom node sticks with a linked top one
7258 SMDS_MeshElement* newElem =
7259 aMesh->AddVolume(curNodes[ 3 ],
7262 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7263 myLastCreatedElems.Append(newElem);
7265 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7266 // 2. : reverse a bottom
7267 uniqueNodes[ 0 ] = curNodes [ 1 ];
7268 uniqueNodes[ 1 ] = curNodes [ 0 ];
7278 if(elem->IsQuadratic()) { // Quadratic quadrangle
7291 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7292 uniqueNodes[0] = curNodes[0];
7293 uniqueNodes[1] = curNodes[2];
7294 uniqueNodes[2] = curNodes[3];
7295 uniqueNodes[3] = curNodes[5];
7296 uniqueNodes[4] = curNodes[6];
7297 uniqueNodes[5] = curNodes[7];
7300 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7301 uniqueNodes[0] = curNodes[0];
7302 uniqueNodes[1] = curNodes[1];
7303 uniqueNodes[2] = curNodes[2];
7304 uniqueNodes[3] = curNodes[4];
7305 uniqueNodes[4] = curNodes[5];
7306 uniqueNodes[5] = curNodes[6];
7309 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7310 uniqueNodes[0] = curNodes[1];
7311 uniqueNodes[1] = curNodes[2];
7312 uniqueNodes[2] = curNodes[3];
7313 uniqueNodes[3] = curNodes[5];
7314 uniqueNodes[4] = curNodes[6];
7315 uniqueNodes[5] = curNodes[0];
7318 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7319 uniqueNodes[0] = curNodes[0];
7320 uniqueNodes[1] = curNodes[1];
7321 uniqueNodes[2] = curNodes[3];
7322 uniqueNodes[3] = curNodes[4];
7323 uniqueNodes[4] = curNodes[6];
7324 uniqueNodes[5] = curNodes[7];
7327 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7328 uniqueNodes[0] = curNodes[0];
7329 uniqueNodes[1] = curNodes[2];
7330 uniqueNodes[2] = curNodes[3];
7331 uniqueNodes[3] = curNodes[1];
7332 uniqueNodes[4] = curNodes[6];
7333 uniqueNodes[5] = curNodes[7];
7336 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7337 uniqueNodes[0] = curNodes[0];
7338 uniqueNodes[1] = curNodes[1];
7339 uniqueNodes[2] = curNodes[2];
7340 uniqueNodes[3] = curNodes[4];
7341 uniqueNodes[4] = curNodes[5];
7342 uniqueNodes[5] = curNodes[7];
7345 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7346 uniqueNodes[0] = curNodes[0];
7347 uniqueNodes[1] = curNodes[1];
7348 uniqueNodes[2] = curNodes[3];
7349 uniqueNodes[3] = curNodes[4];
7350 uniqueNodes[4] = curNodes[2];
7351 uniqueNodes[5] = curNodes[7];
7354 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7355 uniqueNodes[0] = curNodes[0];
7356 uniqueNodes[1] = curNodes[1];
7357 uniqueNodes[2] = curNodes[2];
7358 uniqueNodes[3] = curNodes[4];
7359 uniqueNodes[4] = curNodes[5];
7360 uniqueNodes[5] = curNodes[3];
7366 //////////////////////////////////// HEXAHEDRON
7368 SMDS_VolumeTool hexa (elem);
7369 hexa.SetExternalNormal();
7370 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7371 //////////////////////// ---> tetrahedron
7372 for ( int iFace = 0; iFace < 6; iFace++ ) {
7373 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7374 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7375 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7376 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7377 // one face turns into a point ...
7378 int iOppFace = hexa.GetOppFaceIndex( iFace );
7379 ind = hexa.GetFaceNodesIndices( iOppFace );
7381 iUnique = 2; // reverse a tetrahedron bottom
7382 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7383 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7385 else if ( iUnique >= 0 )
7386 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7388 if ( nbStick == 1 ) {
7389 // ... and the opposite one - into a triangle.
7391 ind = hexa.GetFaceNodesIndices( iFace );
7392 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7399 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7400 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7401 for ( int iFace = 0; iFace < 6; iFace++ ) {
7402 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7403 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7404 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7405 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7406 // one face turns into a point ...
7407 int iOppFace = hexa.GetOppFaceIndex( iFace );
7408 ind = hexa.GetFaceNodesIndices( iOppFace );
7410 iUnique = 2; // reverse a tetrahedron 1 bottom
7411 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7412 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7414 else if ( iUnique >= 0 )
7415 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7417 if ( nbStick == 0 ) {
7418 // ... and the opposite one is a quadrangle
7420 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7421 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7424 SMDS_MeshElement* newElem =
7425 aMesh->AddVolume(curNodes[ind[ 0 ]],
7428 curNodes[indTop[ 0 ]]);
7429 myLastCreatedElems.Append(newElem);
7431 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7438 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7439 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7440 // find indices of quad and tri faces
7441 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7442 for ( iFace = 0; iFace < 6; iFace++ ) {
7443 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7445 for ( iCur = 0; iCur < 4; iCur++ )
7446 nodeSet.insert( curNodes[ind[ iCur ]] );
7447 nbUniqueNodes = nodeSet.size();
7448 if ( nbUniqueNodes == 3 )
7449 iTriFace[ nbTri++ ] = iFace;
7450 else if ( nbUniqueNodes == 4 )
7451 iQuadFace[ nbQuad++ ] = iFace;
7453 if (nbQuad == 2 && nbTri == 4 &&
7454 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7455 // 2 opposite quadrangles stuck with a diagonal;
7456 // sample groups of merged indices: (0-4)(2-6)
7457 // --------------------------------------------> 2 tetrahedrons
7458 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7459 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7460 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7461 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7462 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7463 // stuck with 0-2 diagonal
7471 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7472 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7473 // stuck with 1-3 diagonal
7485 uniqueNodes[ 0 ] = curNodes [ i0 ];
7486 uniqueNodes[ 1 ] = curNodes [ i1d ];
7487 uniqueNodes[ 2 ] = curNodes [ i3d ];
7488 uniqueNodes[ 3 ] = curNodes [ i0t ];
7491 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7495 myLastCreatedElems.Append(newElem);
7497 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7500 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7501 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7502 // --------------------------------------------> prism
7503 // find 2 opposite triangles
7505 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7506 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7507 // find indices of kept and replaced nodes
7508 // and fill unique nodes of 2 opposite triangles
7509 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7510 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7511 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7512 // fill unique nodes
7515 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7516 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7517 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7519 // iCur of a linked node of the opposite face (make normals co-directed):
7520 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7521 // check that correspondent corners of triangles are linked
7522 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7525 uniqueNodes[ iUnique ] = n;
7526 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7535 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7541 } // switch ( nbNodes )
7543 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7546 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7547 // Change nodes of polyedre
7548 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7549 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7551 int nbFaces = aPolyedre->NbFaces();
7553 vector<const SMDS_MeshNode *> poly_nodes;
7554 vector<int> quantities (nbFaces);
7556 for (int iface = 1; iface <= nbFaces; iface++) {
7557 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7558 quantities[iface - 1] = nbFaceNodes;
7560 for (inode = 1; inode <= nbFaceNodes; inode++) {
7561 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7563 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7564 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7565 curNode = (*nnIt).second;
7567 poly_nodes.push_back(curNode);
7570 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7574 // Change regular element or polygon
7575 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7579 // Remove invalid regular element or invalid polygon
7580 rmElemIds.push_back( elem->GetID() );
7583 } // loop on elements
7585 // Remove equal nodes and bad elements
7587 Remove( rmNodeIds, true );
7588 Remove( rmElemIds, false );
7593 // ========================================================
7594 // class : SortableElement
7595 // purpose : allow sorting elements basing on their nodes
7596 // ========================================================
7597 class SortableElement : public set <const SMDS_MeshElement*>
7601 SortableElement( const SMDS_MeshElement* theElem )
7604 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7605 while ( nodeIt->more() )
7606 this->insert( nodeIt->next() );
7609 const SMDS_MeshElement* Get() const
7612 void Set(const SMDS_MeshElement* e) const
7617 mutable const SMDS_MeshElement* myElem;
7620 //=======================================================================
7621 //function : FindEqualElements
7622 //purpose : Return list of group of elements built on the same nodes.
7623 // Search among theElements or in the whole mesh if theElements is empty
7624 //=======================================================================
7625 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7626 TListOfListOfElementsID & theGroupsOfElementsID)
7628 myLastCreatedElems.Clear();
7629 myLastCreatedNodes.Clear();
7631 typedef set<const SMDS_MeshElement*> TElemsSet;
7632 typedef map< SortableElement, int > TMapOfNodeSet;
7633 typedef list<int> TGroupOfElems;
7636 if ( theElements.empty() )
7637 { // get all elements in the mesh
7638 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7639 while ( eIt->more() )
7640 elems.insert( elems.end(), eIt->next());
7643 elems = theElements;
7645 vector< TGroupOfElems > arrayOfGroups;
7646 TGroupOfElems groupOfElems;
7647 TMapOfNodeSet mapOfNodeSet;
7649 TElemsSet::iterator elemIt = elems.begin();
7650 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7651 const SMDS_MeshElement* curElem = *elemIt;
7652 SortableElement SE(curElem);
7655 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7656 if( !(pp.second) ) {
7657 TMapOfNodeSet::iterator& itSE = pp.first;
7658 ind = (*itSE).second;
7659 arrayOfGroups[ind].push_back(curElem->GetID());
7662 groupOfElems.clear();
7663 groupOfElems.push_back(curElem->GetID());
7664 arrayOfGroups.push_back(groupOfElems);
7669 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7670 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7671 groupOfElems = *groupIt;
7672 if ( groupOfElems.size() > 1 ) {
7673 groupOfElems.sort();
7674 theGroupsOfElementsID.push_back(groupOfElems);
7679 //=======================================================================
7680 //function : MergeElements
7681 //purpose : In each given group, substitute all elements by the first one.
7682 //=======================================================================
7684 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7686 myLastCreatedElems.Clear();
7687 myLastCreatedNodes.Clear();
7689 typedef list<int> TListOfIDs;
7690 TListOfIDs rmElemIds; // IDs of elems to remove
7692 SMESHDS_Mesh* aMesh = GetMeshDS();
7694 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7695 while ( groupsIt != theGroupsOfElementsID.end() ) {
7696 TListOfIDs& aGroupOfElemID = *groupsIt;
7697 aGroupOfElemID.sort();
7698 int elemIDToKeep = aGroupOfElemID.front();
7699 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7700 aGroupOfElemID.pop_front();
7701 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7702 while ( idIt != aGroupOfElemID.end() ) {
7703 int elemIDToRemove = *idIt;
7704 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7705 // add the kept element in groups of removed one (PAL15188)
7706 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7707 rmElemIds.push_back( elemIDToRemove );
7713 Remove( rmElemIds, false );
7716 //=======================================================================
7717 //function : MergeEqualElements
7718 //purpose : Remove all but one of elements built on the same nodes.
7719 //=======================================================================
7721 void SMESH_MeshEditor::MergeEqualElements()
7723 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7724 to merge equal elements in the whole mesh */
7725 TListOfListOfElementsID aGroupsOfElementsID;
7726 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7727 MergeElements(aGroupsOfElementsID);
7730 //=======================================================================
7731 //function : FindFaceInSet
7732 //purpose : Return a face having linked nodes n1 and n2 and which is
7733 // - not in avoidSet,
7734 // - in elemSet provided that !elemSet.empty()
7735 // i1 and i2 optionally returns indices of n1 and n2
7736 //=======================================================================
7738 const SMDS_MeshElement*
7739 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7740 const SMDS_MeshNode* n2,
7741 const TIDSortedElemSet& elemSet,
7742 const TIDSortedElemSet& avoidSet,
7748 const SMDS_MeshElement* face = 0;
7750 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7751 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7753 const SMDS_MeshElement* elem = invElemIt->next();
7754 if (avoidSet.count( elem ))
7756 if ( !elemSet.empty() && !elemSet.count( elem ))
7759 i1 = elem->GetNodeIndex( n1 );
7760 // find a n2 linked to n1
7761 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7762 for ( int di = -1; di < 2 && !face; di += 2 )
7764 i2 = (i1+di+nbN) % nbN;
7765 if ( elem->GetNode( i2 ) == n2 )
7768 if ( !face && elem->IsQuadratic())
7770 // analysis for quadratic elements using all nodes
7771 const SMDS_QuadraticFaceOfNodes* F =
7772 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7773 // use special nodes iterator
7774 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7775 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7776 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7778 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7779 if ( n1 == prevN && n2 == n )
7783 else if ( n2 == prevN && n1 == n )
7785 face = elem; swap( i1, i2 );
7791 if ( n1ind ) *n1ind = i1;
7792 if ( n2ind ) *n2ind = i2;
7796 //=======================================================================
7797 //function : findAdjacentFace
7799 //=======================================================================
7801 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7802 const SMDS_MeshNode* n2,
7803 const SMDS_MeshElement* elem)
7805 TIDSortedElemSet elemSet, avoidSet;
7807 avoidSet.insert ( elem );
7808 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7811 //=======================================================================
7812 //function : FindFreeBorder
7814 //=======================================================================
7816 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7818 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7819 const SMDS_MeshNode* theSecondNode,
7820 const SMDS_MeshNode* theLastNode,
7821 list< const SMDS_MeshNode* > & theNodes,
7822 list< const SMDS_MeshElement* >& theFaces)
7824 if ( !theFirstNode || !theSecondNode )
7826 // find border face between theFirstNode and theSecondNode
7827 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7831 theFaces.push_back( curElem );
7832 theNodes.push_back( theFirstNode );
7833 theNodes.push_back( theSecondNode );
7835 //vector<const SMDS_MeshNode*> nodes;
7836 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7837 TIDSortedElemSet foundElems;
7838 bool needTheLast = ( theLastNode != 0 );
7840 while ( nStart != theLastNode ) {
7841 if ( nStart == theFirstNode )
7842 return !needTheLast;
7844 // find all free border faces sharing form nStart
7846 list< const SMDS_MeshElement* > curElemList;
7847 list< const SMDS_MeshNode* > nStartList;
7848 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7849 while ( invElemIt->more() ) {
7850 const SMDS_MeshElement* e = invElemIt->next();
7851 if ( e == curElem || foundElems.insert( e ).second ) {
7853 int iNode = 0, nbNodes = e->NbNodes();
7854 //const SMDS_MeshNode* nodes[nbNodes+1];
7855 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7857 if(e->IsQuadratic()) {
7858 const SMDS_QuadraticFaceOfNodes* F =
7859 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7860 // use special nodes iterator
7861 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7862 while( anIter->more() ) {
7863 nodes[ iNode++ ] = anIter->next();
7867 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7868 while ( nIt->more() )
7869 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7871 nodes[ iNode ] = nodes[ 0 ];
7873 for ( iNode = 0; iNode < nbNodes; iNode++ )
7874 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7875 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7876 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7878 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7879 curElemList.push_back( e );
7883 // analyse the found
7885 int nbNewBorders = curElemList.size();
7886 if ( nbNewBorders == 0 ) {
7887 // no free border furthermore
7888 return !needTheLast;
7890 else if ( nbNewBorders == 1 ) {
7891 // one more element found
7893 nStart = nStartList.front();
7894 curElem = curElemList.front();
7895 theFaces.push_back( curElem );
7896 theNodes.push_back( nStart );
7899 // several continuations found
7900 list< const SMDS_MeshElement* >::iterator curElemIt;
7901 list< const SMDS_MeshNode* >::iterator nStartIt;
7902 // check if one of them reached the last node
7903 if ( needTheLast ) {
7904 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7905 curElemIt!= curElemList.end();
7906 curElemIt++, nStartIt++ )
7907 if ( *nStartIt == theLastNode ) {
7908 theFaces.push_back( *curElemIt );
7909 theNodes.push_back( *nStartIt );
7913 // find the best free border by the continuations
7914 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7915 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7916 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7917 curElemIt!= curElemList.end();
7918 curElemIt++, nStartIt++ )
7920 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7921 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7922 // find one more free border
7923 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7927 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7928 // choice: clear a worse one
7929 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7930 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7931 contNodes[ iWorse ].clear();
7932 contFaces[ iWorse ].clear();
7935 if ( contNodes[0].empty() && contNodes[1].empty() )
7938 // append the best free border
7939 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7940 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7941 theNodes.pop_back(); // remove nIgnore
7942 theNodes.pop_back(); // remove nStart
7943 theFaces.pop_back(); // remove curElem
7944 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7945 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7946 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7947 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7950 } // several continuations found
7951 } // while ( nStart != theLastNode )
7956 //=======================================================================
7957 //function : CheckFreeBorderNodes
7958 //purpose : Return true if the tree nodes are on a free border
7959 //=======================================================================
7961 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7962 const SMDS_MeshNode* theNode2,
7963 const SMDS_MeshNode* theNode3)
7965 list< const SMDS_MeshNode* > nodes;
7966 list< const SMDS_MeshElement* > faces;
7967 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7970 //=======================================================================
7971 //function : SewFreeBorder
7973 //=======================================================================
7975 SMESH_MeshEditor::Sew_Error
7976 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7977 const SMDS_MeshNode* theBordSecondNode,
7978 const SMDS_MeshNode* theBordLastNode,
7979 const SMDS_MeshNode* theSideFirstNode,
7980 const SMDS_MeshNode* theSideSecondNode,
7981 const SMDS_MeshNode* theSideThirdNode,
7982 const bool theSideIsFreeBorder,
7983 const bool toCreatePolygons,
7984 const bool toCreatePolyedrs)
7986 myLastCreatedElems.Clear();
7987 myLastCreatedNodes.Clear();
7989 MESSAGE("::SewFreeBorder()");
7990 Sew_Error aResult = SEW_OK;
7992 // ====================================
7993 // find side nodes and elements
7994 // ====================================
7996 list< const SMDS_MeshNode* > nSide[ 2 ];
7997 list< const SMDS_MeshElement* > eSide[ 2 ];
7998 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7999 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8003 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8004 nSide[0], eSide[0])) {
8005 MESSAGE(" Free Border 1 not found " );
8006 aResult = SEW_BORDER1_NOT_FOUND;
8008 if (theSideIsFreeBorder) {
8011 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8012 nSide[1], eSide[1])) {
8013 MESSAGE(" Free Border 2 not found " );
8014 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8017 if ( aResult != SEW_OK )
8020 if (!theSideIsFreeBorder) {
8024 // -------------------------------------------------------------------------
8026 // 1. If nodes to merge are not coincident, move nodes of the free border
8027 // from the coord sys defined by the direction from the first to last
8028 // nodes of the border to the correspondent sys of the side 2
8029 // 2. On the side 2, find the links most co-directed with the correspondent
8030 // links of the free border
8031 // -------------------------------------------------------------------------
8033 // 1. Since sewing may brake if there are volumes to split on the side 2,
8034 // we wont move nodes but just compute new coordinates for them
8035 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8036 TNodeXYZMap nBordXYZ;
8037 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8038 list< const SMDS_MeshNode* >::iterator nBordIt;
8040 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8041 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8042 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8043 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8044 double tol2 = 1.e-8;
8045 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8046 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8047 // Need node movement.
8049 // find X and Z axes to create trsf
8050 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8052 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8054 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8057 gp_Ax3 toBordAx( Pb1, Zb, X );
8058 gp_Ax3 fromSideAx( Ps1, Zs, X );
8059 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8061 gp_Trsf toBordSys, fromSide2Sys;
8062 toBordSys.SetTransformation( toBordAx );
8063 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8064 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8067 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8068 const SMDS_MeshNode* n = *nBordIt;
8069 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8070 toBordSys.Transforms( xyz );
8071 fromSide2Sys.Transforms( xyz );
8072 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8076 // just insert nodes XYZ in the nBordXYZ map
8077 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8078 const SMDS_MeshNode* n = *nBordIt;
8079 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8083 // 2. On the side 2, find the links most co-directed with the correspondent
8084 // links of the free border
8086 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8087 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8088 sideNodes.push_back( theSideFirstNode );
8090 bool hasVolumes = false;
8091 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8092 set<long> foundSideLinkIDs, checkedLinkIDs;
8093 SMDS_VolumeTool volume;
8094 //const SMDS_MeshNode* faceNodes[ 4 ];
8096 const SMDS_MeshNode* sideNode;
8097 const SMDS_MeshElement* sideElem;
8098 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8099 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8100 nBordIt = bordNodes.begin();
8102 // border node position and border link direction to compare with
8103 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8104 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8105 // choose next side node by link direction or by closeness to
8106 // the current border node:
8107 bool searchByDir = ( *nBordIt != theBordLastNode );
8109 // find the next node on the Side 2
8111 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8113 checkedLinkIDs.clear();
8114 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8116 // loop on inverse elements of current node (prevSideNode) on the Side 2
8117 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8118 while ( invElemIt->more() )
8120 const SMDS_MeshElement* elem = invElemIt->next();
8121 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8122 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8123 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8124 bool isVolume = volume.Set( elem );
8125 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8126 if ( isVolume ) // --volume
8128 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8129 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8130 if(elem->IsQuadratic()) {
8131 const SMDS_QuadraticFaceOfNodes* F =
8132 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8133 // use special nodes iterator
8134 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8135 while( anIter->more() ) {
8136 nodes[ iNode ] = anIter->next();
8137 if ( nodes[ iNode++ ] == prevSideNode )
8138 iPrevNode = iNode - 1;
8142 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8143 while ( nIt->more() ) {
8144 nodes[ iNode ] = cast2Node( nIt->next() );
8145 if ( nodes[ iNode++ ] == prevSideNode )
8146 iPrevNode = iNode - 1;
8149 // there are 2 links to check
8154 // loop on links, to be precise, on the second node of links
8155 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8156 const SMDS_MeshNode* n = nodes[ iNode ];
8158 if ( !volume.IsLinked( n, prevSideNode ))
8162 if ( iNode ) // a node before prevSideNode
8163 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8164 else // a node after prevSideNode
8165 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8167 // check if this link was already used
8168 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8169 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8170 if (!isJustChecked &&
8171 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8173 // test a link geometrically
8174 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8175 bool linkIsBetter = false;
8176 double dot = 0.0, dist = 0.0;
8177 if ( searchByDir ) { // choose most co-directed link
8178 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8179 linkIsBetter = ( dot > maxDot );
8181 else { // choose link with the node closest to bordPos
8182 dist = ( nextXYZ - bordPos ).SquareModulus();
8183 linkIsBetter = ( dist < minDist );
8185 if ( linkIsBetter ) {
8194 } // loop on inverse elements of prevSideNode
8197 MESSAGE(" Cant find path by links of the Side 2 ");
8198 return SEW_BAD_SIDE_NODES;
8200 sideNodes.push_back( sideNode );
8201 sideElems.push_back( sideElem );
8202 foundSideLinkIDs.insert ( linkID );
8203 prevSideNode = sideNode;
8205 if ( *nBordIt == theBordLastNode )
8206 searchByDir = false;
8208 // find the next border link to compare with
8209 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8210 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8211 // move to next border node if sideNode is before forward border node (bordPos)
8212 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8213 prevBordNode = *nBordIt;
8215 bordPos = nBordXYZ[ *nBordIt ];
8216 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8217 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8221 while ( sideNode != theSideSecondNode );
8223 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8224 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8225 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8227 } // end nodes search on the side 2
8229 // ============================
8230 // sew the border to the side 2
8231 // ============================
8233 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8234 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8236 TListOfListOfNodes nodeGroupsToMerge;
8237 if ( nbNodes[0] == nbNodes[1] ||
8238 ( theSideIsFreeBorder && !theSideThirdNode)) {
8240 // all nodes are to be merged
8242 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8243 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8244 nIt[0]++, nIt[1]++ )
8246 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8247 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8248 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8253 // insert new nodes into the border and the side to get equal nb of segments
8255 // get normalized parameters of nodes on the borders
8256 //double param[ 2 ][ maxNbNodes ];
8258 param[0] = new double [ maxNbNodes ];
8259 param[1] = new double [ maxNbNodes ];
8261 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8262 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8263 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8264 const SMDS_MeshNode* nPrev = *nIt;
8265 double bordLength = 0;
8266 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8267 const SMDS_MeshNode* nCur = *nIt;
8268 gp_XYZ segment (nCur->X() - nPrev->X(),
8269 nCur->Y() - nPrev->Y(),
8270 nCur->Z() - nPrev->Z());
8271 double segmentLen = segment.Modulus();
8272 bordLength += segmentLen;
8273 param[ iBord ][ iNode ] = bordLength;
8276 // normalize within [0,1]
8277 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8278 param[ iBord ][ iNode ] /= bordLength;
8282 // loop on border segments
8283 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8284 int i[ 2 ] = { 0, 0 };
8285 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8286 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8288 TElemOfNodeListMap insertMap;
8289 TElemOfNodeListMap::iterator insertMapIt;
8291 // key: elem to insert nodes into
8292 // value: 2 nodes to insert between + nodes to be inserted
8294 bool next[ 2 ] = { false, false };
8296 // find min adjacent segment length after sewing
8297 double nextParam = 10., prevParam = 0;
8298 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8299 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8300 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8301 if ( i[ iBord ] > 0 )
8302 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8304 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8305 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8306 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8308 // choose to insert or to merge nodes
8309 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8310 if ( Abs( du ) <= minSegLen * 0.2 ) {
8313 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8314 const SMDS_MeshNode* n0 = *nIt[0];
8315 const SMDS_MeshNode* n1 = *nIt[1];
8316 nodeGroupsToMerge.back().push_back( n1 );
8317 nodeGroupsToMerge.back().push_back( n0 );
8318 // position of node of the border changes due to merge
8319 param[ 0 ][ i[0] ] += du;
8320 // move n1 for the sake of elem shape evaluation during insertion.
8321 // n1 will be removed by MergeNodes() anyway
8322 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8323 next[0] = next[1] = true;
8328 int intoBord = ( du < 0 ) ? 0 : 1;
8329 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8330 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8331 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8332 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8333 if ( intoBord == 1 ) {
8334 // move node of the border to be on a link of elem of the side
8335 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8336 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8337 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8338 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8339 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8341 insertMapIt = insertMap.find( elem );
8342 bool notFound = ( insertMapIt == insertMap.end() );
8343 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8345 // insert into another link of the same element:
8346 // 1. perform insertion into the other link of the elem
8347 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8348 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8349 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8350 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8351 // 2. perform insertion into the link of adjacent faces
8353 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8355 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8359 if (toCreatePolyedrs) {
8360 // perform insertion into the links of adjacent volumes
8361 UpdateVolumes(n12, n22, nodeList);
8363 // 3. find an element appeared on n1 and n2 after the insertion
8364 insertMap.erase( elem );
8365 elem = findAdjacentFace( n1, n2, 0 );
8367 if ( notFound || otherLink ) {
8368 // add element and nodes of the side into the insertMap
8369 insertMapIt = insertMap.insert
8370 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8371 (*insertMapIt).second.push_back( n1 );
8372 (*insertMapIt).second.push_back( n2 );
8374 // add node to be inserted into elem
8375 (*insertMapIt).second.push_back( nIns );
8376 next[ 1 - intoBord ] = true;
8379 // go to the next segment
8380 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8381 if ( next[ iBord ] ) {
8382 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8384 nPrev[ iBord ] = *nIt[ iBord ];
8385 nIt[ iBord ]++; i[ iBord ]++;
8389 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8391 // perform insertion of nodes into elements
8393 for (insertMapIt = insertMap.begin();
8394 insertMapIt != insertMap.end();
8397 const SMDS_MeshElement* elem = (*insertMapIt).first;
8398 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8399 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8400 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8402 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8404 if ( !theSideIsFreeBorder ) {
8405 // look for and insert nodes into the faces adjacent to elem
8407 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8409 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8414 if (toCreatePolyedrs) {
8415 // perform insertion into the links of adjacent volumes
8416 UpdateVolumes(n1, n2, nodeList);
8422 } // end: insert new nodes
8424 MergeNodes ( nodeGroupsToMerge );
8429 //=======================================================================
8430 //function : InsertNodesIntoLink
8431 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8432 // and theBetweenNode2 and split theElement
8433 //=======================================================================
8435 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8436 const SMDS_MeshNode* theBetweenNode1,
8437 const SMDS_MeshNode* theBetweenNode2,
8438 list<const SMDS_MeshNode*>& theNodesToInsert,
8439 const bool toCreatePoly)
8441 if ( theFace->GetType() != SMDSAbs_Face ) return;
8443 // find indices of 2 link nodes and of the rest nodes
8444 int iNode = 0, il1, il2, i3, i4;
8445 il1 = il2 = i3 = i4 = -1;
8446 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8447 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8449 if(theFace->IsQuadratic()) {
8450 const SMDS_QuadraticFaceOfNodes* F =
8451 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8452 // use special nodes iterator
8453 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8454 while( anIter->more() ) {
8455 const SMDS_MeshNode* n = anIter->next();
8456 if ( n == theBetweenNode1 )
8458 else if ( n == theBetweenNode2 )
8464 nodes[ iNode++ ] = n;
8468 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8469 while ( nodeIt->more() ) {
8470 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8471 if ( n == theBetweenNode1 )
8473 else if ( n == theBetweenNode2 )
8479 nodes[ iNode++ ] = n;
8482 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8485 // arrange link nodes to go one after another regarding the face orientation
8486 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8487 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8492 aNodesToInsert.reverse();
8494 // check that not link nodes of a quadrangles are in good order
8495 int nbFaceNodes = theFace->NbNodes();
8496 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8502 if (toCreatePoly || theFace->IsPoly()) {
8505 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8507 // add nodes of face up to first node of link
8510 if(theFace->IsQuadratic()) {
8511 const SMDS_QuadraticFaceOfNodes* F =
8512 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8513 // use special nodes iterator
8514 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8515 while( anIter->more() && !isFLN ) {
8516 const SMDS_MeshNode* n = anIter->next();
8517 poly_nodes[iNode++] = n;
8518 if (n == nodes[il1]) {
8522 // add nodes to insert
8523 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8524 for (; nIt != aNodesToInsert.end(); nIt++) {
8525 poly_nodes[iNode++] = *nIt;
8527 // add nodes of face starting from last node of link
8528 while ( anIter->more() ) {
8529 poly_nodes[iNode++] = anIter->next();
8533 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8534 while ( nodeIt->more() && !isFLN ) {
8535 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8536 poly_nodes[iNode++] = n;
8537 if (n == nodes[il1]) {
8541 // add nodes to insert
8542 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8543 for (; nIt != aNodesToInsert.end(); nIt++) {
8544 poly_nodes[iNode++] = *nIt;
8546 // add nodes of face starting from last node of link
8547 while ( nodeIt->more() ) {
8548 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8549 poly_nodes[iNode++] = n;
8553 // edit or replace the face
8554 SMESHDS_Mesh *aMesh = GetMeshDS();
8556 if (theFace->IsPoly()) {
8557 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8560 int aShapeId = FindShape( theFace );
8562 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8563 myLastCreatedElems.Append(newElem);
8564 if ( aShapeId && newElem )
8565 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8567 aMesh->RemoveElement(theFace);
8572 if( !theFace->IsQuadratic() ) {
8574 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8575 int nbLinkNodes = 2 + aNodesToInsert.size();
8576 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8577 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8578 linkNodes[ 0 ] = nodes[ il1 ];
8579 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8580 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8581 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8582 linkNodes[ iNode++ ] = *nIt;
8584 // decide how to split a quadrangle: compare possible variants
8585 // and choose which of splits to be a quadrangle
8586 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8587 if ( nbFaceNodes == 3 ) {
8588 iBestQuad = nbSplits;
8591 else if ( nbFaceNodes == 4 ) {
8592 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8593 double aBestRate = DBL_MAX;
8594 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8596 double aBadRate = 0;
8597 // evaluate elements quality
8598 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8599 if ( iSplit == iQuad ) {
8600 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8604 aBadRate += getBadRate( &quad, aCrit );
8607 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8609 nodes[ iSplit < iQuad ? i4 : i3 ]);
8610 aBadRate += getBadRate( &tria, aCrit );
8614 if ( aBadRate < aBestRate ) {
8616 aBestRate = aBadRate;
8621 // create new elements
8622 SMESHDS_Mesh *aMesh = GetMeshDS();
8623 int aShapeId = FindShape( theFace );
8626 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8627 SMDS_MeshElement* newElem = 0;
8628 if ( iSplit == iBestQuad )
8629 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8634 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8636 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8637 myLastCreatedElems.Append(newElem);
8638 if ( aShapeId && newElem )
8639 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8642 // change nodes of theFace
8643 const SMDS_MeshNode* newNodes[ 4 ];
8644 newNodes[ 0 ] = linkNodes[ i1 ];
8645 newNodes[ 1 ] = linkNodes[ i2 ];
8646 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8647 newNodes[ 3 ] = nodes[ i4 ];
8648 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8649 } // end if(!theFace->IsQuadratic())
8650 else { // theFace is quadratic
8651 // we have to split theFace on simple triangles and one simple quadrangle
8653 int nbshift = tmp*2;
8654 // shift nodes in nodes[] by nbshift
8656 for(i=0; i<nbshift; i++) {
8657 const SMDS_MeshNode* n = nodes[0];
8658 for(j=0; j<nbFaceNodes-1; j++) {
8659 nodes[j] = nodes[j+1];
8661 nodes[nbFaceNodes-1] = n;
8663 il1 = il1 - nbshift;
8664 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8665 // n0 n1 n2 n0 n1 n2
8666 // +-----+-----+ +-----+-----+
8675 // create new elements
8676 SMESHDS_Mesh *aMesh = GetMeshDS();
8677 int aShapeId = FindShape( theFace );
8680 if(nbFaceNodes==6) { // quadratic triangle
8681 SMDS_MeshElement* newElem =
8682 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8683 myLastCreatedElems.Append(newElem);
8684 if ( aShapeId && newElem )
8685 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8686 if(theFace->IsMediumNode(nodes[il1])) {
8687 // create quadrangle
8688 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8689 myLastCreatedElems.Append(newElem);
8690 if ( aShapeId && newElem )
8691 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8697 // create quadrangle
8698 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8699 myLastCreatedElems.Append(newElem);
8700 if ( aShapeId && newElem )
8701 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8707 else { // nbFaceNodes==8 - quadratic quadrangle
8708 SMDS_MeshElement* newElem =
8709 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8710 myLastCreatedElems.Append(newElem);
8711 if ( aShapeId && newElem )
8712 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8713 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8714 myLastCreatedElems.Append(newElem);
8715 if ( aShapeId && newElem )
8716 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8717 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8718 myLastCreatedElems.Append(newElem);
8719 if ( aShapeId && newElem )
8720 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8721 if(theFace->IsMediumNode(nodes[il1])) {
8722 // create quadrangle
8723 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8724 myLastCreatedElems.Append(newElem);
8725 if ( aShapeId && newElem )
8726 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8732 // create quadrangle
8733 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8734 myLastCreatedElems.Append(newElem);
8735 if ( aShapeId && newElem )
8736 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8742 // create needed triangles using n1,n2,n3 and inserted nodes
8743 int nbn = 2 + aNodesToInsert.size();
8744 //const SMDS_MeshNode* aNodes[nbn];
8745 vector<const SMDS_MeshNode*> aNodes(nbn);
8746 aNodes[0] = nodes[n1];
8747 aNodes[nbn-1] = nodes[n2];
8748 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8749 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8750 aNodes[iNode++] = *nIt;
8752 for(i=1; i<nbn; i++) {
8753 SMDS_MeshElement* newElem =
8754 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8755 myLastCreatedElems.Append(newElem);
8756 if ( aShapeId && newElem )
8757 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8759 // remove old quadratic face
8760 aMesh->RemoveElement(theFace);
8764 //=======================================================================
8765 //function : UpdateVolumes
8767 //=======================================================================
8768 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8769 const SMDS_MeshNode* theBetweenNode2,
8770 list<const SMDS_MeshNode*>& theNodesToInsert)
8772 myLastCreatedElems.Clear();
8773 myLastCreatedNodes.Clear();
8775 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8776 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8777 const SMDS_MeshElement* elem = invElemIt->next();
8779 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8780 SMDS_VolumeTool aVolume (elem);
8781 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8784 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8785 int iface, nbFaces = aVolume.NbFaces();
8786 vector<const SMDS_MeshNode *> poly_nodes;
8787 vector<int> quantities (nbFaces);
8789 for (iface = 0; iface < nbFaces; iface++) {
8790 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8791 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8792 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8794 for (int inode = 0; inode < nbFaceNodes; inode++) {
8795 poly_nodes.push_back(faceNodes[inode]);
8797 if (nbInserted == 0) {
8798 if (faceNodes[inode] == theBetweenNode1) {
8799 if (faceNodes[inode + 1] == theBetweenNode2) {
8800 nbInserted = theNodesToInsert.size();
8802 // add nodes to insert
8803 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8804 for (; nIt != theNodesToInsert.end(); nIt++) {
8805 poly_nodes.push_back(*nIt);
8809 else if (faceNodes[inode] == theBetweenNode2) {
8810 if (faceNodes[inode + 1] == theBetweenNode1) {
8811 nbInserted = theNodesToInsert.size();
8813 // add nodes to insert in reversed order
8814 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8816 for (; nIt != theNodesToInsert.begin(); nIt--) {
8817 poly_nodes.push_back(*nIt);
8819 poly_nodes.push_back(*nIt);
8826 quantities[iface] = nbFaceNodes + nbInserted;
8829 // Replace or update the volume
8830 SMESHDS_Mesh *aMesh = GetMeshDS();
8832 if (elem->IsPoly()) {
8833 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8837 int aShapeId = FindShape( elem );
8839 SMDS_MeshElement* newElem =
8840 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8841 myLastCreatedElems.Append(newElem);
8842 if (aShapeId && newElem)
8843 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8845 aMesh->RemoveElement(elem);
8850 //=======================================================================
8852 * \brief Convert elements contained in a submesh to quadratic
8853 * \retval int - nb of checked elements
8855 //=======================================================================
8857 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8858 SMESH_MesherHelper& theHelper,
8859 const bool theForce3d)
8862 if( !theSm ) return nbElem;
8864 const bool notFromGroups = false;
8865 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8866 while(ElemItr->more())
8869 const SMDS_MeshElement* elem = ElemItr->next();
8870 if( !elem || elem->IsQuadratic() ) continue;
8872 int id = elem->GetID();
8873 int nbNodes = elem->NbNodes();
8874 vector<const SMDS_MeshNode *> aNds (nbNodes);
8876 for(int i = 0; i < nbNodes; i++)
8878 aNds[i] = elem->GetNode(i);
8880 SMDSAbs_ElementType aType = elem->GetType();
8882 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8884 const SMDS_MeshElement* NewElem = 0;
8890 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8898 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8901 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8908 case SMDSAbs_Volume :
8913 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8916 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8919 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8922 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8923 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8933 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8935 theSm->AddElement( NewElem );
8940 //=======================================================================
8941 //function : ConvertToQuadratic
8943 //=======================================================================
8944 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8946 SMESHDS_Mesh* meshDS = GetMeshDS();
8948 SMESH_MesherHelper aHelper(*myMesh);
8949 aHelper.SetIsQuadratic( true );
8950 const bool notFromGroups = false;
8952 int nbCheckedElems = 0;
8953 if ( myMesh->HasShapeToMesh() )
8955 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8957 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8958 while ( smIt->more() ) {
8959 SMESH_subMesh* sm = smIt->next();
8960 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8961 aHelper.SetSubShape( sm->GetSubShape() );
8962 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8967 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8968 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8970 SMESHDS_SubMesh *smDS = 0;
8971 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8972 while(aEdgeItr->more())
8974 const SMDS_MeshEdge* edge = aEdgeItr->next();
8975 if(edge && !edge->IsQuadratic())
8977 int id = edge->GetID();
8978 const SMDS_MeshNode* n1 = edge->GetNode(0);
8979 const SMDS_MeshNode* n2 = edge->GetNode(1);
8981 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8983 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8984 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8987 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8988 while(aFaceItr->more())
8990 const SMDS_MeshFace* face = aFaceItr->next();
8991 if(!face || face->IsQuadratic() ) continue;
8993 int id = face->GetID();
8994 int nbNodes = face->NbNodes();
8995 vector<const SMDS_MeshNode *> aNds (nbNodes);
8997 for(int i = 0; i < nbNodes; i++)
8999 aNds[i] = face->GetNode(i);
9002 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9004 SMDS_MeshFace * NewFace = 0;
9008 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9011 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9016 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9018 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9019 while(aVolumeItr->more())
9021 const SMDS_MeshVolume* volume = aVolumeItr->next();
9022 if(!volume || volume->IsQuadratic() ) continue;
9024 int id = volume->GetID();
9025 int nbNodes = volume->NbNodes();
9026 vector<const SMDS_MeshNode *> aNds (nbNodes);
9028 for(int i = 0; i < nbNodes; i++)
9030 aNds[i] = volume->GetNode(i);
9033 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9035 SMDS_MeshVolume * NewVolume = 0;
9039 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9040 aNds[3], id, theForce3d );
9043 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9044 aNds[3], aNds[4], id, theForce3d);
9047 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9048 aNds[3], aNds[4], aNds[5], id, theForce3d);
9051 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9052 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9057 ReplaceElemInGroups(volume, NewVolume, meshDS);
9060 if ( !theForce3d && !getenv("NO_FixQuadraticElements")) {
9061 aHelper.SetSubShape(0); // apply to the whole mesh
9062 aHelper.FixQuadraticElements();
9066 //=======================================================================
9068 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9069 * \retval int - nb of checked elements
9071 //=======================================================================
9073 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9074 SMDS_ElemIteratorPtr theItr,
9075 const int theShapeID)
9078 SMESHDS_Mesh* meshDS = GetMeshDS();
9079 const bool notFromGroups = false;
9081 while( theItr->more() )
9083 const SMDS_MeshElement* elem = theItr->next();
9085 if( elem && elem->IsQuadratic())
9087 int id = elem->GetID();
9088 int nbNodes = elem->NbNodes();
9089 vector<const SMDS_MeshNode *> aNds, mediumNodes;
9090 aNds.reserve( nbNodes );
9091 mediumNodes.reserve( nbNodes );
9093 for(int i = 0; i < nbNodes; i++)
9095 const SMDS_MeshNode* n = elem->GetNode(i);
9097 if( elem->IsMediumNode( n ) )
9098 mediumNodes.push_back( n );
9100 aNds.push_back( n );
9102 if( aNds.empty() ) continue;
9103 SMDSAbs_ElementType aType = elem->GetType();
9105 //remove old quadratic element
9106 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9108 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9109 ReplaceElemInGroups(elem, NewElem, meshDS);
9110 if( theSm && NewElem )
9111 theSm->AddElement( NewElem );
9113 // remove medium nodes
9114 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9115 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9116 const SMDS_MeshNode* n = *nIt;
9117 if ( n->NbInverseElements() == 0 ) {
9118 if ( n->GetPosition()->GetShapeId() != theShapeID )
9119 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9120 ( n->GetPosition()->GetShapeId() ));
9122 meshDS->RemoveFreeNode( n, theSm );
9130 //=======================================================================
9131 //function : ConvertFromQuadratic
9133 //=======================================================================
9134 bool SMESH_MeshEditor::ConvertFromQuadratic()
9136 int nbCheckedElems = 0;
9137 if ( myMesh->HasShapeToMesh() )
9139 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9141 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9142 while ( smIt->more() ) {
9143 SMESH_subMesh* sm = smIt->next();
9144 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9145 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9151 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9152 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9154 SMESHDS_SubMesh *aSM = 0;
9155 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9161 //=======================================================================
9162 //function : SewSideElements
9164 //=======================================================================
9166 SMESH_MeshEditor::Sew_Error
9167 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9168 TIDSortedElemSet& theSide2,
9169 const SMDS_MeshNode* theFirstNode1,
9170 const SMDS_MeshNode* theFirstNode2,
9171 const SMDS_MeshNode* theSecondNode1,
9172 const SMDS_MeshNode* theSecondNode2)
9174 myLastCreatedElems.Clear();
9175 myLastCreatedNodes.Clear();
9177 MESSAGE ("::::SewSideElements()");
9178 if ( theSide1.size() != theSide2.size() )
9179 return SEW_DIFF_NB_OF_ELEMENTS;
9181 Sew_Error aResult = SEW_OK;
9183 // 1. Build set of faces representing each side
9184 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9185 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9187 // =======================================================================
9188 // 1. Build set of faces representing each side:
9189 // =======================================================================
9190 // a. build set of nodes belonging to faces
9191 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9192 // c. create temporary faces representing side of volumes if correspondent
9193 // face does not exist
9195 SMESHDS_Mesh* aMesh = GetMeshDS();
9196 SMDS_Mesh aTmpFacesMesh;
9197 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9198 set<const SMDS_MeshElement*> volSet1, volSet2;
9199 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9200 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9201 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9202 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9203 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9204 int iSide, iFace, iNode;
9206 for ( iSide = 0; iSide < 2; iSide++ ) {
9207 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9208 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9209 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9210 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9211 set<const SMDS_MeshElement*>::iterator vIt;
9212 TIDSortedElemSet::iterator eIt;
9213 set<const SMDS_MeshNode*>::iterator nIt;
9215 // check that given nodes belong to given elements
9216 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9217 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9218 int firstIndex = -1, secondIndex = -1;
9219 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9220 const SMDS_MeshElement* elem = *eIt;
9221 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9222 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9223 if ( firstIndex > -1 && secondIndex > -1 ) break;
9225 if ( firstIndex < 0 || secondIndex < 0 ) {
9226 // we can simply return until temporary faces created
9227 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9230 // -----------------------------------------------------------
9231 // 1a. Collect nodes of existing faces
9232 // and build set of face nodes in order to detect missing
9233 // faces corresponing to sides of volumes
9234 // -----------------------------------------------------------
9236 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9238 // loop on the given element of a side
9239 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9240 //const SMDS_MeshElement* elem = *eIt;
9241 const SMDS_MeshElement* elem = *eIt;
9242 if ( elem->GetType() == SMDSAbs_Face ) {
9243 faceSet->insert( elem );
9244 set <const SMDS_MeshNode*> faceNodeSet;
9245 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9246 while ( nodeIt->more() ) {
9247 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9248 nodeSet->insert( n );
9249 faceNodeSet.insert( n );
9251 setOfFaceNodeSet.insert( faceNodeSet );
9253 else if ( elem->GetType() == SMDSAbs_Volume )
9254 volSet->insert( elem );
9256 // ------------------------------------------------------------------------------
9257 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9258 // ------------------------------------------------------------------------------
9260 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9261 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9262 while ( fIt->more() ) { // loop on faces sharing a node
9263 const SMDS_MeshElement* f = fIt->next();
9264 if ( faceSet->find( f ) == faceSet->end() ) {
9265 // check if all nodes are in nodeSet and
9266 // complete setOfFaceNodeSet if they are
9267 set <const SMDS_MeshNode*> faceNodeSet;
9268 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9269 bool allInSet = true;
9270 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9271 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9272 if ( nodeSet->find( n ) == nodeSet->end() )
9275 faceNodeSet.insert( n );
9278 faceSet->insert( f );
9279 setOfFaceNodeSet.insert( faceNodeSet );
9285 // -------------------------------------------------------------------------
9286 // 1c. Create temporary faces representing sides of volumes if correspondent
9287 // face does not exist
9288 // -------------------------------------------------------------------------
9290 if ( !volSet->empty() ) {
9291 //int nodeSetSize = nodeSet->size();
9293 // loop on given volumes
9294 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9295 SMDS_VolumeTool vol (*vIt);
9296 // loop on volume faces: find free faces
9297 // --------------------------------------
9298 list<const SMDS_MeshElement* > freeFaceList;
9299 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9300 if ( !vol.IsFreeFace( iFace ))
9302 // check if there is already a face with same nodes in a face set
9303 const SMDS_MeshElement* aFreeFace = 0;
9304 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9305 int nbNodes = vol.NbFaceNodes( iFace );
9306 set <const SMDS_MeshNode*> faceNodeSet;
9307 vol.GetFaceNodes( iFace, faceNodeSet );
9308 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9310 // no such a face is given but it still can exist, check it
9311 if ( nbNodes == 3 ) {
9312 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9314 else if ( nbNodes == 4 ) {
9315 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9318 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9319 aFreeFace = aMesh->FindFace(poly_nodes);
9323 // create a temporary face
9324 if ( nbNodes == 3 ) {
9325 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9327 else if ( nbNodes == 4 ) {
9328 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9331 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9332 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9336 freeFaceList.push_back( aFreeFace );
9338 } // loop on faces of a volume
9340 // choose one of several free faces
9341 // --------------------------------------
9342 if ( freeFaceList.size() > 1 ) {
9343 // choose a face having max nb of nodes shared by other elems of a side
9344 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9345 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9346 while ( fIt != freeFaceList.end() ) { // loop on free faces
9347 int nbSharedNodes = 0;
9348 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9349 while ( nodeIt->more() ) { // loop on free face nodes
9350 const SMDS_MeshNode* n =
9351 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9352 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9353 while ( invElemIt->more() ) {
9354 const SMDS_MeshElement* e = invElemIt->next();
9355 if ( faceSet->find( e ) != faceSet->end() )
9357 if ( elemSet->find( e ) != elemSet->end() )
9361 if ( nbSharedNodes >= maxNbNodes ) {
9362 maxNbNodes = nbSharedNodes;
9366 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9368 if ( freeFaceList.size() > 1 )
9370 // could not choose one face, use another way
9371 // choose a face most close to the bary center of the opposite side
9372 gp_XYZ aBC( 0., 0., 0. );
9373 set <const SMDS_MeshNode*> addedNodes;
9374 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9375 eIt = elemSet2->begin();
9376 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9377 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9378 while ( nodeIt->more() ) { // loop on free face nodes
9379 const SMDS_MeshNode* n =
9380 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9381 if ( addedNodes.insert( n ).second )
9382 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9385 aBC /= addedNodes.size();
9386 double minDist = DBL_MAX;
9387 fIt = freeFaceList.begin();
9388 while ( fIt != freeFaceList.end() ) { // loop on free faces
9390 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9391 while ( nodeIt->more() ) { // loop on free face nodes
9392 const SMDS_MeshNode* n =
9393 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9394 gp_XYZ p( n->X(),n->Y(),n->Z() );
9395 dist += ( aBC - p ).SquareModulus();
9397 if ( dist < minDist ) {
9399 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9402 fIt = freeFaceList.erase( fIt++ );
9405 } // choose one of several free faces of a volume
9407 if ( freeFaceList.size() == 1 ) {
9408 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9409 faceSet->insert( aFreeFace );
9410 // complete a node set with nodes of a found free face
9411 // for ( iNode = 0; iNode < ; iNode++ )
9412 // nodeSet->insert( fNodes[ iNode ] );
9415 } // loop on volumes of a side
9417 // // complete a set of faces if new nodes in a nodeSet appeared
9418 // // ----------------------------------------------------------
9419 // if ( nodeSetSize != nodeSet->size() ) {
9420 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9421 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9422 // while ( fIt->more() ) { // loop on faces sharing a node
9423 // const SMDS_MeshElement* f = fIt->next();
9424 // if ( faceSet->find( f ) == faceSet->end() ) {
9425 // // check if all nodes are in nodeSet and
9426 // // complete setOfFaceNodeSet if they are
9427 // set <const SMDS_MeshNode*> faceNodeSet;
9428 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9429 // bool allInSet = true;
9430 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9431 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9432 // if ( nodeSet->find( n ) == nodeSet->end() )
9433 // allInSet = false;
9435 // faceNodeSet.insert( n );
9437 // if ( allInSet ) {
9438 // faceSet->insert( f );
9439 // setOfFaceNodeSet.insert( faceNodeSet );
9445 } // Create temporary faces, if there are volumes given
9448 if ( faceSet1.size() != faceSet2.size() ) {
9449 // delete temporary faces: they are in reverseElements of actual nodes
9450 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9451 while ( tmpFaceIt->more() )
9452 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9453 MESSAGE("Diff nb of faces");
9454 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9457 // ============================================================
9458 // 2. Find nodes to merge:
9459 // bind a node to remove to a node to put instead
9460 // ============================================================
9462 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9463 if ( theFirstNode1 != theFirstNode2 )
9464 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9465 if ( theSecondNode1 != theSecondNode2 )
9466 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9468 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9469 set< long > linkIdSet; // links to process
9470 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9472 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9473 list< NLink > linkList[2];
9474 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9475 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9476 // loop on links in linkList; find faces by links and append links
9477 // of the found faces to linkList
9478 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9479 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9480 NLink link[] = { *linkIt[0], *linkIt[1] };
9481 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9482 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9485 // by links, find faces in the face sets,
9486 // and find indices of link nodes in the found faces;
9487 // in a face set, there is only one or no face sharing a link
9488 // ---------------------------------------------------------------
9490 const SMDS_MeshElement* face[] = { 0, 0 };
9491 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9492 vector<const SMDS_MeshNode*> fnodes1(9);
9493 vector<const SMDS_MeshNode*> fnodes2(9);
9494 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9495 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9496 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9497 int iLinkNode[2][2];
9498 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9499 const SMDS_MeshNode* n1 = link[iSide].first;
9500 const SMDS_MeshNode* n2 = link[iSide].second;
9501 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9502 set< const SMDS_MeshElement* > fMap;
9503 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9504 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9505 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9506 while ( fIt->more() ) { // loop on faces sharing a node
9507 const SMDS_MeshElement* f = fIt->next();
9508 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9509 ! fMap.insert( f ).second ) // f encounters twice
9511 if ( face[ iSide ] ) {
9512 MESSAGE( "2 faces per link " );
9513 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9517 faceSet->erase( f );
9518 // get face nodes and find ones of a link
9523 fnodes1.resize(f->NbNodes()+1);
9524 notLinkNodes1.resize(f->NbNodes()-2);
9527 fnodes2.resize(f->NbNodes()+1);
9528 notLinkNodes2.resize(f->NbNodes()-2);
9531 if(!f->IsQuadratic()) {
9532 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9533 while ( nIt->more() ) {
9534 const SMDS_MeshNode* n =
9535 static_cast<const SMDS_MeshNode*>( nIt->next() );
9537 iLinkNode[ iSide ][ 0 ] = iNode;
9539 else if ( n == n2 ) {
9540 iLinkNode[ iSide ][ 1 ] = iNode;
9542 //else if ( notLinkNodes[ iSide ][ 0 ] )
9543 // notLinkNodes[ iSide ][ 1 ] = n;
9545 // notLinkNodes[ iSide ][ 0 ] = n;
9549 notLinkNodes1[nbl] = n;
9550 //notLinkNodes1.push_back(n);
9552 notLinkNodes2[nbl] = n;
9553 //notLinkNodes2.push_back(n);
9555 //faceNodes[ iSide ][ iNode++ ] = n;
9557 fnodes1[iNode++] = n;
9560 fnodes2[iNode++] = n;
9564 else { // f->IsQuadratic()
9565 const SMDS_QuadraticFaceOfNodes* F =
9566 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9567 // use special nodes iterator
9568 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9569 while ( anIter->more() ) {
9570 const SMDS_MeshNode* n =
9571 static_cast<const SMDS_MeshNode*>( anIter->next() );
9573 iLinkNode[ iSide ][ 0 ] = iNode;
9575 else if ( n == n2 ) {
9576 iLinkNode[ iSide ][ 1 ] = iNode;
9581 notLinkNodes1[nbl] = n;
9584 notLinkNodes2[nbl] = n;
9588 fnodes1[iNode++] = n;
9591 fnodes2[iNode++] = n;
9595 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9597 fnodes1[iNode] = fnodes1[0];
9600 fnodes2[iNode] = fnodes1[0];
9607 // check similarity of elements of the sides
9608 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9609 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9610 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9611 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9614 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9616 break; // do not return because it s necessary to remove tmp faces
9619 // set nodes to merge
9620 // -------------------
9622 if ( face[0] && face[1] ) {
9623 int nbNodes = face[0]->NbNodes();
9624 if ( nbNodes != face[1]->NbNodes() ) {
9625 MESSAGE("Diff nb of face nodes");
9626 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9627 break; // do not return because it s necessary to remove tmp faces
9629 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9630 if ( nbNodes == 3 ) {
9631 //nReplaceMap.insert( TNodeNodeMap::value_type
9632 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9633 nReplaceMap.insert( TNodeNodeMap::value_type
9634 ( notLinkNodes1[0], notLinkNodes2[0] ));
9637 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9638 // analyse link orientation in faces
9639 int i1 = iLinkNode[ iSide ][ 0 ];
9640 int i2 = iLinkNode[ iSide ][ 1 ];
9641 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9642 // if notLinkNodes are the first and the last ones, then
9643 // their order does not correspond to the link orientation
9644 if (( i1 == 1 && i2 == 2 ) ||
9645 ( i1 == 2 && i2 == 1 ))
9646 reverse[ iSide ] = !reverse[ iSide ];
9648 if ( reverse[0] == reverse[1] ) {
9649 //nReplaceMap.insert( TNodeNodeMap::value_type
9650 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9651 //nReplaceMap.insert( TNodeNodeMap::value_type
9652 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9653 for(int nn=0; nn<nbNodes-2; nn++) {
9654 nReplaceMap.insert( TNodeNodeMap::value_type
9655 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9659 //nReplaceMap.insert( TNodeNodeMap::value_type
9660 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9661 //nReplaceMap.insert( TNodeNodeMap::value_type
9662 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9663 for(int nn=0; nn<nbNodes-2; nn++) {
9664 nReplaceMap.insert( TNodeNodeMap::value_type
9665 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9670 // add other links of the faces to linkList
9671 // -----------------------------------------
9673 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9674 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9675 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9676 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9677 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9678 if ( !iter_isnew.second ) { // already in a set: no need to process
9679 linkIdSet.erase( iter_isnew.first );
9681 else // new in set == encountered for the first time: add
9683 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9684 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9685 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9686 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9687 linkList[0].push_back ( NLink( n1, n2 ));
9688 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9692 } // loop on link lists
9694 if ( aResult == SEW_OK &&
9695 ( linkIt[0] != linkList[0].end() ||
9696 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9697 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9698 " " << (faceSetPtr[1]->empty()));
9699 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9702 // ====================================================================
9703 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9704 // ====================================================================
9706 // delete temporary faces: they are in reverseElements of actual nodes
9707 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9708 while ( tmpFaceIt->more() )
9709 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9711 if ( aResult != SEW_OK)
9714 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9715 // loop on nodes replacement map
9716 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9717 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9718 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9719 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9720 nodeIDsToRemove.push_back( nToRemove->GetID() );
9721 // loop on elements sharing nToRemove
9722 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9723 while ( invElemIt->more() ) {
9724 const SMDS_MeshElement* e = invElemIt->next();
9725 // get a new suite of nodes: make replacement
9726 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9727 vector< const SMDS_MeshNode*> nodes( nbNodes );
9728 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9729 while ( nIt->more() ) {
9730 const SMDS_MeshNode* n =
9731 static_cast<const SMDS_MeshNode*>( nIt->next() );
9732 nnIt = nReplaceMap.find( n );
9733 if ( nnIt != nReplaceMap.end() ) {
9739 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9740 // elemIDsToRemove.push_back( e->GetID() );
9743 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9747 Remove( nodeIDsToRemove, true );
9752 //================================================================================
9754 * \brief Find corresponding nodes in two sets of faces
9755 * \param theSide1 - first face set
9756 * \param theSide2 - second first face
9757 * \param theFirstNode1 - a boundary node of set 1
9758 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9759 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9760 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9761 * \param nReplaceMap - output map of corresponding nodes
9762 * \retval bool - is a success or not
9764 //================================================================================
9767 //#define DEBUG_MATCHING_NODES
9770 SMESH_MeshEditor::Sew_Error
9771 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9772 set<const SMDS_MeshElement*>& theSide2,
9773 const SMDS_MeshNode* theFirstNode1,
9774 const SMDS_MeshNode* theFirstNode2,
9775 const SMDS_MeshNode* theSecondNode1,
9776 const SMDS_MeshNode* theSecondNode2,
9777 TNodeNodeMap & nReplaceMap)
9779 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9781 nReplaceMap.clear();
9782 if ( theFirstNode1 != theFirstNode2 )
9783 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9784 if ( theSecondNode1 != theSecondNode2 )
9785 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9787 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9788 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9790 list< NLink > linkList[2];
9791 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9792 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9794 // loop on links in linkList; find faces by links and append links
9795 // of the found faces to linkList
9796 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9797 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9798 NLink link[] = { *linkIt[0], *linkIt[1] };
9799 if ( linkSet.find( link[0] ) == linkSet.end() )
9802 // by links, find faces in the face sets,
9803 // and find indices of link nodes in the found faces;
9804 // in a face set, there is only one or no face sharing a link
9805 // ---------------------------------------------------------------
9807 const SMDS_MeshElement* face[] = { 0, 0 };
9808 list<const SMDS_MeshNode*> notLinkNodes[2];
9809 //bool reverse[] = { false, false }; // order of notLinkNodes
9811 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9813 const SMDS_MeshNode* n1 = link[iSide].first;
9814 const SMDS_MeshNode* n2 = link[iSide].second;
9815 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9816 set< const SMDS_MeshElement* > facesOfNode1;
9817 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9819 // during a loop of the first node, we find all faces around n1,
9820 // during a loop of the second node, we find one face sharing both n1 and n2
9821 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9822 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9823 while ( fIt->more() ) { // loop on faces sharing a node
9824 const SMDS_MeshElement* f = fIt->next();
9825 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9826 ! facesOfNode1.insert( f ).second ) // f encounters twice
9828 if ( face[ iSide ] ) {
9829 MESSAGE( "2 faces per link " );
9830 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9833 faceSet->erase( f );
9835 // get not link nodes
9836 int nbN = f->NbNodes();
9837 if ( f->IsQuadratic() )
9839 nbNodes[ iSide ] = nbN;
9840 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9841 int i1 = f->GetNodeIndex( n1 );
9842 int i2 = f->GetNodeIndex( n2 );
9843 int iEnd = nbN, iBeg = -1, iDelta = 1;
9844 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9846 std::swap( iEnd, iBeg ); iDelta = -1;
9851 if ( i == iEnd ) i = iBeg + iDelta;
9852 if ( i == i1 ) break;
9853 nodes.push_back ( f->GetNode( i ) );
9859 // check similarity of elements of the sides
9860 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9861 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9862 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9863 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9866 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9870 // set nodes to merge
9871 // -------------------
9873 if ( face[0] && face[1] ) {
9874 if ( nbNodes[0] != nbNodes[1] ) {
9875 MESSAGE("Diff nb of face nodes");
9876 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9878 #ifdef DEBUG_MATCHING_NODES
9879 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9880 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9881 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9883 int nbN = nbNodes[0];
9885 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9886 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9887 for ( int i = 0 ; i < nbN - 2; ++i ) {
9888 #ifdef DEBUG_MATCHING_NODES
9889 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9891 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9895 // add other links of the face 1 to linkList
9896 // -----------------------------------------
9898 const SMDS_MeshElement* f0 = face[0];
9899 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9900 for ( int i = 0; i < nbN; i++ )
9902 const SMDS_MeshNode* n2 = f0->GetNode( i );
9903 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9904 linkSet.insert( SMESH_TLink( n1, n2 ));
9905 if ( !iter_isnew.second ) { // already in a set: no need to process
9906 linkSet.erase( iter_isnew.first );
9908 else // new in set == encountered for the first time: add
9910 #ifdef DEBUG_MATCHING_NODES
9911 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9912 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9914 linkList[0].push_back ( NLink( n1, n2 ));
9915 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9920 } // loop on link lists
9925 //================================================================================
9927 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9928 \param theElems - the list of elements (edges or faces) to be replicated
9929 The nodes for duplication could be found from these elements
9930 \param theNodesNot - list of nodes to NOT replicate
9931 \param theAffectedElems - the list of elements (cells and edges) to which the
9932 replicated nodes should be associated to.
9933 \return TRUE if operation has been completed successfully, FALSE otherwise
9935 //================================================================================
9937 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9938 const TIDSortedElemSet& theNodesNot,
9939 const TIDSortedElemSet& theAffectedElems )
9941 myLastCreatedElems.Clear();
9942 myLastCreatedNodes.Clear();
9944 if ( theElems.size() == 0 )
9947 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9952 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9953 // duplicate elements and nodes
9954 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9955 // replce nodes by duplications
9956 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9960 //================================================================================
9962 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9963 \param theMeshDS - mesh instance
9964 \param theElems - the elements replicated or modified (nodes should be changed)
9965 \param theNodesNot - nodes to NOT replicate
9966 \param theNodeNodeMap - relation of old node to new created node
9967 \param theIsDoubleElem - flag os to replicate element or modify
9968 \return TRUE if operation has been completed successfully, FALSE otherwise
9970 //================================================================================
9972 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9973 const TIDSortedElemSet& theElems,
9974 const TIDSortedElemSet& theNodesNot,
9975 std::map< const SMDS_MeshNode*,
9976 const SMDS_MeshNode* >& theNodeNodeMap,
9977 const bool theIsDoubleElem )
9979 // iterate on through element and duplicate them (by nodes duplication)
9981 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9982 for ( ; elemItr != theElems.end(); ++elemItr )
9984 const SMDS_MeshElement* anElem = *elemItr;
9988 bool isDuplicate = false;
9989 // duplicate nodes to duplicate element
9990 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9991 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9993 while ( anIter->more() )
9996 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9997 SMDS_MeshNode* aNewNode = aCurrNode;
9998 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9999 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10000 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10003 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10004 theNodeNodeMap[ aCurrNode ] = aNewNode;
10005 myLastCreatedNodes.Append( aNewNode );
10007 isDuplicate |= (aCurrNode != aNewNode);
10008 newNodes[ ind++ ] = aNewNode;
10010 if ( !isDuplicate )
10013 if ( theIsDoubleElem )
10014 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10016 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10023 //================================================================================
10025 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10026 \param theNodes - identifiers of nodes to be doubled
10027 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10028 nodes. If list of element identifiers is empty then nodes are doubled but
10029 they not assigned to elements
10030 \return TRUE if operation has been completed successfully, FALSE otherwise
10032 //================================================================================
10034 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10035 const std::list< int >& theListOfModifiedElems )
10037 myLastCreatedElems.Clear();
10038 myLastCreatedNodes.Clear();
10040 if ( theListOfNodes.size() == 0 )
10043 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10047 // iterate through nodes and duplicate them
10049 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10051 std::list< int >::const_iterator aNodeIter;
10052 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10054 int aCurr = *aNodeIter;
10055 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10061 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10064 anOldNodeToNewNode[ aNode ] = aNewNode;
10065 myLastCreatedNodes.Append( aNewNode );
10069 // Create map of new nodes for modified elements
10071 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10073 std::list< int >::const_iterator anElemIter;
10074 for ( anElemIter = theListOfModifiedElems.begin();
10075 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10077 int aCurr = *anElemIter;
10078 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10082 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10084 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10086 while ( anIter->more() )
10088 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10089 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10091 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10092 aNodeArr[ ind++ ] = aNewNode;
10095 aNodeArr[ ind++ ] = aCurrNode;
10097 anElemToNodes[ anElem ] = aNodeArr;
10100 // Change nodes of elements
10102 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10103 anElemToNodesIter = anElemToNodes.begin();
10104 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10106 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10107 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10109 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10117 //================================================================================
10119 \brief Check if element located inside shape
10120 \return TRUE if IN or ON shape, FALSE otherwise
10122 //================================================================================
10124 template<class Classifier>
10125 bool isInside(const SMDS_MeshElement* theElem,
10126 Classifier& theClassifier,
10127 const double theTol)
10129 gp_XYZ centerXYZ (0, 0, 0);
10130 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10131 while (aNodeItr->more())
10132 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10134 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10135 theClassifier.Perform(aPnt, theTol);
10136 TopAbs_State aState = theClassifier.State();
10137 return (aState == TopAbs_IN || aState == TopAbs_ON );
10140 //================================================================================
10142 * \brief Classifier of the 3D point on the TopoDS_Face
10143 * with interaface suitable for isInside()
10145 //================================================================================
10147 struct _FaceClassifier
10149 Extrema_ExtPS _extremum;
10150 BRepAdaptor_Surface _surface;
10151 TopAbs_State _state;
10153 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10155 _extremum.Initialize( _surface,
10156 _surface.FirstUParameter(), _surface.LastUParameter(),
10157 _surface.FirstVParameter(), _surface.LastVParameter(),
10158 _surface.Tolerance(), _surface.Tolerance() );
10160 void Perform(const gp_Pnt& aPnt, double theTol)
10162 _state = TopAbs_OUT;
10163 _extremum.Perform(aPnt);
10164 if ( _extremum.IsDone() )
10165 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10166 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10168 TopAbs_State State() const
10175 //================================================================================
10177 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10178 \param theElems - group of of elements (edges or faces) to be replicated
10179 \param theNodesNot - group of nodes not to replicate
10180 \param theShape - shape to detect affected elements (element which geometric center
10181 located on or inside shape).
10182 The replicated nodes should be associated to affected elements.
10183 \return TRUE if operation has been completed successfully, FALSE otherwise
10185 //================================================================================
10187 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10188 const TIDSortedElemSet& theNodesNot,
10189 const TopoDS_Shape& theShape )
10191 if ( theShape.IsNull() )
10194 const double aTol = Precision::Confusion();
10195 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10196 auto_ptr<_FaceClassifier> aFaceClassifier;
10197 if ( theShape.ShapeType() == TopAbs_SOLID )
10199 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10200 bsc3d->PerformInfinitePoint(aTol);
10202 else if (theShape.ShapeType() == TopAbs_FACE )
10204 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10207 // iterates on indicated elements and get elements by back references from their nodes
10208 TIDSortedElemSet anAffected;
10209 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10210 for ( ; elemItr != theElems.end(); ++elemItr )
10212 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10216 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10217 while ( nodeItr->more() )
10219 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10220 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10222 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10223 while ( backElemItr->more() )
10225 const SMDS_MeshElement* curElem = backElemItr->next();
10226 if ( curElem && theElems.find(curElem) == theElems.end() &&
10228 isInside( curElem, *bsc3d, aTol ) :
10229 isInside( curElem, *aFaceClassifier, aTol )))
10230 anAffected.insert( curElem );
10234 return DoubleNodes( theElems, theNodesNot, anAffected );
10237 //================================================================================
10239 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10240 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10241 * \return TRUE if operation has been completed successfully, FALSE otherwise
10243 //================================================================================
10245 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10247 // iterates on volume elements and detect all free faces on them
10248 SMESHDS_Mesh* aMesh = GetMeshDS();
10251 //bool res = false;
10252 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10253 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10256 const SMDS_MeshVolume* volume = vIt->next();
10257 SMDS_VolumeTool vTool( volume );
10258 vTool.SetExternalNormal();
10259 const bool isPoly = volume->IsPoly();
10260 const bool isQuad = volume->IsQuadratic();
10261 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10263 if (!vTool.IsFreeFace(iface))
10266 vector<const SMDS_MeshNode *> nodes;
10267 int nbFaceNodes = vTool.NbFaceNodes(iface);
10268 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10270 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10271 nodes.push_back(faceNodes[inode]);
10273 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10274 nodes.push_back(faceNodes[inode]);
10276 // add new face based on volume nodes
10277 if (aMesh->FindFace( nodes ) ) {
10279 continue; // face already exsist
10281 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10285 return ( nbFree==(nbExisted+nbCreated) );