1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
27 #include "SMESH_MeshEditor.hxx"
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
41 #include "SMESH_Algo.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_Group.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMESH_OctreeNode.hxx"
46 #include "SMESH_subMesh.hxx"
48 #include "utilities.h"
50 #include <BRepAdaptor_Surface.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRep_Tool.hxx>
54 #include <Extrema_GenExtPS.hxx>
55 #include <Extrema_POnCurv.hxx>
56 #include <Extrema_POnSurf.hxx>
57 #include <GC_MakeSegment.hxx>
58 #include <Geom2d_Curve.hxx>
59 #include <GeomAPI_ExtremaCurveCurve.hxx>
60 #include <GeomAdaptor_Surface.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Line.hxx>
63 #include <Geom_Surface.hxx>
64 #include <IntAna_IntConicQuad.hxx>
65 #include <IntAna_Quadric.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS_Face.hxx>
81 #include <gp_Trsf.hxx>
93 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
96 using namespace SMESH::Controls;
98 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
101 //=======================================================================
102 //function : SMESH_MeshEditor
104 //=======================================================================
106 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
107 :myMesh( theMesh ) // theMesh may be NULL
111 //=======================================================================
115 //=======================================================================
118 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
119 const SMDSAbs_ElementType type,
123 SMDS_MeshElement* e = 0;
124 int nbnode = node.size();
125 SMESHDS_Mesh* mesh = GetMeshDS();
127 case SMDSAbs_0DElement:
129 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
130 else e = mesh->Add0DElement (node[0] );
134 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
135 else e = mesh->AddEdge (node[0], node[1] );
136 else if ( nbnode == 3 )
137 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
138 else e = mesh->AddEdge (node[0], node[1], node[2] );
143 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144 else e = mesh->AddFace (node[0], node[1], node[2] );
145 else if (nbnode == 4)
146 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
148 else if (nbnode == 6)
149 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150 node[4], node[5], ID);
151 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
153 else if (nbnode == 8)
154 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7], ID);
156 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7] );
159 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
160 else e = mesh->AddPolygonalFace (node );
166 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
168 else if (nbnode == 5)
169 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
173 else if (nbnode == 6)
174 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175 node[4], node[5], ID);
176 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
178 else if (nbnode == 8)
179 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180 node[4], node[5], node[6], node[7], ID);
181 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
182 node[4], node[5], node[6], node[7] );
183 else if (nbnode == 10)
184 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7],
186 node[8], node[9], ID);
187 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7],
190 else if (nbnode == 13)
191 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
193 node[8], node[9], node[10],node[11],
195 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7],
197 node[8], node[9], node[10],node[11],
199 else if (nbnode == 15)
200 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
203 node[12],node[13],node[14],ID);
204 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
205 node[4], node[5], node[6], node[7],
206 node[8], node[9], node[10],node[11],
207 node[12],node[13],node[14] );
208 else if (nbnode == 20)
209 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
210 node[4], node[5], node[6], node[7],
211 node[8], node[9], node[10],node[11],
212 node[12],node[13],node[14],node[15],
213 node[16],node[17],node[18],node[19],ID);
214 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
215 node[4], node[5], node[6], node[7],
216 node[8], node[9], node[10],node[11],
217 node[12],node[13],node[14],node[15],
218 node[16],node[17],node[18],node[19] );
224 //=======================================================================
228 //=======================================================================
230 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
231 const SMDSAbs_ElementType type,
235 vector<const SMDS_MeshNode*> nodes;
236 nodes.reserve( nodeIDs.size() );
237 vector<int>::const_iterator id = nodeIDs.begin();
238 while ( id != nodeIDs.end() ) {
239 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
240 nodes.push_back( node );
244 return AddElement( nodes, type, isPoly, ID );
247 //=======================================================================
249 //purpose : Remove a node or an element.
250 // Modify a compute state of sub-meshes which become empty
251 //=======================================================================
253 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
256 myLastCreatedElems.Clear();
257 myLastCreatedNodes.Clear();
259 SMESHDS_Mesh* aMesh = GetMeshDS();
260 set< SMESH_subMesh *> smmap;
262 list<int>::const_iterator it = theIDs.begin();
263 for ( ; it != theIDs.end(); it++ ) {
264 const SMDS_MeshElement * elem;
266 elem = aMesh->FindNode( *it );
268 elem = aMesh->FindElement( *it );
272 // Notify VERTEX sub-meshes about modification
274 const SMDS_MeshNode* node = cast2Node( elem );
275 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
276 if ( int aShapeID = node->GetPosition()->GetShapeId() )
277 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
280 // Find sub-meshes to notify about modification
281 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
282 // while ( nodeIt->more() ) {
283 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
284 // const SMDS_PositionPtr& aPosition = node->GetPosition();
285 // if ( aPosition.get() ) {
286 // if ( int aShapeID = aPosition->GetShapeId() ) {
287 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288 // smmap.insert( sm );
295 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
297 aMesh->RemoveElement( elem );
300 // Notify sub-meshes about modification
301 if ( !smmap.empty() ) {
302 set< SMESH_subMesh *>::iterator smIt;
303 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
304 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
307 // // Check if the whole mesh becomes empty
308 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
309 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
314 //=======================================================================
315 //function : FindShape
316 //purpose : Return an index of the shape theElem is on
317 // or zero if a shape not found
318 //=======================================================================
320 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
322 myLastCreatedElems.Clear();
323 myLastCreatedNodes.Clear();
325 SMESHDS_Mesh * aMesh = GetMeshDS();
326 if ( aMesh->ShapeToMesh().IsNull() )
329 if ( theElem->GetType() == SMDSAbs_Node ) {
330 const SMDS_PositionPtr& aPosition =
331 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
332 if ( aPosition.get() )
333 return aPosition->GetShapeId();
338 TopoDS_Shape aShape; // the shape a node is on
339 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
340 while ( nodeIt->more() ) {
341 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
342 const SMDS_PositionPtr& aPosition = node->GetPosition();
343 if ( aPosition.get() ) {
344 int aShapeID = aPosition->GetShapeId();
345 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
347 if ( sm->Contains( theElem ))
349 if ( aShape.IsNull() )
350 aShape = aMesh->IndexToShape( aShapeID );
353 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
358 // None of nodes is on a proper shape,
359 // find the shape among ancestors of aShape on which a node is
360 if ( aShape.IsNull() ) {
361 //MESSAGE ("::FindShape() - NONE node is on shape")
364 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
365 for ( ; ancIt.More(); ancIt.Next() ) {
366 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
367 if ( sm && sm->Contains( theElem ))
368 return aMesh->ShapeToIndex( ancIt.Value() );
371 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
375 //=======================================================================
376 //function : IsMedium
378 //=======================================================================
380 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
381 const SMDSAbs_ElementType typeToCheck)
383 bool isMedium = false;
384 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
385 while (it->more() && !isMedium ) {
386 const SMDS_MeshElement* elem = it->next();
387 isMedium = elem->IsMediumNode(node);
392 //=======================================================================
393 //function : ShiftNodesQuadTria
395 // Shift nodes in the array corresponded to quadratic triangle
396 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
397 //=======================================================================
398 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
400 const SMDS_MeshNode* nd1 = aNodes[0];
401 aNodes[0] = aNodes[1];
402 aNodes[1] = aNodes[2];
404 const SMDS_MeshNode* nd2 = aNodes[3];
405 aNodes[3] = aNodes[4];
406 aNodes[4] = aNodes[5];
410 //=======================================================================
411 //function : GetNodesFromTwoTria
413 // Shift nodes in the array corresponded to quadratic triangle
414 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
415 //=======================================================================
416 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
417 const SMDS_MeshElement * theTria2,
418 const SMDS_MeshNode* N1[],
419 const SMDS_MeshNode* N2[])
421 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
424 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
427 if(it->more()) return false;
428 it = theTria2->nodesIterator();
431 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
434 if(it->more()) return false;
436 int sames[3] = {-1,-1,-1};
448 if(nbsames!=2) return false;
450 ShiftNodesQuadTria(N1);
452 ShiftNodesQuadTria(N1);
455 i = sames[0] + sames[1] + sames[2];
457 ShiftNodesQuadTria(N2);
459 // now we receive following N1 and N2 (using numeration as above image)
460 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
461 // i.e. first nodes from both arrays determ new diagonal
465 //=======================================================================
466 //function : InverseDiag
467 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
468 // but having other common link.
469 // Return False if args are improper
470 //=======================================================================
472 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
473 const SMDS_MeshElement * theTria2 )
475 myLastCreatedElems.Clear();
476 myLastCreatedNodes.Clear();
478 if (!theTria1 || !theTria2)
481 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
482 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
485 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
486 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
490 // put nodes in array and find out indices of the same ones
491 const SMDS_MeshNode* aNodes [6];
492 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
494 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
495 while ( it->more() ) {
496 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
498 if ( i > 2 ) // theTria2
499 // find same node of theTria1
500 for ( int j = 0; j < 3; j++ )
501 if ( aNodes[ i ] == aNodes[ j ]) {
510 return false; // theTria1 is not a triangle
511 it = theTria2->nodesIterator();
513 if ( i == 6 && it->more() )
514 return false; // theTria2 is not a triangle
517 // find indices of 1,2 and of A,B in theTria1
518 int iA = 0, iB = 0, i1 = 0, i2 = 0;
519 for ( i = 0; i < 6; i++ ) {
520 if ( sameInd [ i ] == 0 )
527 // nodes 1 and 2 should not be the same
528 if ( aNodes[ i1 ] == aNodes[ i2 ] )
532 aNodes[ iA ] = aNodes[ i2 ];
534 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
536 //MESSAGE( theTria1 << theTria2 );
538 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
539 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
541 //MESSAGE( theTria1 << theTria2 );
545 } // end if(F1 && F2)
547 // check case of quadratic faces
548 const SMDS_QuadraticFaceOfNodes* QF1 =
549 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
550 if(!QF1) return false;
551 const SMDS_QuadraticFaceOfNodes* QF2 =
552 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
553 if(!QF2) return false;
556 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
557 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
565 const SMDS_MeshNode* N1 [6];
566 const SMDS_MeshNode* N2 [6];
567 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
569 // now we receive following N1 and N2 (using numeration as above image)
570 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
571 // i.e. first nodes from both arrays determ new diagonal
573 const SMDS_MeshNode* N1new [6];
574 const SMDS_MeshNode* N2new [6];
587 // replaces nodes in faces
588 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
589 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
594 //=======================================================================
595 //function : findTriangles
596 //purpose : find triangles sharing theNode1-theNode2 link
597 //=======================================================================
599 static bool findTriangles(const SMDS_MeshNode * theNode1,
600 const SMDS_MeshNode * theNode2,
601 const SMDS_MeshElement*& theTria1,
602 const SMDS_MeshElement*& theTria2)
604 if ( !theNode1 || !theNode2 ) return false;
606 theTria1 = theTria2 = 0;
608 set< const SMDS_MeshElement* > emap;
609 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
611 const SMDS_MeshElement* elem = it->next();
612 if ( elem->NbNodes() == 3 )
615 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
617 const SMDS_MeshElement* elem = it->next();
618 if ( emap.find( elem ) != emap.end() )
620 // theTria1 must be element with minimum ID
621 if( theTria1->GetID() < elem->GetID() ) {
634 return ( theTria1 && theTria2 );
637 //=======================================================================
638 //function : InverseDiag
639 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
640 // with ones built on the same 4 nodes but having other common link.
641 // Return false if proper faces not found
642 //=======================================================================
644 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
645 const SMDS_MeshNode * theNode2)
647 myLastCreatedElems.Clear();
648 myLastCreatedNodes.Clear();
650 MESSAGE( "::InverseDiag()" );
652 const SMDS_MeshElement *tr1, *tr2;
653 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
656 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
657 //if (!F1) return false;
658 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
659 //if (!F2) return false;
662 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
663 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
667 // put nodes in array
668 // and find indices of 1,2 and of A in tr1 and of B in tr2
669 int i, iA1 = 0, i1 = 0;
670 const SMDS_MeshNode* aNodes1 [3];
671 SMDS_ElemIteratorPtr it;
672 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
673 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
674 if ( aNodes1[ i ] == theNode1 )
675 iA1 = i; // node A in tr1
676 else if ( aNodes1[ i ] != theNode2 )
680 const SMDS_MeshNode* aNodes2 [3];
681 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
682 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683 if ( aNodes2[ i ] == theNode2 )
684 iB2 = i; // node B in tr2
685 else if ( aNodes2[ i ] != theNode1 )
689 // nodes 1 and 2 should not be the same
690 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
694 aNodes1[ iA1 ] = aNodes2[ i2 ];
696 aNodes2[ iB2 ] = aNodes1[ i1 ];
698 //MESSAGE( tr1 << tr2 );
700 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
701 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
703 //MESSAGE( tr1 << tr2 );
708 // check case of quadratic faces
709 const SMDS_QuadraticFaceOfNodes* QF1 =
710 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
711 if(!QF1) return false;
712 const SMDS_QuadraticFaceOfNodes* QF2 =
713 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
714 if(!QF2) return false;
715 return InverseDiag(tr1,tr2);
718 //=======================================================================
719 //function : getQuadrangleNodes
720 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
721 // fusion of triangles tr1 and tr2 having shared link on
722 // theNode1 and theNode2
723 //=======================================================================
725 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
726 const SMDS_MeshNode * theNode1,
727 const SMDS_MeshNode * theNode2,
728 const SMDS_MeshElement * tr1,
729 const SMDS_MeshElement * tr2 )
731 if( tr1->NbNodes() != tr2->NbNodes() )
733 // find the 4-th node to insert into tr1
734 const SMDS_MeshNode* n4 = 0;
735 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
737 while ( !n4 && i<3 ) {
738 const SMDS_MeshNode * n = cast2Node( it->next() );
740 bool isDiag = ( n == theNode1 || n == theNode2 );
744 // Make an array of nodes to be in a quadrangle
745 int iNode = 0, iFirstDiag = -1;
746 it = tr1->nodesIterator();
749 const SMDS_MeshNode * n = cast2Node( it->next() );
751 bool isDiag = ( n == theNode1 || n == theNode2 );
753 if ( iFirstDiag < 0 )
755 else if ( iNode - iFirstDiag == 1 )
756 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
758 else if ( n == n4 ) {
759 return false; // tr1 and tr2 should not have all the same nodes
761 theQuadNodes[ iNode++ ] = n;
763 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
764 theQuadNodes[ iNode ] = n4;
769 //=======================================================================
770 //function : DeleteDiag
771 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
772 // with a quadrangle built on the same 4 nodes.
773 // Return false if proper faces not found
774 //=======================================================================
776 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
777 const SMDS_MeshNode * theNode2)
779 myLastCreatedElems.Clear();
780 myLastCreatedNodes.Clear();
782 MESSAGE( "::DeleteDiag()" );
784 const SMDS_MeshElement *tr1, *tr2;
785 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
788 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
789 //if (!F1) return false;
790 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
791 //if (!F2) return false;
794 const SMDS_MeshNode* aNodes [ 4 ];
795 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
798 //MESSAGE( endl << tr1 << tr2 );
800 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
801 myLastCreatedElems.Append(tr1);
802 GetMeshDS()->RemoveElement( tr2 );
804 //MESSAGE( endl << tr1 );
809 // check case of quadratic faces
810 const SMDS_QuadraticFaceOfNodes* QF1 =
811 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
812 if(!QF1) return false;
813 const SMDS_QuadraticFaceOfNodes* QF2 =
814 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
815 if(!QF2) return false;
818 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
819 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
827 const SMDS_MeshNode* N1 [6];
828 const SMDS_MeshNode* N2 [6];
829 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
831 // now we receive following N1 and N2 (using numeration as above image)
832 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
833 // i.e. first nodes from both arrays determ new diagonal
835 const SMDS_MeshNode* aNodes[8];
845 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
846 myLastCreatedElems.Append(tr1);
847 GetMeshDS()->RemoveElement( tr2 );
849 // remove middle node (9)
850 GetMeshDS()->RemoveNode( N1[4] );
855 //=======================================================================
856 //function : Reorient
857 //purpose : Reverse theElement orientation
858 //=======================================================================
860 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
862 myLastCreatedElems.Clear();
863 myLastCreatedNodes.Clear();
867 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
868 if ( !it || !it->more() )
871 switch ( theElem->GetType() ) {
875 if(!theElem->IsQuadratic()) {
876 int i = theElem->NbNodes();
877 vector<const SMDS_MeshNode*> aNodes( i );
879 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
880 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
883 // quadratic elements
884 if(theElem->GetType()==SMDSAbs_Edge) {
885 vector<const SMDS_MeshNode*> aNodes(3);
886 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
887 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
888 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
889 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
892 int nbn = theElem->NbNodes();
893 vector<const SMDS_MeshNode*> aNodes(nbn);
894 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
896 for(; i<nbn/2; i++) {
897 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
899 for(i=0; i<nbn/2; i++) {
900 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
902 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
906 case SMDSAbs_Volume: {
907 if (theElem->IsPoly()) {
908 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
909 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
911 MESSAGE("Warning: bad volumic element");
915 int nbFaces = aPolyedre->NbFaces();
916 vector<const SMDS_MeshNode *> poly_nodes;
917 vector<int> quantities (nbFaces);
919 // reverse each face of the polyedre
920 for (int iface = 1; iface <= nbFaces; iface++) {
921 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
922 quantities[iface - 1] = nbFaceNodes;
924 for (inode = nbFaceNodes; inode >= 1; inode--) {
925 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
926 poly_nodes.push_back(curNode);
930 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
934 SMDS_VolumeTool vTool;
935 if ( !vTool.Set( theElem ))
938 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
947 //=======================================================================
948 //function : getBadRate
950 //=======================================================================
952 static double getBadRate (const SMDS_MeshElement* theElem,
953 SMESH::Controls::NumericalFunctorPtr& theCrit)
955 SMESH::Controls::TSequenceOfXYZ P;
956 if ( !theElem || !theCrit->GetPoints( theElem, P ))
958 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
959 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
962 //=======================================================================
963 //function : QuadToTri
964 //purpose : Cut quadrangles into triangles.
965 // theCrit is used to select a diagonal to cut
966 //=======================================================================
968 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
969 SMESH::Controls::NumericalFunctorPtr theCrit)
971 myLastCreatedElems.Clear();
972 myLastCreatedNodes.Clear();
974 MESSAGE( "::QuadToTri()" );
976 if ( !theCrit.get() )
979 SMESHDS_Mesh * aMesh = GetMeshDS();
981 Handle(Geom_Surface) surface;
982 SMESH_MesherHelper helper( *GetMesh() );
984 TIDSortedElemSet::iterator itElem;
985 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
986 const SMDS_MeshElement* elem = *itElem;
987 if ( !elem || elem->GetType() != SMDSAbs_Face )
989 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
992 // retrieve element nodes
993 const SMDS_MeshNode* aNodes [8];
994 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
996 while ( itN->more() )
997 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
999 // compare two sets of possible triangles
1000 double aBadRate1, aBadRate2; // to what extent a set is bad
1001 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1002 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1003 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1005 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1006 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1007 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1009 int aShapeId = FindShape( elem );
1010 const SMDS_MeshElement* newElem = 0;
1012 if( !elem->IsQuadratic() ) {
1014 // split liner quadrangle
1016 if ( aBadRate1 <= aBadRate2 ) {
1017 // tr1 + tr2 is better
1018 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1019 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1022 // tr3 + tr4 is better
1023 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1024 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1029 // split quadratic quadrangle
1031 // get surface elem is on
1032 if ( aShapeId != helper.GetSubShapeID() ) {
1036 shape = aMesh->IndexToShape( aShapeId );
1037 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1038 TopoDS_Face face = TopoDS::Face( shape );
1039 surface = BRep_Tool::Surface( face );
1040 if ( !surface.IsNull() )
1041 helper.SetSubShape( shape );
1045 const SMDS_MeshNode* aNodes [8];
1046 const SMDS_MeshNode* inFaceNode = 0;
1047 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1049 while ( itN->more() ) {
1050 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1051 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1052 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1054 inFaceNode = aNodes[ i-1 ];
1057 // find middle point for (0,1,2,3)
1058 // and create a node in this point;
1060 if ( surface.IsNull() ) {
1062 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1066 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1069 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1071 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1073 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1074 myLastCreatedNodes.Append(newN);
1076 // create a new element
1077 const SMDS_MeshNode* N[6];
1078 if ( aBadRate1 <= aBadRate2 ) {
1085 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1086 aNodes[6], aNodes[7], newN );
1095 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1096 aNodes[7], aNodes[4], newN );
1098 aMesh->ChangeElementNodes( elem, N, 6 );
1102 // care of a new element
1104 myLastCreatedElems.Append(newElem);
1105 AddToSameGroups( newElem, elem, aMesh );
1107 // put a new triangle on the same shape
1109 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1114 //=======================================================================
1115 //function : BestSplit
1116 //purpose : Find better diagonal for cutting.
1117 //=======================================================================
1119 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1120 SMESH::Controls::NumericalFunctorPtr theCrit)
1122 myLastCreatedElems.Clear();
1123 myLastCreatedNodes.Clear();
1128 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1131 if( theQuad->NbNodes()==4 ||
1132 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1134 // retrieve element nodes
1135 const SMDS_MeshNode* aNodes [4];
1136 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1138 //while (itN->more())
1140 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1142 // compare two sets of possible triangles
1143 double aBadRate1, aBadRate2; // to what extent a set is bad
1144 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1145 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1146 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1148 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1149 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1150 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1152 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1153 return 1; // diagonal 1-3
1155 return 2; // diagonal 2-4
1162 // Methods of splitting volumes into tetra
1164 const int theHexTo5_1[5*4+1] =
1166 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1168 const int theHexTo5_2[5*4+1] =
1170 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1172 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1174 const int theHexTo6_1[6*4+1] =
1176 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
1178 const int theHexTo6_2[6*4+1] =
1180 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
1182 const int theHexTo6_3[6*4+1] =
1184 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
1186 const int theHexTo6_4[6*4+1] =
1188 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
1190 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1192 const int thePyraTo2_1[2*4+1] =
1194 0, 1, 2, 4, 0, 2, 3, 4, -1
1196 const int thePyraTo2_2[2*4+1] =
1198 1, 2, 3, 4, 1, 3, 0, 4, -1
1200 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1202 const int thePentaTo3_1[3*4+1] =
1204 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1206 const int thePentaTo3_2[3*4+1] =
1208 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1210 const int thePentaTo3_3[3*4+1] =
1212 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1214 const int thePentaTo3_4[3*4+1] =
1216 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1218 const int thePentaTo3_5[3*4+1] =
1220 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1222 const int thePentaTo3_6[3*4+1] =
1224 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1226 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1227 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1229 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1232 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1233 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1234 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1239 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1240 bool _baryNode; //!< additional node is to be created at cell barycenter
1241 bool _ownConn; //!< to delete _connectivity in destructor
1243 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1244 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1245 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1246 bool hasFacet( const TTriangleFacet& facet ) const
1248 const int* tetConn = _connectivity;
1249 for ( ; tetConn[0] >= 0; tetConn += 4 )
1250 if (( facet.contains( tetConn[0] ) +
1251 facet.contains( tetConn[1] ) +
1252 facet.contains( tetConn[2] ) +
1253 facet.contains( tetConn[3] )) == 3 )
1259 //=======================================================================
1261 * \brief return TSplitMethod for the given element
1263 //=======================================================================
1265 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1267 int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1269 // Find out how adjacent volumes are split
1271 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1272 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1273 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1275 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1276 maxTetConnSize += 4 * ( nbNodes - 2 );
1277 if ( nbNodes < 4 ) continue;
1279 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1280 const int* nInd = vol.GetFaceNodesIndices( iF );
1283 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1284 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1285 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1286 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1290 int iCom = 0; // common node of triangle faces to split into
1291 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1293 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1294 nInd[ iQ * ( (iCom+1)%nbNodes )],
1295 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1296 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1297 nInd[ iQ * ( (iCom+2)%nbNodes )],
1298 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1299 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1301 triaSplits.push_back( t012 );
1302 triaSplits.push_back( t023 );
1307 if ( !triaSplits.empty() )
1308 hasAdjacentSplits = true;
1311 // Among variants of split method select one compliant with adjacent volumes
1313 TSplitMethod method;
1314 if ( !vol.Element()->IsPoly() )
1316 int nbVariants = 2, nbTet = 0;
1317 const int** connVariants = 0;
1318 switch ( vol.Element()->GetEntityType() )
1320 case SMDSEntity_Hexa:
1321 case SMDSEntity_Quad_Hexa:
1322 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1323 connVariants = theHexTo5, nbTet = 5;
1325 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1327 case SMDSEntity_Pyramid:
1328 case SMDSEntity_Quad_Pyramid:
1329 connVariants = thePyraTo2; nbTet = 2;
1331 case SMDSEntity_Penta:
1332 case SMDSEntity_Quad_Penta:
1333 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1338 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1340 // check method compliancy with adjacent tetras,
1341 // all found splits must be among facets of tetras described by this method
1342 method = TSplitMethod( nbTet, connVariants[variant] );
1343 if ( hasAdjacentSplits && method._nbTetra > 0 )
1345 bool facetCreated = true;
1346 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1348 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1349 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1350 facetCreated = method.hasFacet( *facet );
1352 if ( !facetCreated )
1353 method = TSplitMethod(0); // incompatible method
1357 if ( method._nbTetra < 1 )
1359 // No standard method is applicable, use a generic solution:
1360 // each facet of a volume is split into triangles and
1361 // each of triangles and a volume barycenter form a tetrahedron.
1363 int* connectivity = new int[ maxTetConnSize + 1 ];
1364 method._connectivity = connectivity;
1365 method._ownConn = true;
1366 method._baryNode = true;
1369 int baryCenInd = vol.NbNodes();
1370 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1372 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1373 const int* nInd = vol.GetFaceNodesIndices( iF );
1374 // find common node of triangle facets of tetra to create
1375 int iCommon = 0; // index in linear numeration
1376 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1377 if ( !triaSplits.empty() )
1380 const TTriangleFacet* facet = &triaSplits.front();
1381 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1382 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1383 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1386 else if ( nbNodes > 3 )
1388 // find the best method of splitting into triangles by aspect ratio
1389 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1390 map< double, int > badness2iCommon;
1391 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1392 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1393 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1394 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1396 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1397 nodes[ iQ*((iLast-1)%nbNodes)],
1398 nodes[ iQ*((iLast )%nbNodes)]);
1399 double badness = getBadRate( &tria, aspectRatio );
1400 badness2iCommon.insert( make_pair( badness, iCommon ));
1402 // use iCommon with lowest badness
1403 iCommon = badness2iCommon.begin()->second;
1405 if ( iCommon >= nbNodes )
1406 iCommon = 0; // something wrong
1407 // fill connectivity of tetra
1408 int nbTet = nbNodes - 2;
1409 for ( int i = 0; i < nbTet; ++i )
1411 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1412 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1413 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1414 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1415 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1416 connectivity[ connSize++ ] = baryCenInd;
1420 connectivity[ connSize++ ] = -1;
1424 //================================================================================
1426 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1428 //================================================================================
1430 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1432 // find the tetrahedron including the three nodes of facet
1433 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1434 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1435 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1436 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1437 while ( volIt1->more() )
1439 const SMDS_MeshElement* v = volIt1->next();
1440 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1442 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1443 while ( volIt2->more() )
1444 if ( v != volIt2->next() )
1446 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1447 while ( volIt3->more() )
1448 if ( v == volIt3->next() )
1455 //=======================================================================
1456 //function : SplitVolumesIntoTetra
1457 //purpose : Split volumic elements into tetrahedra.
1458 //=======================================================================
1460 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1461 const int theMethodFlags)
1463 // std-like iterator on coordinates of nodes of mesh element
1464 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1465 NXyzIterator xyzEnd;
1467 SMDS_VolumeTool volTool;
1468 SMESH_MesherHelper helper( *GetMesh());
1470 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1471 SMESHDS_SubMesh* fSubMesh = subMesh;
1473 SMESH_SequenceOfElemPtr newNodes, newElems;
1475 TIDSortedElemSet::const_iterator elem = theElems.begin();
1476 for ( ; elem != theElems.end(); ++elem )
1478 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1479 if ( geomType <= SMDSEntity_Quad_Tetra )
1480 continue; // tetra or face or ...
1482 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1484 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1485 if ( splitMethod._nbTetra < 1 ) continue;
1487 // find submesh to add new tetras in
1488 if ( !subMesh || !subMesh->Contains( *elem ))
1490 int shapeID = FindShape( *elem );
1491 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1492 subMesh = GetMeshDS()->MeshElements( shapeID );
1495 if ( (*elem)->IsQuadratic() )
1498 // add quadratic links to the helper
1499 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1501 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1502 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1503 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1505 helper.SetIsQuadratic( true );
1510 helper.SetIsQuadratic( false );
1512 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1513 if ( splitMethod._baryNode )
1515 // make a node at barycenter
1517 gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1518 SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1519 nodes.push_back( gcNode );
1520 newNodes.Append( gcNode );
1524 helper.SetElementsOnShape( true );
1525 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1526 const int* tetConn = splitMethod._connectivity;
1527 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1528 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1529 nodes[ tetConn[1] ],
1530 nodes[ tetConn[2] ],
1531 nodes[ tetConn[3] ]));
1533 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1535 // Split faces on sides of the split volume
1537 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1538 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1540 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1541 if ( nbNodes < 4 ) continue;
1543 // find an existing face
1544 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1545 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1546 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1548 // among possible triangles create ones discribed by split method
1549 const int* nInd = volTool.GetFaceNodesIndices( iF );
1550 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1551 int iCom = 0; // common node of triangle faces to split into
1552 list< TTriangleFacet > facets;
1553 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1555 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1556 nInd[ iQ * ( (iCom+1)%nbNodes )],
1557 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1558 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1559 nInd[ iQ * ( (iCom+2)%nbNodes )],
1560 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1561 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1563 facets.push_back( t012 );
1564 facets.push_back( t023 );
1565 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1566 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1567 nInd[ iQ * ((iLast-1)%nbNodes )],
1568 nInd[ iQ * ((iLast )%nbNodes )]));
1572 // find submesh to add new faces in
1573 if ( !fSubMesh || !fSubMesh->Contains( face ))
1575 int shapeID = FindShape( face );
1576 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1579 helper.SetElementsOnShape( false );
1580 vector< const SMDS_MeshElement* > triangles;
1581 list< TTriangleFacet >::iterator facet = facets.begin();
1582 for ( ; facet != facets.end(); ++facet )
1584 if ( !volTool.IsFaceExternal( iF ))
1585 swap( facet->_n2, facet->_n3 );
1586 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1587 volNodes[ facet->_n2 ],
1588 volNodes[ facet->_n3 ]));
1589 if ( triangles.back() && fSubMesh )
1590 fSubMesh->AddElement( triangles.back());
1591 newElems.Append( triangles.back() );
1593 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1594 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1597 } // loop on volume faces to split them into triangles
1599 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1601 } // loop on volumes to split
1603 myLastCreatedNodes = newNodes;
1604 myLastCreatedElems = newElems;
1607 //=======================================================================
1608 //function : AddToSameGroups
1609 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1610 //=======================================================================
1612 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1613 const SMDS_MeshElement* elemInGroups,
1614 SMESHDS_Mesh * aMesh)
1616 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1617 if (!groups.empty()) {
1618 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1619 for ( ; grIt != groups.end(); grIt++ ) {
1620 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1621 if ( group && group->Contains( elemInGroups ))
1622 group->SMDSGroup().Add( elemToAdd );
1628 //=======================================================================
1629 //function : RemoveElemFromGroups
1630 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1631 //=======================================================================
1632 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1633 SMESHDS_Mesh * aMesh)
1635 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1636 if (!groups.empty())
1638 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1639 for (; GrIt != groups.end(); GrIt++)
1641 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1642 if (!grp || grp->IsEmpty()) continue;
1643 grp->SMDSGroup().Remove(removeelem);
1648 //================================================================================
1650 * \brief Replace elemToRm by elemToAdd in the all groups
1652 //================================================================================
1654 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1655 const SMDS_MeshElement* elemToAdd,
1656 SMESHDS_Mesh * aMesh)
1658 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1659 if (!groups.empty()) {
1660 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1661 for ( ; grIt != groups.end(); grIt++ ) {
1662 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1663 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1664 group->SMDSGroup().Add( elemToAdd );
1669 //================================================================================
1671 * \brief Replace elemToRm by elemToAdd in the all groups
1673 //================================================================================
1675 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1676 const vector<const SMDS_MeshElement*>& elemToAdd,
1677 SMESHDS_Mesh * aMesh)
1679 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1680 if (!groups.empty())
1682 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1683 for ( ; grIt != groups.end(); grIt++ ) {
1684 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1685 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1686 for ( int i = 0; i < elemToAdd.size(); ++i )
1687 group->SMDSGroup().Add( elemToAdd[ i ] );
1692 //=======================================================================
1693 //function : QuadToTri
1694 //purpose : Cut quadrangles into triangles.
1695 // theCrit is used to select a diagonal to cut
1696 //=======================================================================
1698 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1699 const bool the13Diag)
1701 myLastCreatedElems.Clear();
1702 myLastCreatedNodes.Clear();
1704 MESSAGE( "::QuadToTri()" );
1706 SMESHDS_Mesh * aMesh = GetMeshDS();
1708 Handle(Geom_Surface) surface;
1709 SMESH_MesherHelper helper( *GetMesh() );
1711 TIDSortedElemSet::iterator itElem;
1712 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1713 const SMDS_MeshElement* elem = *itElem;
1714 if ( !elem || elem->GetType() != SMDSAbs_Face )
1716 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1717 if(!isquad) continue;
1719 if(elem->NbNodes()==4) {
1720 // retrieve element nodes
1721 const SMDS_MeshNode* aNodes [4];
1722 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1724 while ( itN->more() )
1725 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1727 int aShapeId = FindShape( elem );
1728 const SMDS_MeshElement* newElem = 0;
1730 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1731 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1734 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1735 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1737 myLastCreatedElems.Append(newElem);
1738 // put a new triangle on the same shape and add to the same groups
1740 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1741 AddToSameGroups( newElem, elem, aMesh );
1744 // Quadratic quadrangle
1746 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1748 // get surface elem is on
1749 int aShapeId = FindShape( elem );
1750 if ( aShapeId != helper.GetSubShapeID() ) {
1754 shape = aMesh->IndexToShape( aShapeId );
1755 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1756 TopoDS_Face face = TopoDS::Face( shape );
1757 surface = BRep_Tool::Surface( face );
1758 if ( !surface.IsNull() )
1759 helper.SetSubShape( shape );
1763 const SMDS_MeshNode* aNodes [8];
1764 const SMDS_MeshNode* inFaceNode = 0;
1765 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1767 while ( itN->more() ) {
1768 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1769 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1770 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1772 inFaceNode = aNodes[ i-1 ];
1776 // find middle point for (0,1,2,3)
1777 // and create a node in this point;
1779 if ( surface.IsNull() ) {
1781 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1785 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1788 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1790 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1792 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1793 myLastCreatedNodes.Append(newN);
1795 // create a new element
1796 const SMDS_MeshElement* newElem = 0;
1797 const SMDS_MeshNode* N[6];
1805 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1806 aNodes[6], aNodes[7], newN );
1815 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1816 aNodes[7], aNodes[4], newN );
1818 myLastCreatedElems.Append(newElem);
1819 aMesh->ChangeElementNodes( elem, N, 6 );
1820 // put a new triangle on the same shape and add to the same groups
1822 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1823 AddToSameGroups( newElem, elem, aMesh );
1830 //=======================================================================
1831 //function : getAngle
1833 //=======================================================================
1835 double getAngle(const SMDS_MeshElement * tr1,
1836 const SMDS_MeshElement * tr2,
1837 const SMDS_MeshNode * n1,
1838 const SMDS_MeshNode * n2)
1840 double angle = 2*PI; // bad angle
1843 SMESH::Controls::TSequenceOfXYZ P1, P2;
1844 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1845 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1848 if(!tr1->IsQuadratic())
1849 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1851 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1852 if ( N1.SquareMagnitude() <= gp::Resolution() )
1854 if(!tr2->IsQuadratic())
1855 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1857 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1858 if ( N2.SquareMagnitude() <= gp::Resolution() )
1861 // find the first diagonal node n1 in the triangles:
1862 // take in account a diagonal link orientation
1863 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1864 for ( int t = 0; t < 2; t++ ) {
1865 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1866 int i = 0, iDiag = -1;
1867 while ( it->more()) {
1868 const SMDS_MeshElement *n = it->next();
1869 if ( n == n1 || n == n2 )
1873 if ( i - iDiag == 1 )
1874 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1882 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1885 angle = N1.Angle( N2 );
1890 // =================================================
1891 // class generating a unique ID for a pair of nodes
1892 // and able to return nodes by that ID
1893 // =================================================
1897 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1898 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1901 long GetLinkID (const SMDS_MeshNode * n1,
1902 const SMDS_MeshNode * n2) const
1904 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1907 bool GetNodes (const long theLinkID,
1908 const SMDS_MeshNode* & theNode1,
1909 const SMDS_MeshNode* & theNode2) const
1911 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1912 if ( !theNode1 ) return false;
1913 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1914 if ( !theNode2 ) return false;
1920 const SMESHDS_Mesh* myMesh;
1925 //=======================================================================
1926 //function : TriToQuad
1927 //purpose : Fuse neighbour triangles into quadrangles.
1928 // theCrit is used to select a neighbour to fuse with.
1929 // theMaxAngle is a max angle between element normals at which
1930 // fusion is still performed.
1931 //=======================================================================
1933 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1934 SMESH::Controls::NumericalFunctorPtr theCrit,
1935 const double theMaxAngle)
1937 myLastCreatedElems.Clear();
1938 myLastCreatedNodes.Clear();
1940 MESSAGE( "::TriToQuad()" );
1942 if ( !theCrit.get() )
1945 SMESHDS_Mesh * aMesh = GetMeshDS();
1947 // Prepare data for algo: build
1948 // 1. map of elements with their linkIDs
1949 // 2. map of linkIDs with their elements
1951 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1952 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1953 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1954 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1956 TIDSortedElemSet::iterator itElem;
1957 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1958 const SMDS_MeshElement* elem = *itElem;
1959 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1960 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1961 if(!IsTria) continue;
1963 // retrieve element nodes
1964 const SMDS_MeshNode* aNodes [4];
1965 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1968 aNodes[ i++ ] = cast2Node( itN->next() );
1969 aNodes[ 3 ] = aNodes[ 0 ];
1972 for ( i = 0; i < 3; i++ ) {
1973 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1974 // check if elements sharing a link can be fused
1975 itLE = mapLi_listEl.find( link );
1976 if ( itLE != mapLi_listEl.end() ) {
1977 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1979 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1980 //if ( FindShape( elem ) != FindShape( elem2 ))
1981 // continue; // do not fuse triangles laying on different shapes
1982 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1983 continue; // avoid making badly shaped quads
1984 (*itLE).second.push_back( elem );
1987 mapLi_listEl[ link ].push_back( elem );
1989 mapEl_setLi [ elem ].insert( link );
1992 // Clean the maps from the links shared by a sole element, ie
1993 // links to which only one element is bound in mapLi_listEl
1995 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1996 int nbElems = (*itLE).second.size();
1997 if ( nbElems < 2 ) {
1998 const SMDS_MeshElement* elem = (*itLE).second.front();
1999 SMESH_TLink link = (*itLE).first;
2000 mapEl_setLi[ elem ].erase( link );
2001 if ( mapEl_setLi[ elem ].empty() )
2002 mapEl_setLi.erase( elem );
2006 // Algo: fuse triangles into quadrangles
2008 while ( ! mapEl_setLi.empty() ) {
2009 // Look for the start element:
2010 // the element having the least nb of shared links
2011 const SMDS_MeshElement* startElem = 0;
2013 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2014 int nbLinks = (*itEL).second.size();
2015 if ( nbLinks < minNbLinks ) {
2016 startElem = (*itEL).first;
2017 minNbLinks = nbLinks;
2018 if ( minNbLinks == 1 )
2023 // search elements to fuse starting from startElem or links of elements
2024 // fused earlyer - startLinks
2025 list< SMESH_TLink > startLinks;
2026 while ( startElem || !startLinks.empty() ) {
2027 while ( !startElem && !startLinks.empty() ) {
2028 // Get an element to start, by a link
2029 SMESH_TLink linkId = startLinks.front();
2030 startLinks.pop_front();
2031 itLE = mapLi_listEl.find( linkId );
2032 if ( itLE != mapLi_listEl.end() ) {
2033 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2034 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2035 for ( ; itE != listElem.end() ; itE++ )
2036 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2038 mapLi_listEl.erase( itLE );
2043 // Get candidates to be fused
2044 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2045 const SMESH_TLink *link12, *link13;
2047 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2048 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2049 ASSERT( !setLi.empty() );
2050 set< SMESH_TLink >::iterator itLi;
2051 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2053 const SMESH_TLink & link = (*itLi);
2054 itLE = mapLi_listEl.find( link );
2055 if ( itLE == mapLi_listEl.end() )
2058 const SMDS_MeshElement* elem = (*itLE).second.front();
2060 elem = (*itLE).second.back();
2061 mapLi_listEl.erase( itLE );
2062 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2073 // add other links of elem to list of links to re-start from
2074 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2075 set< SMESH_TLink >::iterator it;
2076 for ( it = links.begin(); it != links.end(); it++ ) {
2077 const SMESH_TLink& link2 = (*it);
2078 if ( link2 != link )
2079 startLinks.push_back( link2 );
2083 // Get nodes of possible quadrangles
2084 const SMDS_MeshNode *n12 [4], *n13 [4];
2085 bool Ok12 = false, Ok13 = false;
2086 const SMDS_MeshNode *linkNode1, *linkNode2;
2088 linkNode1 = link12->first;
2089 linkNode2 = link12->second;
2090 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2094 linkNode1 = link13->first;
2095 linkNode2 = link13->second;
2096 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2100 // Choose a pair to fuse
2101 if ( Ok12 && Ok13 ) {
2102 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2103 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2104 double aBadRate12 = getBadRate( &quad12, theCrit );
2105 double aBadRate13 = getBadRate( &quad13, theCrit );
2106 if ( aBadRate13 < aBadRate12 )
2113 // and remove fused elems and removed links from the maps
2114 mapEl_setLi.erase( tr1 );
2116 mapEl_setLi.erase( tr2 );
2117 mapLi_listEl.erase( *link12 );
2118 if(tr1->NbNodes()==3) {
2119 if( tr1->GetID() < tr2->GetID() ) {
2120 aMesh->ChangeElementNodes( tr1, n12, 4 );
2121 myLastCreatedElems.Append(tr1);
2122 aMesh->RemoveElement( tr2 );
2125 aMesh->ChangeElementNodes( tr2, n12, 4 );
2126 myLastCreatedElems.Append(tr2);
2127 aMesh->RemoveElement( tr1);
2131 const SMDS_MeshNode* N1 [6];
2132 const SMDS_MeshNode* N2 [6];
2133 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2134 // now we receive following N1 and N2 (using numeration as above image)
2135 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2136 // i.e. first nodes from both arrays determ new diagonal
2137 const SMDS_MeshNode* aNodes[8];
2146 if( tr1->GetID() < tr2->GetID() ) {
2147 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2148 myLastCreatedElems.Append(tr1);
2149 GetMeshDS()->RemoveElement( tr2 );
2152 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2153 myLastCreatedElems.Append(tr2);
2154 GetMeshDS()->RemoveElement( tr1 );
2156 // remove middle node (9)
2157 GetMeshDS()->RemoveNode( N1[4] );
2161 mapEl_setLi.erase( tr3 );
2162 mapLi_listEl.erase( *link13 );
2163 if(tr1->NbNodes()==3) {
2164 if( tr1->GetID() < tr2->GetID() ) {
2165 aMesh->ChangeElementNodes( tr1, n13, 4 );
2166 myLastCreatedElems.Append(tr1);
2167 aMesh->RemoveElement( tr3 );
2170 aMesh->ChangeElementNodes( tr3, n13, 4 );
2171 myLastCreatedElems.Append(tr3);
2172 aMesh->RemoveElement( tr1 );
2176 const SMDS_MeshNode* N1 [6];
2177 const SMDS_MeshNode* N2 [6];
2178 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2179 // now we receive following N1 and N2 (using numeration as above image)
2180 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2181 // i.e. first nodes from both arrays determ new diagonal
2182 const SMDS_MeshNode* aNodes[8];
2191 if( tr1->GetID() < tr2->GetID() ) {
2192 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2193 myLastCreatedElems.Append(tr1);
2194 GetMeshDS()->RemoveElement( tr3 );
2197 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2198 myLastCreatedElems.Append(tr3);
2199 GetMeshDS()->RemoveElement( tr1 );
2201 // remove middle node (9)
2202 GetMeshDS()->RemoveNode( N1[4] );
2206 // Next element to fuse: the rejected one
2208 startElem = Ok12 ? tr3 : tr2;
2210 } // if ( startElem )
2211 } // while ( startElem || !startLinks.empty() )
2212 } // while ( ! mapEl_setLi.empty() )
2218 /*#define DUMPSO(txt) \
2219 // cout << txt << endl;
2220 //=============================================================================
2224 //=============================================================================
2225 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2229 int tmp = idNodes[ i1 ];
2230 idNodes[ i1 ] = idNodes[ i2 ];
2231 idNodes[ i2 ] = tmp;
2232 gp_Pnt Ptmp = P[ i1 ];
2235 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2238 //=======================================================================
2239 //function : SortQuadNodes
2240 //purpose : Set 4 nodes of a quadrangle face in a good order.
2241 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2243 //=======================================================================
2245 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2250 for ( i = 0; i < 4; i++ ) {
2251 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2253 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2256 gp_Vec V1(P[0], P[1]);
2257 gp_Vec V2(P[0], P[2]);
2258 gp_Vec V3(P[0], P[3]);
2260 gp_Vec Cross1 = V1 ^ V2;
2261 gp_Vec Cross2 = V2 ^ V3;
2264 if (Cross1.Dot(Cross2) < 0)
2269 if (Cross1.Dot(Cross2) < 0)
2273 swap ( i, i + 1, idNodes, P );
2275 // for ( int ii = 0; ii < 4; ii++ ) {
2276 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2277 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2283 //=======================================================================
2284 //function : SortHexaNodes
2285 //purpose : Set 8 nodes of a hexahedron in a good order.
2286 // Return success status
2287 //=======================================================================
2289 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2294 DUMPSO( "INPUT: ========================================");
2295 for ( i = 0; i < 8; i++ ) {
2296 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2297 if ( !n ) return false;
2298 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2299 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2301 DUMPSO( "========================================");
2304 set<int> faceNodes; // ids of bottom face nodes, to be found
2305 set<int> checkedId1; // ids of tried 2-nd nodes
2306 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2307 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2308 int iMin, iLoop1 = 0;
2310 // Loop to try the 2-nd nodes
2312 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2314 // Find not checked 2-nd node
2315 for ( i = 1; i < 8; i++ )
2316 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2317 int id1 = idNodes[i];
2318 swap ( 1, i, idNodes, P );
2319 checkedId1.insert ( id1 );
2323 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2324 // ie that all but meybe one (id3 which is on the same face) nodes
2325 // lay on the same side from the triangle plane.
2327 bool manyInPlane = false; // more than 4 nodes lay in plane
2329 while ( ++iLoop2 < 6 ) {
2331 // get 1-2-3 plane coeffs
2332 Standard_Real A, B, C, D;
2333 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2334 if ( N.SquareMagnitude() > gp::Resolution() )
2336 gp_Pln pln ( P[0], N );
2337 pln.Coefficients( A, B, C, D );
2339 // find the node (iMin) closest to pln
2340 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2342 for ( i = 3; i < 8; i++ ) {
2343 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2344 if ( fabs( dist[i] ) < minDist ) {
2345 minDist = fabs( dist[i] );
2348 if ( fabs( dist[i] ) <= tol )
2349 idInPln.insert( idNodes[i] );
2352 // there should not be more than 4 nodes in bottom plane
2353 if ( idInPln.size() > 1 )
2355 DUMPSO( "### idInPln.size() = " << idInPln.size());
2356 // idInPlane does not contain the first 3 nodes
2357 if ( manyInPlane || idInPln.size() == 5)
2358 return false; // all nodes in one plane
2361 // set the 1-st node to be not in plane
2362 for ( i = 3; i < 8; i++ ) {
2363 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2364 DUMPSO( "### Reset 0-th node");
2365 swap( 0, i, idNodes, P );
2370 // reset to re-check second nodes
2371 leastDist = DBL_MAX;
2375 break; // from iLoop2;
2378 // check that the other 4 nodes are on the same side
2379 bool sameSide = true;
2380 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2381 for ( i = 3; sameSide && i < 8; i++ ) {
2383 sameSide = ( isNeg == dist[i] <= 0.);
2386 // keep best solution
2387 if ( sameSide && minDist < leastDist ) {
2388 leastDist = minDist;
2390 faceNodes.insert( idNodes[ 1 ] );
2391 faceNodes.insert( idNodes[ 2 ] );
2392 faceNodes.insert( idNodes[ iMin ] );
2393 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2394 << " leastDist = " << leastDist);
2395 if ( leastDist <= DBL_MIN )
2400 // set next 3-d node to check
2401 int iNext = 2 + iLoop2;
2403 DUMPSO( "Try 2-nd");
2404 swap ( 2, iNext, idNodes, P );
2406 } // while ( iLoop2 < 6 )
2409 if ( faceNodes.empty() ) return false;
2411 // Put the faceNodes in proper places
2412 for ( i = 4; i < 8; i++ ) {
2413 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2414 // find a place to put
2416 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2418 DUMPSO( "Set faceNodes");
2419 swap ( iTo, i, idNodes, P );
2424 // Set nodes of the found bottom face in good order
2425 DUMPSO( " Found bottom face: ");
2426 i = SortQuadNodes( theMesh, idNodes );
2428 gp_Pnt Ptmp = P[ i ];
2433 // for ( int ii = 0; ii < 4; ii++ ) {
2434 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2435 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2438 // Gravity center of the top and bottom faces
2439 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2440 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2442 // Get direction from the bottom to the top face
2443 gp_Vec upDir ( aGCb, aGCt );
2444 Standard_Real upDirSize = upDir.Magnitude();
2445 if ( upDirSize <= gp::Resolution() ) return false;
2448 // Assure that the bottom face normal points up
2449 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2450 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2451 if ( Nb.Dot( upDir ) < 0 ) {
2452 DUMPSO( "Reverse bottom face");
2453 swap( 1, 3, idNodes, P );
2456 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2457 Standard_Real minDist = DBL_MAX;
2458 for ( i = 4; i < 8; i++ ) {
2459 // projection of P[i] to the plane defined by P[0] and upDir
2460 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2461 Standard_Real sqDist = P[0].SquareDistance( Pp );
2462 if ( sqDist < minDist ) {
2467 DUMPSO( "Set 4-th");
2468 swap ( 4, iMin, idNodes, P );
2470 // Set nodes of the top face in good order
2471 DUMPSO( "Sort top face");
2472 i = SortQuadNodes( theMesh, &idNodes[4] );
2475 gp_Pnt Ptmp = P[ i ];
2480 // Assure that direction of the top face normal is from the bottom face
2481 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2482 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2483 if ( Nt.Dot( upDir ) < 0 ) {
2484 DUMPSO( "Reverse top face");
2485 swap( 5, 7, idNodes, P );
2488 // DUMPSO( "OUTPUT: ========================================");
2489 // for ( i = 0; i < 8; i++ ) {
2490 // float *p = ugrid->GetPoint(idNodes[i]);
2491 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2497 //================================================================================
2499 * \brief Return nodes linked to the given one
2500 * \param theNode - the node
2501 * \param linkedNodes - the found nodes
2502 * \param type - the type of elements to check
2504 * Medium nodes are ignored
2506 //================================================================================
2508 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2509 TIDSortedElemSet & linkedNodes,
2510 SMDSAbs_ElementType type )
2512 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2513 while ( elemIt->more() )
2515 const SMDS_MeshElement* elem = elemIt->next();
2516 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2517 if ( elem->GetType() == SMDSAbs_Volume )
2519 SMDS_VolumeTool vol( elem );
2520 while ( nodeIt->more() ) {
2521 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2522 if ( theNode != n && vol.IsLinked( theNode, n ))
2523 linkedNodes.insert( n );
2528 for ( int i = 0; nodeIt->more(); ++i ) {
2529 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2530 if ( n == theNode ) {
2531 int iBefore = i - 1;
2533 if ( elem->IsQuadratic() ) {
2534 int nb = elem->NbNodes() / 2;
2535 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2536 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2538 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2539 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2546 //=======================================================================
2547 //function : laplacianSmooth
2548 //purpose : pulls theNode toward the center of surrounding nodes directly
2549 // connected to that node along an element edge
2550 //=======================================================================
2552 void laplacianSmooth(const SMDS_MeshNode* theNode,
2553 const Handle(Geom_Surface)& theSurface,
2554 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2556 // find surrounding nodes
2558 TIDSortedElemSet nodeSet;
2559 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2561 // compute new coodrs
2563 double coord[] = { 0., 0., 0. };
2564 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2565 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2566 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2567 if ( theSurface.IsNull() ) { // smooth in 3D
2568 coord[0] += node->X();
2569 coord[1] += node->Y();
2570 coord[2] += node->Z();
2572 else { // smooth in 2D
2573 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2574 gp_XY* uv = theUVMap[ node ];
2575 coord[0] += uv->X();
2576 coord[1] += uv->Y();
2579 int nbNodes = nodeSet.size();
2582 coord[0] /= nbNodes;
2583 coord[1] /= nbNodes;
2585 if ( !theSurface.IsNull() ) {
2586 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2587 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2588 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2594 coord[2] /= nbNodes;
2598 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2601 //=======================================================================
2602 //function : centroidalSmooth
2603 //purpose : pulls theNode toward the element-area-weighted centroid of the
2604 // surrounding elements
2605 //=======================================================================
2607 void centroidalSmooth(const SMDS_MeshNode* theNode,
2608 const Handle(Geom_Surface)& theSurface,
2609 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2611 gp_XYZ aNewXYZ(0.,0.,0.);
2612 SMESH::Controls::Area anAreaFunc;
2613 double totalArea = 0.;
2618 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2619 while ( elemIt->more() )
2621 const SMDS_MeshElement* elem = elemIt->next();
2624 gp_XYZ elemCenter(0.,0.,0.);
2625 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2626 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2627 int nn = elem->NbNodes();
2628 if(elem->IsQuadratic()) nn = nn/2;
2630 //while ( itN->more() ) {
2632 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2634 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2635 aNodePoints.push_back( aP );
2636 if ( !theSurface.IsNull() ) { // smooth in 2D
2637 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2638 gp_XY* uv = theUVMap[ aNode ];
2639 aP.SetCoord( uv->X(), uv->Y(), 0. );
2643 double elemArea = anAreaFunc.GetValue( aNodePoints );
2644 totalArea += elemArea;
2646 aNewXYZ += elemCenter * elemArea;
2648 aNewXYZ /= totalArea;
2649 if ( !theSurface.IsNull() ) {
2650 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2651 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2656 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2659 //=======================================================================
2660 //function : getClosestUV
2661 //purpose : return UV of closest projection
2662 //=======================================================================
2664 static bool getClosestUV (Extrema_GenExtPS& projector,
2665 const gp_Pnt& point,
2668 projector.Perform( point );
2669 if ( projector.IsDone() ) {
2670 double u, v, minVal = DBL_MAX;
2671 for ( int i = projector.NbExt(); i > 0; i-- )
2672 if ( projector.Value( i ) < minVal ) {
2673 minVal = projector.Value( i );
2674 projector.Point( i ).Parameter( u, v );
2676 result.SetCoord( u, v );
2682 //=======================================================================
2684 //purpose : Smooth theElements during theNbIterations or until a worst
2685 // element has aspect ratio <= theTgtAspectRatio.
2686 // Aspect Ratio varies in range [1.0, inf].
2687 // If theElements is empty, the whole mesh is smoothed.
2688 // theFixedNodes contains additionally fixed nodes. Nodes built
2689 // on edges and boundary nodes are always fixed.
2690 //=======================================================================
2692 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2693 set<const SMDS_MeshNode*> & theFixedNodes,
2694 const SmoothMethod theSmoothMethod,
2695 const int theNbIterations,
2696 double theTgtAspectRatio,
2699 myLastCreatedElems.Clear();
2700 myLastCreatedNodes.Clear();
2702 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2704 if ( theTgtAspectRatio < 1.0 )
2705 theTgtAspectRatio = 1.0;
2707 const double disttol = 1.e-16;
2709 SMESH::Controls::AspectRatio aQualityFunc;
2711 SMESHDS_Mesh* aMesh = GetMeshDS();
2713 if ( theElems.empty() ) {
2714 // add all faces to theElems
2715 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2716 while ( fIt->more() ) {
2717 const SMDS_MeshElement* face = fIt->next();
2718 theElems.insert( face );
2721 // get all face ids theElems are on
2722 set< int > faceIdSet;
2723 TIDSortedElemSet::iterator itElem;
2725 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2726 int fId = FindShape( *itElem );
2727 // check that corresponding submesh exists and a shape is face
2729 faceIdSet.find( fId ) == faceIdSet.end() &&
2730 aMesh->MeshElements( fId )) {
2731 TopoDS_Shape F = aMesh->IndexToShape( fId );
2732 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2733 faceIdSet.insert( fId );
2736 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2738 // ===============================================
2739 // smooth elements on each TopoDS_Face separately
2740 // ===============================================
2742 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2743 for ( ; fId != faceIdSet.rend(); ++fId ) {
2744 // get face surface and submesh
2745 Handle(Geom_Surface) surface;
2746 SMESHDS_SubMesh* faceSubMesh = 0;
2748 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2749 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2750 bool isUPeriodic = false, isVPeriodic = false;
2752 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2753 surface = BRep_Tool::Surface( face );
2754 faceSubMesh = aMesh->MeshElements( *fId );
2755 fToler2 = BRep_Tool::Tolerance( face );
2756 fToler2 *= fToler2 * 10.;
2757 isUPeriodic = surface->IsUPeriodic();
2759 vPeriod = surface->UPeriod();
2760 isVPeriodic = surface->IsVPeriodic();
2762 uPeriod = surface->VPeriod();
2763 surface->Bounds( u1, u2, v1, v2 );
2765 // ---------------------------------------------------------
2766 // for elements on a face, find movable and fixed nodes and
2767 // compute UV for them
2768 // ---------------------------------------------------------
2769 bool checkBoundaryNodes = false;
2770 bool isQuadratic = false;
2771 set<const SMDS_MeshNode*> setMovableNodes;
2772 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2773 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2774 list< const SMDS_MeshElement* > elemsOnFace;
2776 Extrema_GenExtPS projector;
2777 GeomAdaptor_Surface surfAdaptor;
2778 if ( !surface.IsNull() ) {
2779 surfAdaptor.Load( surface );
2780 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2782 int nbElemOnFace = 0;
2783 itElem = theElems.begin();
2784 // loop on not yet smoothed elements: look for elems on a face
2785 while ( itElem != theElems.end() ) {
2786 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2787 break; // all elements found
2789 const SMDS_MeshElement* elem = *itElem;
2790 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2791 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2795 elemsOnFace.push_back( elem );
2796 theElems.erase( itElem++ );
2800 isQuadratic = elem->IsQuadratic();
2802 // get movable nodes of elem
2803 const SMDS_MeshNode* node;
2804 SMDS_TypeOfPosition posType;
2805 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2806 int nn = 0, nbn = elem->NbNodes();
2807 if(elem->IsQuadratic())
2809 while ( nn++ < nbn ) {
2810 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2811 const SMDS_PositionPtr& pos = node->GetPosition();
2812 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2813 if (posType != SMDS_TOP_EDGE &&
2814 posType != SMDS_TOP_VERTEX &&
2815 theFixedNodes.find( node ) == theFixedNodes.end())
2817 // check if all faces around the node are on faceSubMesh
2818 // because a node on edge may be bound to face
2819 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2821 if ( faceSubMesh ) {
2822 while ( eIt->more() && all ) {
2823 const SMDS_MeshElement* e = eIt->next();
2824 all = faceSubMesh->Contains( e );
2828 setMovableNodes.insert( node );
2830 checkBoundaryNodes = true;
2832 if ( posType == SMDS_TOP_3DSPACE )
2833 checkBoundaryNodes = true;
2836 if ( surface.IsNull() )
2839 // get nodes to check UV
2840 list< const SMDS_MeshNode* > uvCheckNodes;
2841 itN = elem->nodesIterator();
2842 nn = 0; nbn = elem->NbNodes();
2843 if(elem->IsQuadratic())
2845 while ( nn++ < nbn ) {
2846 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2847 if ( uvMap.find( node ) == uvMap.end() )
2848 uvCheckNodes.push_back( node );
2849 // add nodes of elems sharing node
2850 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2851 // while ( eIt->more() ) {
2852 // const SMDS_MeshElement* e = eIt->next();
2853 // if ( e != elem ) {
2854 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2855 // while ( nIt->more() ) {
2856 // const SMDS_MeshNode* n =
2857 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2858 // if ( uvMap.find( n ) == uvMap.end() )
2859 // uvCheckNodes.push_back( n );
2865 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2866 for ( ; n != uvCheckNodes.end(); ++n ) {
2869 const SMDS_PositionPtr& pos = node->GetPosition();
2870 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2872 switch ( posType ) {
2873 case SMDS_TOP_FACE: {
2874 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2875 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2878 case SMDS_TOP_EDGE: {
2879 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2880 Handle(Geom2d_Curve) pcurve;
2881 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2882 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2883 if ( !pcurve.IsNull() ) {
2884 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2885 uv = pcurve->Value( u ).XY();
2889 case SMDS_TOP_VERTEX: {
2890 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2891 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2892 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2897 // check existing UV
2898 bool project = true;
2899 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2900 double dist1 = DBL_MAX, dist2 = 0;
2901 if ( posType != SMDS_TOP_3DSPACE ) {
2902 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2903 project = dist1 > fToler2;
2905 if ( project ) { // compute new UV
2907 if ( !getClosestUV( projector, pNode, newUV )) {
2908 MESSAGE("Node Projection Failed " << node);
2912 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2914 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2916 if ( posType != SMDS_TOP_3DSPACE )
2917 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2918 if ( dist2 < dist1 )
2922 // store UV in the map
2923 listUV.push_back( uv );
2924 uvMap.insert( make_pair( node, &listUV.back() ));
2926 } // loop on not yet smoothed elements
2928 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2929 checkBoundaryNodes = true;
2931 // fix nodes on mesh boundary
2933 if ( checkBoundaryNodes ) {
2934 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2935 map< NLink, int >::iterator link_nb;
2936 // put all elements links to linkNbMap
2937 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2938 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2939 const SMDS_MeshElement* elem = (*elemIt);
2940 int nbn = elem->NbNodes();
2941 if(elem->IsQuadratic())
2943 // loop on elem links: insert them in linkNbMap
2944 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2945 for ( int iN = 0; iN < nbn; ++iN ) {
2946 curNode = elem->GetNode( iN );
2948 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2949 else link = make_pair( prevNode , curNode );
2951 link_nb = linkNbMap.find( link );
2952 if ( link_nb == linkNbMap.end() )
2953 linkNbMap.insert( make_pair ( link, 1 ));
2958 // remove nodes that are in links encountered only once from setMovableNodes
2959 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2960 if ( link_nb->second == 1 ) {
2961 setMovableNodes.erase( link_nb->first.first );
2962 setMovableNodes.erase( link_nb->first.second );
2967 // -----------------------------------------------------
2968 // for nodes on seam edge, compute one more UV ( uvMap2 );
2969 // find movable nodes linked to nodes on seam and which
2970 // are to be smoothed using the second UV ( uvMap2 )
2971 // -----------------------------------------------------
2973 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2974 if ( !surface.IsNull() ) {
2975 TopExp_Explorer eExp( face, TopAbs_EDGE );
2976 for ( ; eExp.More(); eExp.Next() ) {
2977 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2978 if ( !BRep_Tool::IsClosed( edge, face ))
2980 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2981 if ( !sm ) continue;
2982 // find out which parameter varies for a node on seam
2985 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2986 if ( pcurve.IsNull() ) continue;
2987 uv1 = pcurve->Value( f );
2989 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2990 if ( pcurve.IsNull() ) continue;
2991 uv2 = pcurve->Value( f );
2992 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2994 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2995 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2997 // get nodes on seam and its vertices
2998 list< const SMDS_MeshNode* > seamNodes;
2999 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3000 while ( nSeamIt->more() ) {
3001 const SMDS_MeshNode* node = nSeamIt->next();
3002 if ( !isQuadratic || !IsMedium( node ))
3003 seamNodes.push_back( node );
3005 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3006 for ( ; vExp.More(); vExp.Next() ) {
3007 sm = aMesh->MeshElements( vExp.Current() );
3009 nSeamIt = sm->GetNodes();
3010 while ( nSeamIt->more() )
3011 seamNodes.push_back( nSeamIt->next() );
3014 // loop on nodes on seam
3015 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3016 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3017 const SMDS_MeshNode* nSeam = *noSeIt;
3018 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3019 if ( n_uv == uvMap.end() )
3022 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3023 // set the second UV
3024 listUV.push_back( *n_uv->second );
3025 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3026 if ( uvMap2.empty() )
3027 uvMap2 = uvMap; // copy the uvMap contents
3028 uvMap2[ nSeam ] = &listUV.back();
3030 // collect movable nodes linked to ones on seam in nodesNearSeam
3031 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3032 while ( eIt->more() ) {
3033 const SMDS_MeshElement* e = eIt->next();
3034 int nbUseMap1 = 0, nbUseMap2 = 0;
3035 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3036 int nn = 0, nbn = e->NbNodes();
3037 if(e->IsQuadratic()) nbn = nbn/2;
3038 while ( nn++ < nbn )
3040 const SMDS_MeshNode* n =
3041 static_cast<const SMDS_MeshNode*>( nIt->next() );
3043 setMovableNodes.find( n ) == setMovableNodes.end() )
3045 // add only nodes being closer to uv2 than to uv1
3046 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3047 0.5 * ( n->Y() + nSeam->Y() ),
3048 0.5 * ( n->Z() + nSeam->Z() ));
3050 getClosestUV( projector, pMid, uv );
3051 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3052 nodesNearSeam.insert( n );
3058 // for centroidalSmooth all element nodes must
3059 // be on one side of a seam
3060 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3061 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3063 while ( nn++ < nbn ) {
3064 const SMDS_MeshNode* n =
3065 static_cast<const SMDS_MeshNode*>( nIt->next() );
3066 setMovableNodes.erase( n );
3070 } // loop on nodes on seam
3071 } // loop on edge of a face
3072 } // if ( !face.IsNull() )
3074 if ( setMovableNodes.empty() ) {
3075 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3076 continue; // goto next face
3084 double maxRatio = -1., maxDisplacement = -1.;
3085 set<const SMDS_MeshNode*>::iterator nodeToMove;
3086 for ( it = 0; it < theNbIterations; it++ ) {
3087 maxDisplacement = 0.;
3088 nodeToMove = setMovableNodes.begin();
3089 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3090 const SMDS_MeshNode* node = (*nodeToMove);
3091 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3094 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3095 if ( theSmoothMethod == LAPLACIAN )
3096 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3098 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3100 // node displacement
3101 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3102 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3103 if ( aDispl > maxDisplacement )
3104 maxDisplacement = aDispl;
3106 // no node movement => exit
3107 //if ( maxDisplacement < 1.e-16 ) {
3108 if ( maxDisplacement < disttol ) {
3109 MESSAGE("-- no node movement --");
3113 // check elements quality
3115 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3116 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3117 const SMDS_MeshElement* elem = (*elemIt);
3118 if ( !elem || elem->GetType() != SMDSAbs_Face )
3120 SMESH::Controls::TSequenceOfXYZ aPoints;
3121 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3122 double aValue = aQualityFunc.GetValue( aPoints );
3123 if ( aValue > maxRatio )
3127 if ( maxRatio <= theTgtAspectRatio ) {
3128 MESSAGE("-- quality achived --");
3131 if (it+1 == theNbIterations) {
3132 MESSAGE("-- Iteration limit exceeded --");
3134 } // smoothing iterations
3136 MESSAGE(" Face id: " << *fId <<
3137 " Nb iterstions: " << it <<
3138 " Displacement: " << maxDisplacement <<
3139 " Aspect Ratio " << maxRatio);
3141 // ---------------------------------------
3142 // new nodes positions are computed,
3143 // record movement in DS and set new UV
3144 // ---------------------------------------
3145 nodeToMove = setMovableNodes.begin();
3146 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3147 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3148 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3149 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3150 if ( node_uv != uvMap.end() ) {
3151 gp_XY* uv = node_uv->second;
3153 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3157 // move medium nodes of quadratic elements
3160 SMESH_MesherHelper helper( *GetMesh() );
3161 if ( !face.IsNull() )
3162 helper.SetSubShape( face );
3163 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3164 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3165 const SMDS_QuadraticFaceOfNodes* QF =
3166 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3168 vector<const SMDS_MeshNode*> Ns;
3169 Ns.reserve(QF->NbNodes()+1);
3170 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3171 while ( anIter->more() )
3172 Ns.push_back( anIter->next() );
3173 Ns.push_back( Ns[0] );
3175 for(int i=0; i<QF->NbNodes(); i=i+2) {
3176 if ( !surface.IsNull() ) {
3177 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3178 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3179 gp_XY uv = ( uv1 + uv2 ) / 2.;
3180 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3181 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3184 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3185 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3186 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3188 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3189 fabs( Ns[i+1]->Y() - y ) > disttol ||
3190 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3191 // we have to move i+1 node
3192 aMesh->MoveNode( Ns[i+1], x, y, z );
3199 } // loop on face ids
3203 //=======================================================================
3204 //function : isReverse
3205 //purpose : Return true if normal of prevNodes is not co-directied with
3206 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3207 // iNotSame is where prevNodes and nextNodes are different
3208 //=======================================================================
3210 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3211 vector<const SMDS_MeshNode*> nextNodes,
3215 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3216 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3218 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3219 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3220 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3221 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3223 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3224 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3225 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3226 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3228 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3230 return (vA ^ vB) * vN < 0.0;
3233 //=======================================================================
3235 * \brief Create elements by sweeping an element
3236 * \param elem - element to sweep
3237 * \param newNodesItVec - nodes generated from each node of the element
3238 * \param newElems - generated elements
3239 * \param nbSteps - number of sweeping steps
3240 * \param srcElements - to append elem for each generated element
3242 //=======================================================================
3244 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3245 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3246 list<const SMDS_MeshElement*>& newElems,
3248 SMESH_SequenceOfElemPtr& srcElements)
3250 SMESHDS_Mesh* aMesh = GetMeshDS();
3252 // Loop on elem nodes:
3253 // find new nodes and detect same nodes indices
3254 int nbNodes = elem->NbNodes();
3255 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3256 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3257 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3258 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3260 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3261 vector<int> sames(nbNodes);
3262 vector<bool> issimple(nbNodes);
3264 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3265 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3266 const SMDS_MeshNode* node = nnIt->first;
3267 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3268 if ( listNewNodes.empty() ) {
3272 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3274 itNN[ iNode ] = listNewNodes.begin();
3275 prevNod[ iNode ] = node;
3276 nextNod[ iNode ] = listNewNodes.front();
3277 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3278 if ( prevNod[ iNode ] != nextNod [ iNode ])
3279 iNotSameNode = iNode;
3283 sames[nbSame++] = iNode;
3288 //cout<<" nbSame = "<<nbSame<<endl;
3289 if ( nbSame == nbNodes || nbSame > 2) {
3290 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3291 //INFOS( " Too many same nodes of element " << elem->GetID() );
3295 // if( elem->IsQuadratic() && nbSame>0 ) {
3296 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3300 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3301 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3303 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3304 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3305 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3309 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3310 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3311 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3312 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3314 // check element orientation
3316 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3317 //MESSAGE("Reversed elem " << elem );
3321 std::swap( iBeforeSame, iAfterSame );
3324 // make new elements
3325 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3327 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3328 if(issimple[iNode]) {
3329 nextNod[ iNode ] = *itNN[ iNode ];
3333 if( elem->GetType()==SMDSAbs_Node ) {
3334 // we have to use two nodes
3335 midlNod[ iNode ] = *itNN[ iNode ];
3337 nextNod[ iNode ] = *itNN[ iNode ];
3340 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3341 // we have to use each second node
3343 nextNod[ iNode ] = *itNN[ iNode ];
3347 // we have to use two nodes
3348 midlNod[ iNode ] = *itNN[ iNode ];
3350 nextNod[ iNode ] = *itNN[ iNode ];
3355 SMDS_MeshElement* aNewElem = 0;
3356 if(!elem->IsPoly()) {
3357 switch ( nbNodes ) {
3361 if ( nbSame == 0 ) {
3363 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3365 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3371 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3372 nextNod[ 1 ], nextNod[ 0 ] );
3374 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3375 nextNod[ iNotSameNode ] );
3379 case 3: { // TRIANGLE or quadratic edge
3380 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3382 if ( nbSame == 0 ) // --- pentahedron
3383 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3384 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3386 else if ( nbSame == 1 ) // --- pyramid
3387 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3388 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3389 nextNod[ iSameNode ]);
3391 else // 2 same nodes: --- tetrahedron
3392 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3393 nextNod[ iNotSameNode ]);
3395 else { // quadratic edge
3396 if(nbSame==0) { // quadratic quadrangle
3397 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3398 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3400 else if(nbSame==1) { // quadratic triangle
3402 return; // medium node on axis
3404 else if(sames[0]==0) {
3405 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3406 nextNod[2], midlNod[1], prevNod[2]);
3408 else { // sames[0]==1
3409 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3410 midlNod[0], nextNod[2], prevNod[2]);
3419 case 4: { // QUADRANGLE
3421 if ( nbSame == 0 ) // --- hexahedron
3422 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3423 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3425 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3426 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3427 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3428 nextNod[ iSameNode ]);
3429 newElems.push_back( aNewElem );
3430 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3431 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3432 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3434 else if ( nbSame == 2 ) { // pentahedron
3435 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3436 // iBeforeSame is same too
3437 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3438 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3439 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3441 // iAfterSame is same too
3442 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3443 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3444 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3448 case 6: { // quadratic triangle
3449 // create pentahedron with 15 nodes
3451 if(i0>0) { // reversed case
3452 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3453 nextNod[0], nextNod[2], nextNod[1],
3454 prevNod[5], prevNod[4], prevNod[3],
3455 nextNod[5], nextNod[4], nextNod[3],
3456 midlNod[0], midlNod[2], midlNod[1]);
3458 else { // not reversed case
3459 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3460 nextNod[0], nextNod[1], nextNod[2],
3461 prevNod[3], prevNod[4], prevNod[5],
3462 nextNod[3], nextNod[4], nextNod[5],
3463 midlNod[0], midlNod[1], midlNod[2]);
3466 else if(nbSame==1) {
3467 // 2d order pyramid of 13 nodes
3468 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3469 // int n12,int n23,int n34,int n41,
3470 // int n15,int n25,int n35,int n45, int ID);
3472 int n1,n4,n41,n15,n45;
3473 if(i0>0) { // reversed case
3474 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3475 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3481 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3482 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3487 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3488 nextNod[n4], prevNod[n4], prevNod[n5],
3489 midlNod[n1], nextNod[n41],
3490 midlNod[n4], prevNod[n41],
3491 prevNod[n15], nextNod[n15],
3492 nextNod[n45], prevNod[n45]);
3494 else if(nbSame==2) {
3495 // 2d order tetrahedron of 10 nodes
3496 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3497 // int n12,int n23,int n31,
3498 // int n14,int n24,int n34, int ID);
3499 int n1 = iNotSameNode;
3500 int n2,n3,n12,n23,n31;
3501 if(i0>0) { // reversed case
3502 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3503 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3509 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3510 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3515 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3516 prevNod[n12], prevNod[n23], prevNod[n31],
3517 midlNod[n1], nextNod[n12], nextNod[n31]);
3521 case 8: { // quadratic quadrangle
3523 // create hexahedron with 20 nodes
3524 if(i0>0) { // reversed case
3525 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3526 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3527 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3528 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3529 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3531 else { // not reversed case
3532 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3533 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3534 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3535 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3536 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3539 else if(nbSame==1) {
3540 // --- pyramid + pentahedron - can not be created since it is needed
3541 // additional middle node ot the center of face
3542 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3545 else if(nbSame==2) {
3546 // 2d order Pentahedron with 15 nodes
3547 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3548 // int n12,int n23,int n31,int n45,int n56,int n64,
3549 // int n14,int n25,int n36, int ID);
3551 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3552 // iBeforeSame is same too
3559 // iAfterSame is same too
3565 int n12,n45,n14,n25;
3566 if(i0>0) { //reversed case
3578 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3579 prevNod[n4], prevNod[n5], nextNod[n5],
3580 prevNod[n12], midlNod[n2], nextNod[n12],
3581 prevNod[n45], midlNod[n5], nextNod[n45],
3582 prevNod[n14], prevNod[n25], nextNod[n25]);
3587 // realized for extrusion only
3588 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3589 //vector<int> quantities (nbNodes + 2);
3591 //quantities[0] = nbNodes; // bottom of prism
3592 //for (int inode = 0; inode < nbNodes; inode++) {
3593 // polyedre_nodes[inode] = prevNod[inode];
3596 //quantities[1] = nbNodes; // top of prism
3597 //for (int inode = 0; inode < nbNodes; inode++) {
3598 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3601 //for (int iface = 0; iface < nbNodes; iface++) {
3602 // quantities[iface + 2] = 4;
3603 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3604 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3605 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3606 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3607 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3609 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3616 // realized for extrusion only
3617 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3618 vector<int> quantities (nbNodes + 2);
3620 quantities[0] = nbNodes; // bottom of prism
3621 for (int inode = 0; inode < nbNodes; inode++) {
3622 polyedre_nodes[inode] = prevNod[inode];
3625 quantities[1] = nbNodes; // top of prism
3626 for (int inode = 0; inode < nbNodes; inode++) {
3627 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3630 for (int iface = 0; iface < nbNodes; iface++) {
3631 quantities[iface + 2] = 4;
3632 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3633 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3634 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3635 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3636 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3638 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3642 newElems.push_back( aNewElem );
3643 myLastCreatedElems.Append(aNewElem);
3644 srcElements.Append( elem );
3647 // set new prev nodes
3648 for ( iNode = 0; iNode < nbNodes; iNode++ )
3649 prevNod[ iNode ] = nextNod[ iNode ];
3654 //=======================================================================
3656 * \brief Create 1D and 2D elements around swept elements
3657 * \param mapNewNodes - source nodes and ones generated from them
3658 * \param newElemsMap - source elements and ones generated from them
3659 * \param elemNewNodesMap - nodes generated from each node of each element
3660 * \param elemSet - all swept elements
3661 * \param nbSteps - number of sweeping steps
3662 * \param srcElements - to append elem for each generated element
3664 //=======================================================================
3666 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3667 TElemOfElemListMap & newElemsMap,
3668 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3669 TIDSortedElemSet& elemSet,
3671 SMESH_SequenceOfElemPtr& srcElements)
3673 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3674 SMESHDS_Mesh* aMesh = GetMeshDS();
3676 // Find nodes belonging to only one initial element - sweep them to get edges.
3678 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3679 for ( ; nList != mapNewNodes.end(); nList++ ) {
3680 const SMDS_MeshNode* node =
3681 static_cast<const SMDS_MeshNode*>( nList->first );
3682 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3683 int nbInitElems = 0;
3684 const SMDS_MeshElement* el = 0;
3685 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3686 while ( eIt->more() && nbInitElems < 2 ) {
3688 SMDSAbs_ElementType type = el->GetType();
3689 if ( type == SMDSAbs_Volume || type < highType ) continue;
3690 if ( type > highType ) {
3694 if ( elemSet.find(el) != elemSet.end() )
3697 if ( nbInitElems < 2 ) {
3698 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3699 if(!NotCreateEdge) {
3700 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3701 list<const SMDS_MeshElement*> newEdges;
3702 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3707 // Make a ceiling for each element ie an equal element of last new nodes.
3708 // Find free links of faces - make edges and sweep them into faces.
3710 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3711 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3712 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3713 const SMDS_MeshElement* elem = itElem->first;
3714 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3716 if ( elem->GetType() == SMDSAbs_Edge ) {
3717 // create a ceiling edge
3718 if (!elem->IsQuadratic()) {
3719 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3720 vecNewNodes[ 1 ]->second.back())) {
3721 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3722 vecNewNodes[ 1 ]->second.back()));
3723 srcElements.Append( myLastCreatedElems.Last() );
3727 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3728 vecNewNodes[ 1 ]->second.back(),
3729 vecNewNodes[ 2 ]->second.back())) {
3730 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3731 vecNewNodes[ 1 ]->second.back(),
3732 vecNewNodes[ 2 ]->second.back()));
3733 srcElements.Append( myLastCreatedElems.Last() );
3737 if ( elem->GetType() != SMDSAbs_Face )
3740 if(itElem->second.size()==0) continue;
3742 bool hasFreeLinks = false;
3744 TIDSortedElemSet avoidSet;
3745 avoidSet.insert( elem );
3747 set<const SMDS_MeshNode*> aFaceLastNodes;
3748 int iNode, nbNodes = vecNewNodes.size();
3749 if(!elem->IsQuadratic()) {
3750 // loop on the face nodes
3751 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3752 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3753 // look for free links of the face
3754 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3755 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3756 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3757 // check if a link is free
3758 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3759 hasFreeLinks = true;
3760 // make an edge and a ceiling for a new edge
3761 if ( !aMesh->FindEdge( n1, n2 )) {
3762 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3763 srcElements.Append( myLastCreatedElems.Last() );
3765 n1 = vecNewNodes[ iNode ]->second.back();
3766 n2 = vecNewNodes[ iNext ]->second.back();
3767 if ( !aMesh->FindEdge( n1, n2 )) {
3768 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3769 srcElements.Append( myLastCreatedElems.Last() );
3774 else { // elem is quadratic face
3775 int nbn = nbNodes/2;
3776 for ( iNode = 0; iNode < nbn; iNode++ ) {
3777 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3778 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3779 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3780 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3781 // check if a link is free
3782 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3783 hasFreeLinks = true;
3784 // make an edge and a ceiling for a new edge
3786 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3787 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3788 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3789 srcElements.Append( myLastCreatedElems.Last() );
3791 n1 = vecNewNodes[ iNode ]->second.back();
3792 n2 = vecNewNodes[ iNext ]->second.back();
3793 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3794 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3795 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3796 srcElements.Append( myLastCreatedElems.Last() );
3800 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3801 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3805 // sweep free links into faces
3807 if ( hasFreeLinks ) {
3808 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3809 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3811 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3812 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3813 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3814 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3816 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3817 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3819 while ( iVol++ < volNb ) v++;
3820 // find indices of free faces of a volume and their source edges
3821 list< int > freeInd;
3822 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3823 SMDS_VolumeTool vTool( *v );
3824 int iF, nbF = vTool.NbFaces();
3825 for ( iF = 0; iF < nbF; iF ++ ) {
3826 if (vTool.IsFreeFace( iF ) &&
3827 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3828 initNodeSet != faceNodeSet) // except an initial face
3830 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3832 freeInd.push_back( iF );
3833 // find source edge of a free face iF
3834 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3835 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3836 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3837 initNodeSet.begin(), initNodeSet.end(),
3838 commonNodes.begin());
3839 if ( (*v)->IsQuadratic() )
3840 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3842 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3844 if ( !srcEdges.back() )
3846 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3847 << iF << " of volume #" << vTool.ID() << endl;
3852 if ( freeInd.empty() )
3855 // create faces for all steps;
3856 // if such a face has been already created by sweep of edge,
3857 // assure that its orientation is OK
3858 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3860 vTool.SetExternalNormal();
3861 list< int >::iterator ind = freeInd.begin();
3862 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3863 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3865 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3866 int nbn = vTool.NbFaceNodes( *ind );
3868 case 3: { ///// triangle
3869 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3871 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3872 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3873 aMesh->ChangeElementNodes( f, nodes, nbn );
3876 case 4: { ///// quadrangle
3877 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3879 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3880 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3881 aMesh->ChangeElementNodes( f, nodes, nbn );
3885 if( (*v)->IsQuadratic() ) {
3886 if(nbn==6) { /////// quadratic triangle
3887 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3888 nodes[1], nodes[3], nodes[5] );
3890 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3891 nodes[1], nodes[3], nodes[5]));
3893 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3894 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3895 tmpnodes[0] = nodes[0];
3896 tmpnodes[1] = nodes[2];
3897 tmpnodes[2] = nodes[4];
3898 tmpnodes[3] = nodes[1];
3899 tmpnodes[4] = nodes[3];
3900 tmpnodes[5] = nodes[5];
3901 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3904 else { /////// quadratic quadrangle
3905 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3906 nodes[1], nodes[3], nodes[5], nodes[7] );
3908 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3909 nodes[1], nodes[3], nodes[5], nodes[7]));
3911 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3912 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3913 tmpnodes[0] = nodes[0];
3914 tmpnodes[1] = nodes[2];
3915 tmpnodes[2] = nodes[4];
3916 tmpnodes[3] = nodes[6];
3917 tmpnodes[4] = nodes[1];
3918 tmpnodes[5] = nodes[3];
3919 tmpnodes[6] = nodes[5];
3920 tmpnodes[7] = nodes[7];
3921 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3925 else { //////// polygon
3926 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3927 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3929 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3930 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3931 aMesh->ChangeElementNodes( f, nodes, nbn );
3934 while ( srcElements.Length() < myLastCreatedElems.Length() )
3935 srcElements.Append( *srcEdge );
3937 } // loop on free faces
3939 // go to the next volume
3941 while ( iVol++ < nbVolumesByStep ) v++;
3944 } // sweep free links into faces
3946 // Make a ceiling face with a normal external to a volume
3948 SMDS_VolumeTool lastVol( itElem->second.back() );
3950 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3952 lastVol.SetExternalNormal();
3953 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3954 int nbn = lastVol.NbFaceNodes( iF );
3957 if (!hasFreeLinks ||
3958 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3959 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3962 if (!hasFreeLinks ||
3963 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3964 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3967 if(itElem->second.back()->IsQuadratic()) {
3969 if (!hasFreeLinks ||
3970 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3971 nodes[1], nodes[3], nodes[5]) ) {
3972 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3973 nodes[1], nodes[3], nodes[5]));
3977 if (!hasFreeLinks ||
3978 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3979 nodes[1], nodes[3], nodes[5], nodes[7]) )
3980 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3981 nodes[1], nodes[3], nodes[5], nodes[7]));
3985 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3986 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3987 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3991 while ( srcElements.Length() < myLastCreatedElems.Length() )
3992 srcElements.Append( myLastCreatedElems.Last() );
3994 } // loop on swept elements
3997 //=======================================================================
3998 //function : RotationSweep
4000 //=======================================================================
4002 SMESH_MeshEditor::PGroupIDs
4003 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4004 const gp_Ax1& theAxis,
4005 const double theAngle,
4006 const int theNbSteps,
4007 const double theTol,
4008 const bool theMakeGroups,
4009 const bool theMakeWalls)
4011 myLastCreatedElems.Clear();
4012 myLastCreatedNodes.Clear();
4014 // source elements for each generated one
4015 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4017 MESSAGE( "RotationSweep()");
4019 aTrsf.SetRotation( theAxis, theAngle );
4021 aTrsf2.SetRotation( theAxis, theAngle/2. );
4023 gp_Lin aLine( theAxis );
4024 double aSqTol = theTol * theTol;
4026 SMESHDS_Mesh* aMesh = GetMeshDS();
4028 TNodeOfNodeListMap mapNewNodes;
4029 TElemOfVecOfNnlmiMap mapElemNewNodes;
4030 TElemOfElemListMap newElemsMap;
4033 TIDSortedElemSet::iterator itElem;
4034 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4035 const SMDS_MeshElement* elem = *itElem;
4036 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4038 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4039 newNodesItVec.reserve( elem->NbNodes() );
4041 // loop on elem nodes
4042 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4043 while ( itN->more() ) {
4044 // check if a node has been already sweeped
4045 const SMDS_MeshNode* node = cast2Node( itN->next() );
4047 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4049 aXYZ.Coord( coord[0], coord[1], coord[2] );
4050 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4052 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4053 if ( nIt == mapNewNodes.end() ) {
4054 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4055 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4058 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4060 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4061 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4062 const SMDS_MeshNode * newNode = node;
4063 for ( int i = 0; i < theNbSteps; i++ ) {
4065 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4067 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4068 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4069 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4070 myLastCreatedNodes.Append(newNode);
4071 srcNodes.Append( node );
4072 listNewNodes.push_back( newNode );
4073 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4074 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4077 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4079 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4080 myLastCreatedNodes.Append(newNode);
4081 srcNodes.Append( node );
4082 listNewNodes.push_back( newNode );
4085 listNewNodes.push_back( newNode );
4086 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4087 listNewNodes.push_back( newNode );
4094 // if current elem is quadratic and current node is not medium
4095 // we have to check - may be it is needed to insert additional nodes
4096 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4097 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4098 if(listNewNodes.size()==theNbSteps) {
4099 listNewNodes.clear();
4101 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4103 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4104 const SMDS_MeshNode * newNode = node;
4106 for(int i = 0; i<theNbSteps; i++) {
4107 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4108 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4109 cout<<" 3 AddNode: "<<newNode;
4110 myLastCreatedNodes.Append(newNode);
4111 listNewNodes.push_back( newNode );
4112 srcNodes.Append( node );
4113 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4114 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4115 cout<<" 4 AddNode: "<<newNode;
4116 myLastCreatedNodes.Append(newNode);
4117 srcNodes.Append( node );
4118 listNewNodes.push_back( newNode );
4122 listNewNodes.push_back( newNode );
4128 newNodesItVec.push_back( nIt );
4130 // make new elements
4131 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4135 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4137 PGroupIDs newGroupIDs;
4138 if ( theMakeGroups )
4139 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4145 //=======================================================================
4146 //function : CreateNode
4148 //=======================================================================
4149 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4152 const double tolnode,
4153 SMESH_SequenceOfNode& aNodes)
4155 myLastCreatedElems.Clear();
4156 myLastCreatedNodes.Clear();
4159 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4161 // try to search in sequence of existing nodes
4162 // if aNodes.Length()>0 we 'nave to use given sequence
4163 // else - use all nodes of mesh
4164 if(aNodes.Length()>0) {
4166 for(i=1; i<=aNodes.Length(); i++) {
4167 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4168 if(P1.Distance(P2)<tolnode)
4169 return aNodes.Value(i);
4173 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4174 while(itn->more()) {
4175 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4176 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4177 if(P1.Distance(P2)<tolnode)
4182 // create new node and return it
4183 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4184 myLastCreatedNodes.Append(NewNode);
4189 //=======================================================================
4190 //function : ExtrusionSweep
4192 //=======================================================================
4194 SMESH_MeshEditor::PGroupIDs
4195 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4196 const gp_Vec& theStep,
4197 const int theNbSteps,
4198 TElemOfElemListMap& newElemsMap,
4199 const bool theMakeGroups,
4201 const double theTolerance)
4203 ExtrusParam aParams;
4204 aParams.myDir = gp_Dir(theStep);
4205 aParams.myNodes.Clear();
4206 aParams.mySteps = new TColStd_HSequenceOfReal;
4208 for(i=1; i<=theNbSteps; i++)
4209 aParams.mySteps->Append(theStep.Magnitude());
4212 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4216 //=======================================================================
4217 //function : ExtrusionSweep
4219 //=======================================================================
4221 SMESH_MeshEditor::PGroupIDs
4222 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4223 ExtrusParam& theParams,
4224 TElemOfElemListMap& newElemsMap,
4225 const bool theMakeGroups,
4227 const double theTolerance)
4229 myLastCreatedElems.Clear();
4230 myLastCreatedNodes.Clear();
4232 // source elements for each generated one
4233 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4235 SMESHDS_Mesh* aMesh = GetMeshDS();
4237 int nbsteps = theParams.mySteps->Length();
4239 TNodeOfNodeListMap mapNewNodes;
4240 //TNodeOfNodeVecMap mapNewNodes;
4241 TElemOfVecOfNnlmiMap mapElemNewNodes;
4242 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4245 TIDSortedElemSet::iterator itElem;
4246 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4247 // check element type
4248 const SMDS_MeshElement* elem = *itElem;
4249 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4252 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4253 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254 newNodesItVec.reserve( elem->NbNodes() );
4256 // loop on elem nodes
4257 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4258 while ( itN->more() )
4260 // check if a node has been already sweeped
4261 const SMDS_MeshNode* node = cast2Node( itN->next() );
4262 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4263 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4264 if ( nIt == mapNewNodes.end() ) {
4265 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4266 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4267 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4268 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4269 //vecNewNodes.reserve(nbsteps);
4272 double coord[] = { node->X(), node->Y(), node->Z() };
4273 //int nbsteps = theParams.mySteps->Length();
4274 for ( int i = 0; i < nbsteps; i++ ) {
4275 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4276 // create additional node
4277 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4278 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4279 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4280 if( theFlags & EXTRUSION_FLAG_SEW ) {
4281 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4282 theTolerance, theParams.myNodes);
4283 listNewNodes.push_back( newNode );
4286 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4287 myLastCreatedNodes.Append(newNode);
4288 srcNodes.Append( node );
4289 listNewNodes.push_back( newNode );
4292 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4293 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4294 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4295 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4296 if( theFlags & EXTRUSION_FLAG_SEW ) {
4297 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4298 theTolerance, theParams.myNodes);
4299 listNewNodes.push_back( newNode );
4300 //vecNewNodes[i]=newNode;
4303 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4304 myLastCreatedNodes.Append(newNode);
4305 srcNodes.Append( node );
4306 listNewNodes.push_back( newNode );
4307 //vecNewNodes[i]=newNode;
4312 // if current elem is quadratic and current node is not medium
4313 // we have to check - may be it is needed to insert additional nodes
4314 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4315 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4316 if(listNewNodes.size()==nbsteps) {
4317 listNewNodes.clear();
4318 double coord[] = { node->X(), node->Y(), node->Z() };
4319 for ( int i = 0; i < nbsteps; i++ ) {
4320 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4321 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4322 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4323 if( theFlags & EXTRUSION_FLAG_SEW ) {
4324 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4325 theTolerance, theParams.myNodes);
4326 listNewNodes.push_back( newNode );
4329 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4330 myLastCreatedNodes.Append(newNode);
4331 srcNodes.Append( node );
4332 listNewNodes.push_back( newNode );
4334 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4335 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4336 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4337 if( theFlags & EXTRUSION_FLAG_SEW ) {
4338 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4339 theTolerance, theParams.myNodes);
4340 listNewNodes.push_back( newNode );
4343 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4344 myLastCreatedNodes.Append(newNode);
4345 srcNodes.Append( node );
4346 listNewNodes.push_back( newNode );
4352 newNodesItVec.push_back( nIt );
4354 // make new elements
4355 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4358 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4359 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4361 PGroupIDs newGroupIDs;
4362 if ( theMakeGroups )
4363 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4369 //=======================================================================
4370 //class : SMESH_MeshEditor_PathPoint
4371 //purpose : auxiliary class
4372 //=======================================================================
4373 class SMESH_MeshEditor_PathPoint {
4375 SMESH_MeshEditor_PathPoint() {
4376 myPnt.SetCoord(99., 99., 99.);
4377 myTgt.SetCoord(1.,0.,0.);
4381 void SetPnt(const gp_Pnt& aP3D){
4384 void SetTangent(const gp_Dir& aTgt){
4387 void SetAngle(const double& aBeta){
4390 void SetParameter(const double& aPrm){
4393 const gp_Pnt& Pnt()const{
4396 const gp_Dir& Tangent()const{
4399 double Angle()const{
4402 double Parameter()const{
4414 //=======================================================================
4415 //function : ExtrusionAlongTrack
4417 //=======================================================================
4418 SMESH_MeshEditor::Extrusion_Error
4419 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4420 SMESH_subMesh* theTrack,
4421 const SMDS_MeshNode* theN1,
4422 const bool theHasAngles,
4423 list<double>& theAngles,
4424 const bool theLinearVariation,
4425 const bool theHasRefPoint,
4426 const gp_Pnt& theRefPoint,
4427 const bool theMakeGroups)
4429 myLastCreatedElems.Clear();
4430 myLastCreatedNodes.Clear();
4433 std::list<double> aPrms;
4434 TIDSortedElemSet::iterator itElem;
4437 TopoDS_Edge aTrackEdge;
4438 TopoDS_Vertex aV1, aV2;
4440 SMDS_ElemIteratorPtr aItE;
4441 SMDS_NodeIteratorPtr aItN;
4442 SMDSAbs_ElementType aTypeE;
4444 TNodeOfNodeListMap mapNewNodes;
4447 aNbE = theElements.size();
4450 return EXTR_NO_ELEMENTS;
4452 // 1.1 Track Pattern
4455 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4457 aItE = pSubMeshDS->GetElements();
4458 while ( aItE->more() ) {
4459 const SMDS_MeshElement* pE = aItE->next();
4460 aTypeE = pE->GetType();
4461 // Pattern must contain links only
4462 if ( aTypeE != SMDSAbs_Edge )
4463 return EXTR_PATH_NOT_EDGE;
4466 list<SMESH_MeshEditor_PathPoint> fullList;
4468 const TopoDS_Shape& aS = theTrack->GetSubShape();
4469 // Sub shape for the Pattern must be an Edge or Wire
4470 if( aS.ShapeType() == TopAbs_EDGE ) {
4471 aTrackEdge = TopoDS::Edge( aS );
4472 // the Edge must not be degenerated
4473 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4474 return EXTR_BAD_PATH_SHAPE;
4475 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4476 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4477 const SMDS_MeshNode* aN1 = aItN->next();
4478 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4479 const SMDS_MeshNode* aN2 = aItN->next();
4480 // starting node must be aN1 or aN2
4481 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4482 return EXTR_BAD_STARTING_NODE;
4483 aItN = pSubMeshDS->GetNodes();
4484 while ( aItN->more() ) {
4485 const SMDS_MeshNode* pNode = aItN->next();
4486 const SMDS_EdgePosition* pEPos =
4487 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4488 double aT = pEPos->GetUParameter();
4489 aPrms.push_back( aT );
4491 //Extrusion_Error err =
4492 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4494 else if( aS.ShapeType() == TopAbs_WIRE ) {
4495 list< SMESH_subMesh* > LSM;
4496 TopTools_SequenceOfShape Edges;
4497 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4498 while(itSM->more()) {
4499 SMESH_subMesh* SM = itSM->next();
4501 const TopoDS_Shape& aS = SM->GetSubShape();
4504 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4505 int startNid = theN1->GetID();
4506 TColStd_MapOfInteger UsedNums;
4507 int NbEdges = Edges.Length();
4509 for(; i<=NbEdges; i++) {
4511 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4512 for(; itLSM!=LSM.end(); itLSM++) {
4514 if(UsedNums.Contains(k)) continue;
4515 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4516 SMESH_subMesh* locTrack = *itLSM;
4517 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4518 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4519 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4520 const SMDS_MeshNode* aN1 = aItN->next();
4521 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4522 const SMDS_MeshNode* aN2 = aItN->next();
4523 // starting node must be aN1 or aN2
4524 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4525 // 2. Collect parameters on the track edge
4527 aItN = locMeshDS->GetNodes();
4528 while ( aItN->more() ) {
4529 const SMDS_MeshNode* pNode = aItN->next();
4530 const SMDS_EdgePosition* pEPos =
4531 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4532 double aT = pEPos->GetUParameter();
4533 aPrms.push_back( aT );
4535 list<SMESH_MeshEditor_PathPoint> LPP;
4536 //Extrusion_Error err =
4537 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4538 LLPPs.push_back(LPP);
4540 // update startN for search following egde
4541 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4542 else startNid = aN1->GetID();
4546 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4547 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4548 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4549 for(; itPP!=firstList.end(); itPP++) {
4550 fullList.push_back( *itPP );
4552 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4553 fullList.pop_back();
4555 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4556 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4557 itPP = currList.begin();
4558 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4559 gp_Dir D1 = PP1.Tangent();
4560 gp_Dir D2 = PP2.Tangent();
4561 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4562 (D1.Z()+D2.Z())/2 ) );
4563 PP1.SetTangent(Dnew);
4564 fullList.push_back(PP1);
4566 for(; itPP!=firstList.end(); itPP++) {
4567 fullList.push_back( *itPP );
4569 PP1 = fullList.back();
4570 fullList.pop_back();
4572 // if wire not closed
4573 fullList.push_back(PP1);
4577 return EXTR_BAD_PATH_SHAPE;
4580 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4581 theHasRefPoint, theRefPoint, theMakeGroups);
4585 //=======================================================================
4586 //function : ExtrusionAlongTrack
4588 //=======================================================================
4589 SMESH_MeshEditor::Extrusion_Error
4590 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4591 SMESH_Mesh* theTrack,
4592 const SMDS_MeshNode* theN1,
4593 const bool theHasAngles,
4594 list<double>& theAngles,
4595 const bool theLinearVariation,
4596 const bool theHasRefPoint,
4597 const gp_Pnt& theRefPoint,
4598 const bool theMakeGroups)
4600 myLastCreatedElems.Clear();
4601 myLastCreatedNodes.Clear();
4604 std::list<double> aPrms;
4605 TIDSortedElemSet::iterator itElem;
4608 TopoDS_Edge aTrackEdge;
4609 TopoDS_Vertex aV1, aV2;
4611 SMDS_ElemIteratorPtr aItE;
4612 SMDS_NodeIteratorPtr aItN;
4613 SMDSAbs_ElementType aTypeE;
4615 TNodeOfNodeListMap mapNewNodes;
4618 aNbE = theElements.size();
4621 return EXTR_NO_ELEMENTS;
4623 // 1.1 Track Pattern
4626 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4628 aItE = pMeshDS->elementsIterator();
4629 while ( aItE->more() ) {
4630 const SMDS_MeshElement* pE = aItE->next();
4631 aTypeE = pE->GetType();
4632 // Pattern must contain links only
4633 if ( aTypeE != SMDSAbs_Edge )
4634 return EXTR_PATH_NOT_EDGE;
4637 list<SMESH_MeshEditor_PathPoint> fullList;
4639 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4640 // Sub shape for the Pattern must be an Edge or Wire
4641 if( aS.ShapeType() == TopAbs_EDGE ) {
4642 aTrackEdge = TopoDS::Edge( aS );
4643 // the Edge must not be degenerated
4644 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4645 return EXTR_BAD_PATH_SHAPE;
4646 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4647 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4648 const SMDS_MeshNode* aN1 = aItN->next();
4649 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4650 const SMDS_MeshNode* aN2 = aItN->next();
4651 // starting node must be aN1 or aN2
4652 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4653 return EXTR_BAD_STARTING_NODE;
4654 aItN = pMeshDS->nodesIterator();
4655 while ( aItN->more() ) {
4656 const SMDS_MeshNode* pNode = aItN->next();
4657 if( pNode==aN1 || pNode==aN2 ) continue;
4658 const SMDS_EdgePosition* pEPos =
4659 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4660 double aT = pEPos->GetUParameter();
4661 aPrms.push_back( aT );
4663 //Extrusion_Error err =
4664 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4666 else if( aS.ShapeType() == TopAbs_WIRE ) {
4667 list< SMESH_subMesh* > LSM;
4668 TopTools_SequenceOfShape Edges;
4669 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4670 for(; eExp.More(); eExp.Next()) {
4671 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4672 if( BRep_Tool::Degenerated(E) ) continue;
4673 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4679 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4680 int startNid = theN1->GetID();
4681 TColStd_MapOfInteger UsedNums;
4682 int NbEdges = Edges.Length();
4684 for(; i<=NbEdges; i++) {
4686 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4687 for(; itLSM!=LSM.end(); itLSM++) {
4689 if(UsedNums.Contains(k)) continue;
4690 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4691 SMESH_subMesh* locTrack = *itLSM;
4692 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4693 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4694 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4695 const SMDS_MeshNode* aN1 = aItN->next();
4696 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4697 const SMDS_MeshNode* aN2 = aItN->next();
4698 // starting node must be aN1 or aN2
4699 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4700 // 2. Collect parameters on the track edge
4702 aItN = locMeshDS->GetNodes();
4703 while ( aItN->more() ) {
4704 const SMDS_MeshNode* pNode = aItN->next();
4705 const SMDS_EdgePosition* pEPos =
4706 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4707 double aT = pEPos->GetUParameter();
4708 aPrms.push_back( aT );
4710 list<SMESH_MeshEditor_PathPoint> LPP;
4711 //Extrusion_Error err =
4712 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4713 LLPPs.push_back(LPP);
4715 // update startN for search following egde
4716 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4717 else startNid = aN1->GetID();
4721 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4722 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4723 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4724 for(; itPP!=firstList.end(); itPP++) {
4725 fullList.push_back( *itPP );
4727 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4728 fullList.pop_back();
4730 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4731 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4732 itPP = currList.begin();
4733 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4734 gp_Pnt P1 = PP1.Pnt();
4735 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4736 gp_Pnt P2 = PP2.Pnt();
4737 gp_Dir D1 = PP1.Tangent();
4738 gp_Dir D2 = PP2.Tangent();
4739 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4740 (D1.Z()+D2.Z())/2 ) );
4741 PP1.SetTangent(Dnew);
4742 fullList.push_back(PP1);
4744 for(; itPP!=currList.end(); itPP++) {
4745 fullList.push_back( *itPP );
4747 PP1 = fullList.back();
4748 fullList.pop_back();
4750 // if wire not closed
4751 fullList.push_back(PP1);
4755 return EXTR_BAD_PATH_SHAPE;
4758 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4759 theHasRefPoint, theRefPoint, theMakeGroups);
4763 //=======================================================================
4764 //function : MakeEdgePathPoints
4765 //purpose : auxilary for ExtrusionAlongTrack
4766 //=======================================================================
4767 SMESH_MeshEditor::Extrusion_Error
4768 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4769 const TopoDS_Edge& aTrackEdge,
4771 list<SMESH_MeshEditor_PathPoint>& LPP)
4773 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4775 aTolVec2=aTolVec*aTolVec;
4777 TopoDS_Vertex aV1, aV2;
4778 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4779 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4780 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4781 // 2. Collect parameters on the track edge
4782 aPrms.push_front( aT1 );
4783 aPrms.push_back( aT2 );
4786 if( FirstIsStart ) {
4797 SMESH_MeshEditor_PathPoint aPP;
4798 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4799 std::list<double>::iterator aItD = aPrms.begin();
4800 for(; aItD != aPrms.end(); ++aItD) {
4804 aC3D->D1( aT, aP3D, aVec );
4805 aL2 = aVec.SquareMagnitude();
4806 if ( aL2 < aTolVec2 )
4807 return EXTR_CANT_GET_TANGENT;
4808 gp_Dir aTgt( aVec );
4810 aPP.SetTangent( aTgt );
4811 aPP.SetParameter( aT );
4818 //=======================================================================
4819 //function : MakeExtrElements
4820 //purpose : auxilary for ExtrusionAlongTrack
4821 //=======================================================================
4822 SMESH_MeshEditor::Extrusion_Error
4823 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4824 list<SMESH_MeshEditor_PathPoint>& fullList,
4825 const bool theHasAngles,
4826 list<double>& theAngles,
4827 const bool theLinearVariation,
4828 const bool theHasRefPoint,
4829 const gp_Pnt& theRefPoint,
4830 const bool theMakeGroups)
4832 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4833 int aNbTP = fullList.size();
4834 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4836 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4837 LinearAngleVariation(aNbTP-1, theAngles);
4839 vector<double> aAngles( aNbTP );
4841 for(; j<aNbTP; ++j) {
4844 if ( theHasAngles ) {
4846 std::list<double>::iterator aItD = theAngles.begin();
4847 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4849 aAngles[j] = anAngle;
4852 // fill vector of path points with angles
4853 //aPPs.resize(fullList.size());
4855 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4856 for(; itPP!=fullList.end(); itPP++) {
4858 SMESH_MeshEditor_PathPoint PP = *itPP;
4859 PP.SetAngle(aAngles[j]);
4863 TNodeOfNodeListMap mapNewNodes;
4864 TElemOfVecOfNnlmiMap mapElemNewNodes;
4865 TElemOfElemListMap newElemsMap;
4866 TIDSortedElemSet::iterator itElem;
4869 SMDSAbs_ElementType aTypeE;
4870 // source elements for each generated one
4871 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4873 // 3. Center of rotation aV0
4874 gp_Pnt aV0 = theRefPoint;
4876 if ( !theHasRefPoint ) {
4878 aGC.SetCoord( 0.,0.,0. );
4880 itElem = theElements.begin();
4881 for ( ; itElem != theElements.end(); itElem++ ) {
4882 const SMDS_MeshElement* elem = *itElem;
4884 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4885 while ( itN->more() ) {
4886 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4891 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4892 list<const SMDS_MeshNode*> aLNx;
4893 mapNewNodes[node] = aLNx;
4895 gp_XYZ aXYZ( aX, aY, aZ );
4903 } // if (!theHasRefPoint) {
4904 mapNewNodes.clear();
4906 // 4. Processing the elements
4907 SMESHDS_Mesh* aMesh = GetMeshDS();
4909 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4910 // check element type
4911 const SMDS_MeshElement* elem = *itElem;
4912 aTypeE = elem->GetType();
4913 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4916 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4917 newNodesItVec.reserve( elem->NbNodes() );
4919 // loop on elem nodes
4921 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4922 while ( itN->more() )
4925 // check if a node has been already processed
4926 const SMDS_MeshNode* node =
4927 static_cast<const SMDS_MeshNode*>( itN->next() );
4928 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4929 if ( nIt == mapNewNodes.end() ) {
4930 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4931 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4934 aX = node->X(); aY = node->Y(); aZ = node->Z();
4936 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4937 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4938 gp_Ax1 anAx1, anAxT1T0;
4939 gp_Dir aDT1x, aDT0x, aDT1T0;
4944 aPN0.SetCoord(aX, aY, aZ);
4946 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4948 aDT0x= aPP0.Tangent();
4949 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4951 for ( j = 1; j < aNbTP; ++j ) {
4952 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4954 aDT1x = aPP1.Tangent();
4955 aAngle1x = aPP1.Angle();
4957 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4959 gp_Vec aV01x( aP0x, aP1x );
4960 aTrsf.SetTranslation( aV01x );
4963 aV1x = aV0x.Transformed( aTrsf );
4964 aPN1 = aPN0.Transformed( aTrsf );
4966 // rotation 1 [ T1,T0 ]
4967 aAngleT1T0=-aDT1x.Angle( aDT0x );
4968 if (fabs(aAngleT1T0) > aTolAng) {
4970 anAxT1T0.SetLocation( aV1x );
4971 anAxT1T0.SetDirection( aDT1T0 );
4972 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4974 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4978 if ( theHasAngles ) {
4979 anAx1.SetLocation( aV1x );
4980 anAx1.SetDirection( aDT1x );
4981 aTrsfRot.SetRotation( anAx1, aAngle1x );
4983 aPN1 = aPN1.Transformed( aTrsfRot );
4987 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4988 // create additional node
4989 double x = ( aPN1.X() + aPN0.X() )/2.;
4990 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4991 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4992 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4993 myLastCreatedNodes.Append(newNode);
4994 srcNodes.Append( node );
4995 listNewNodes.push_back( newNode );
5000 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5001 myLastCreatedNodes.Append(newNode);
5002 srcNodes.Append( node );
5003 listNewNodes.push_back( newNode );
5013 // if current elem is quadratic and current node is not medium
5014 // we have to check - may be it is needed to insert additional nodes
5015 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5016 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5017 if(listNewNodes.size()==aNbTP-1) {
5018 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5019 gp_XYZ P(node->X(), node->Y(), node->Z());
5020 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5022 for(i=0; i<aNbTP-1; i++) {
5023 const SMDS_MeshNode* N = *it;
5024 double x = ( N->X() + P.X() )/2.;
5025 double y = ( N->Y() + P.Y() )/2.;
5026 double z = ( N->Z() + P.Z() )/2.;
5027 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5028 srcNodes.Append( node );
5029 myLastCreatedNodes.Append(newN);
5032 P = gp_XYZ(N->X(),N->Y(),N->Z());
5034 listNewNodes.clear();
5035 for(i=0; i<2*(aNbTP-1); i++) {
5036 listNewNodes.push_back(aNodes[i]);
5042 newNodesItVec.push_back( nIt );
5044 // make new elements
5045 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5046 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5047 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5050 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5052 if ( theMakeGroups )
5053 generateGroups( srcNodes, srcElems, "extruded");
5059 //=======================================================================
5060 //function : LinearAngleVariation
5061 //purpose : auxilary for ExtrusionAlongTrack
5062 //=======================================================================
5063 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5064 list<double>& Angles)
5066 int nbAngles = Angles.size();
5067 if( nbSteps > nbAngles ) {
5068 vector<double> theAngles(nbAngles);
5069 list<double>::iterator it = Angles.begin();
5071 for(; it!=Angles.end(); it++) {
5073 theAngles[i] = (*it);
5076 double rAn2St = double( nbAngles ) / double( nbSteps );
5077 double angPrev = 0, angle;
5078 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5079 double angCur = rAn2St * ( iSt+1 );
5080 double angCurFloor = floor( angCur );
5081 double angPrevFloor = floor( angPrev );
5082 if ( angPrevFloor == angCurFloor )
5083 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5085 int iP = int( angPrevFloor );
5086 double angPrevCeil = ceil(angPrev);
5087 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5089 int iC = int( angCurFloor );
5090 if ( iC < nbAngles )
5091 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5093 iP = int( angPrevCeil );
5095 angle += theAngles[ iC ];
5097 res.push_back(angle);
5102 for(; it!=res.end(); it++)
5103 Angles.push_back( *it );
5108 //=======================================================================
5109 //function : Transform
5111 //=======================================================================
5113 SMESH_MeshEditor::PGroupIDs
5114 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5115 const gp_Trsf& theTrsf,
5117 const bool theMakeGroups,
5118 SMESH_Mesh* theTargetMesh)
5120 myLastCreatedElems.Clear();
5121 myLastCreatedNodes.Clear();
5123 bool needReverse = false;
5124 string groupPostfix;
5125 switch ( theTrsf.Form() ) {
5130 groupPostfix = "mirrored";
5133 groupPostfix = "rotated";
5135 case gp_Translation:
5136 groupPostfix = "translated";
5139 groupPostfix = "scaled";
5142 needReverse = false;
5143 groupPostfix = "transformed";
5146 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5147 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5148 SMESHDS_Mesh* aMesh = GetMeshDS();
5151 // map old node to new one
5152 TNodeNodeMap nodeMap;
5154 // elements sharing moved nodes; those of them which have all
5155 // nodes mirrored but are not in theElems are to be reversed
5156 TIDSortedElemSet inverseElemSet;
5158 // source elements for each generated one
5159 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5162 TIDSortedElemSet::iterator itElem;
5163 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5164 const SMDS_MeshElement* elem = *itElem;
5168 // loop on elem nodes
5169 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5170 while ( itN->more() ) {
5172 // check if a node has been already transformed
5173 const SMDS_MeshNode* node = cast2Node( itN->next() );
5174 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5175 nodeMap.insert( make_pair ( node, node ));
5176 if ( !n2n_isnew.second )
5180 coord[0] = node->X();
5181 coord[1] = node->Y();
5182 coord[2] = node->Z();
5183 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5184 if ( theTargetMesh ) {
5185 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5186 n2n_isnew.first->second = newNode;
5187 myLastCreatedNodes.Append(newNode);
5188 srcNodes.Append( node );
5190 else if ( theCopy ) {
5191 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5192 n2n_isnew.first->second = newNode;
5193 myLastCreatedNodes.Append(newNode);
5194 srcNodes.Append( node );
5197 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5198 // node position on shape becomes invalid
5199 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5200 ( SMDS_SpacePosition::originSpacePosition() );
5203 // keep inverse elements
5204 if ( !theCopy && !theTargetMesh && needReverse ) {
5205 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5206 while ( invElemIt->more() ) {
5207 const SMDS_MeshElement* iel = invElemIt->next();
5208 inverseElemSet.insert( iel );
5214 // either create new elements or reverse mirrored ones
5215 if ( !theCopy && !needReverse && !theTargetMesh )
5218 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5219 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5220 theElems.insert( *invElemIt );
5222 // replicate or reverse elements
5225 REV_TETRA = 0, // = nbNodes - 4
5226 REV_PYRAMID = 1, // = nbNodes - 4
5227 REV_PENTA = 2, // = nbNodes - 4
5229 REV_HEXA = 4, // = nbNodes - 4
5233 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5234 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5235 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5236 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5237 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5238 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5241 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5243 const SMDS_MeshElement* elem = *itElem;
5244 if ( !elem || elem->GetType() == SMDSAbs_Node )
5247 int nbNodes = elem->NbNodes();
5248 int elemType = elem->GetType();
5250 if (elem->IsPoly()) {
5251 // Polygon or Polyhedral Volume
5252 switch ( elemType ) {
5255 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5257 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5258 while (itN->more()) {
5259 const SMDS_MeshNode* node =
5260 static_cast<const SMDS_MeshNode*>(itN->next());
5261 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5262 if (nodeMapIt == nodeMap.end())
5263 break; // not all nodes transformed
5265 // reverse mirrored faces and volumes
5266 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5268 poly_nodes[iNode] = (*nodeMapIt).second;
5272 if ( iNode != nbNodes )
5273 continue; // not all nodes transformed
5275 if ( theTargetMesh ) {
5276 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5277 srcElems.Append( elem );
5279 else if ( theCopy ) {
5280 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5281 srcElems.Append( elem );
5284 aMesh->ChangePolygonNodes(elem, poly_nodes);
5288 case SMDSAbs_Volume:
5290 // ATTENTION: Reversing is not yet done!!!
5291 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5292 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5294 MESSAGE("Warning: bad volumic element");
5298 vector<const SMDS_MeshNode*> poly_nodes;
5299 vector<int> quantities;
5301 bool allTransformed = true;
5302 int nbFaces = aPolyedre->NbFaces();
5303 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5304 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5305 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5306 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5307 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5308 if (nodeMapIt == nodeMap.end()) {
5309 allTransformed = false; // not all nodes transformed
5311 poly_nodes.push_back((*nodeMapIt).second);
5314 quantities.push_back(nbFaceNodes);
5316 if ( !allTransformed )
5317 continue; // not all nodes transformed
5319 if ( theTargetMesh ) {
5320 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5321 srcElems.Append( elem );
5323 else if ( theCopy ) {
5324 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5325 srcElems.Append( elem );
5328 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5338 int* i = index[ FORWARD ];
5339 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5340 if ( elemType == SMDSAbs_Face )
5341 i = index[ REV_FACE ];
5343 i = index[ nbNodes - 4 ];
5345 if(elem->IsQuadratic()) {
5346 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5349 if(nbNodes==3) { // quadratic edge
5350 static int anIds[] = {1,0,2};
5353 else if(nbNodes==6) { // quadratic triangle
5354 static int anIds[] = {0,2,1,5,4,3};
5357 else if(nbNodes==8) { // quadratic quadrangle
5358 static int anIds[] = {0,3,2,1,7,6,5,4};
5361 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5362 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5365 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5366 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5369 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5370 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5373 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5374 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5380 // find transformed nodes
5381 vector<const SMDS_MeshNode*> nodes(nbNodes);
5383 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5384 while ( itN->more() ) {
5385 const SMDS_MeshNode* node =
5386 static_cast<const SMDS_MeshNode*>( itN->next() );
5387 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5388 if ( nodeMapIt == nodeMap.end() )
5389 break; // not all nodes transformed
5390 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5392 if ( iNode != nbNodes )
5393 continue; // not all nodes transformed
5395 if ( theTargetMesh ) {
5396 if ( SMDS_MeshElement* copy =
5397 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5398 myLastCreatedElems.Append( copy );
5399 srcElems.Append( elem );
5402 else if ( theCopy ) {
5403 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5404 myLastCreatedElems.Append( copy );
5405 srcElems.Append( elem );
5409 // reverse element as it was reversed by transformation
5411 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5415 PGroupIDs newGroupIDs;
5417 if ( theMakeGroups && theCopy ||
5418 theMakeGroups && theTargetMesh )
5419 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5425 //=======================================================================
5428 //=======================================================================
5430 SMESH_MeshEditor::PGroupIDs
5431 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5432 const gp_Pnt& thePoint,
5433 const std::list<double>& theScaleFact,
5435 const bool theMakeGroups,
5436 SMESH_Mesh* theTargetMesh)
5438 myLastCreatedElems.Clear();
5439 myLastCreatedNodes.Clear();
5441 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5442 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5443 SMESHDS_Mesh* aMesh = GetMeshDS();
5445 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5446 std::list<double>::const_iterator itS = theScaleFact.begin();
5448 if(theScaleFact.size()==1) {
5452 if(theScaleFact.size()==2) {
5457 if(theScaleFact.size()>2) {
5464 // map old node to new one
5465 TNodeNodeMap nodeMap;
5467 // elements sharing moved nodes; those of them which have all
5468 // nodes mirrored but are not in theElems are to be reversed
5469 TIDSortedElemSet inverseElemSet;
5471 // source elements for each generated one
5472 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5475 TIDSortedElemSet::iterator itElem;
5476 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5477 const SMDS_MeshElement* elem = *itElem;
5481 // loop on elem nodes
5482 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5483 while ( itN->more() ) {
5485 // check if a node has been already transformed
5486 const SMDS_MeshNode* node = cast2Node( itN->next() );
5487 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5488 nodeMap.insert( make_pair ( node, node ));
5489 if ( !n2n_isnew.second )
5493 //coord[0] = node->X();
5494 //coord[1] = node->Y();
5495 //coord[2] = node->Z();
5496 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5497 double dx = (node->X() - thePoint.X()) * scaleX;
5498 double dy = (node->Y() - thePoint.Y()) * scaleY;
5499 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5500 if ( theTargetMesh ) {
5501 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5502 const SMDS_MeshNode * newNode =
5503 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5504 n2n_isnew.first->second = newNode;
5505 myLastCreatedNodes.Append(newNode);
5506 srcNodes.Append( node );
5508 else if ( theCopy ) {
5509 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5510 const SMDS_MeshNode * newNode =
5511 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5512 n2n_isnew.first->second = newNode;
5513 myLastCreatedNodes.Append(newNode);
5514 srcNodes.Append( node );
5517 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5518 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5519 // node position on shape becomes invalid
5520 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5521 ( SMDS_SpacePosition::originSpacePosition() );
5524 // keep inverse elements
5525 //if ( !theCopy && !theTargetMesh && needReverse ) {
5526 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5527 // while ( invElemIt->more() ) {
5528 // const SMDS_MeshElement* iel = invElemIt->next();
5529 // inverseElemSet.insert( iel );
5535 // either create new elements or reverse mirrored ones
5536 //if ( !theCopy && !needReverse && !theTargetMesh )
5537 if ( !theCopy && !theTargetMesh )
5540 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5541 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5542 theElems.insert( *invElemIt );
5544 // replicate or reverse elements
5547 REV_TETRA = 0, // = nbNodes - 4
5548 REV_PYRAMID = 1, // = nbNodes - 4
5549 REV_PENTA = 2, // = nbNodes - 4
5551 REV_HEXA = 4, // = nbNodes - 4
5555 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5556 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5557 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5558 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5559 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5560 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5563 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5565 const SMDS_MeshElement* elem = *itElem;
5566 if ( !elem || elem->GetType() == SMDSAbs_Node )
5569 int nbNodes = elem->NbNodes();
5570 int elemType = elem->GetType();
5572 if (elem->IsPoly()) {
5573 // Polygon or Polyhedral Volume
5574 switch ( elemType ) {
5577 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5579 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5580 while (itN->more()) {
5581 const SMDS_MeshNode* node =
5582 static_cast<const SMDS_MeshNode*>(itN->next());
5583 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5584 if (nodeMapIt == nodeMap.end())
5585 break; // not all nodes transformed
5586 //if (needReverse) {
5587 // // reverse mirrored faces and volumes
5588 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5590 poly_nodes[iNode] = (*nodeMapIt).second;
5594 if ( iNode != nbNodes )
5595 continue; // not all nodes transformed
5597 if ( theTargetMesh ) {
5598 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5599 srcElems.Append( elem );
5601 else if ( theCopy ) {
5602 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5603 srcElems.Append( elem );
5606 aMesh->ChangePolygonNodes(elem, poly_nodes);
5610 case SMDSAbs_Volume:
5612 // ATTENTION: Reversing is not yet done!!!
5613 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5614 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5616 MESSAGE("Warning: bad volumic element");
5620 vector<const SMDS_MeshNode*> poly_nodes;
5621 vector<int> quantities;
5623 bool allTransformed = true;
5624 int nbFaces = aPolyedre->NbFaces();
5625 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5626 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5627 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5628 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5629 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5630 if (nodeMapIt == nodeMap.end()) {
5631 allTransformed = false; // not all nodes transformed
5633 poly_nodes.push_back((*nodeMapIt).second);
5636 quantities.push_back(nbFaceNodes);
5638 if ( !allTransformed )
5639 continue; // not all nodes transformed
5641 if ( theTargetMesh ) {
5642 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5643 srcElems.Append( elem );
5645 else if ( theCopy ) {
5646 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5647 srcElems.Append( elem );
5650 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5660 int* i = index[ FORWARD ];
5661 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5662 // if ( elemType == SMDSAbs_Face )
5663 // i = index[ REV_FACE ];
5665 // i = index[ nbNodes - 4 ];
5667 if(elem->IsQuadratic()) {
5668 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5671 // if(nbNodes==3) { // quadratic edge
5672 // static int anIds[] = {1,0,2};
5675 // else if(nbNodes==6) { // quadratic triangle
5676 // static int anIds[] = {0,2,1,5,4,3};
5679 // else if(nbNodes==8) { // quadratic quadrangle
5680 // static int anIds[] = {0,3,2,1,7,6,5,4};
5683 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5684 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5687 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5688 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5691 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5692 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5695 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5696 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5702 // find transformed nodes
5703 vector<const SMDS_MeshNode*> nodes(nbNodes);
5705 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5706 while ( itN->more() ) {
5707 const SMDS_MeshNode* node =
5708 static_cast<const SMDS_MeshNode*>( itN->next() );
5709 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5710 if ( nodeMapIt == nodeMap.end() )
5711 break; // not all nodes transformed
5712 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5714 if ( iNode != nbNodes )
5715 continue; // not all nodes transformed
5717 if ( theTargetMesh ) {
5718 if ( SMDS_MeshElement* copy =
5719 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5720 myLastCreatedElems.Append( copy );
5721 srcElems.Append( elem );
5724 else if ( theCopy ) {
5725 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5726 myLastCreatedElems.Append( copy );
5727 srcElems.Append( elem );
5731 // reverse element as it was reversed by transformation
5733 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5737 PGroupIDs newGroupIDs;
5739 if ( theMakeGroups && theCopy ||
5740 theMakeGroups && theTargetMesh ) {
5741 string groupPostfix = "scaled";
5742 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5749 //=======================================================================
5751 * \brief Create groups of elements made during transformation
5752 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5753 * \param elemGens - elements making corresponding myLastCreatedElems
5754 * \param postfix - to append to names of new groups
5756 //=======================================================================
5758 SMESH_MeshEditor::PGroupIDs
5759 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5760 const SMESH_SequenceOfElemPtr& elemGens,
5761 const std::string& postfix,
5762 SMESH_Mesh* targetMesh)
5764 PGroupIDs newGroupIDs( new list<int> );
5765 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5767 // Sort existing groups by types and collect their names
5769 // to store an old group and a generated new one
5770 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5771 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5773 set< string > groupNames;
5775 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5776 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5777 while ( groupIt->more() ) {
5778 SMESH_Group * group = groupIt->next();
5779 if ( !group ) continue;
5780 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5781 if ( !groupDS || groupDS->IsEmpty() ) continue;
5782 groupNames.insert( group->GetName() );
5783 groupDS->SetStoreName( group->GetName() );
5784 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5789 // loop on nodes and elements
5790 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5792 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5793 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5794 if ( gens.Length() != elems.Length() )
5795 throw SALOME_Exception(LOCALIZED("invalid args"));
5797 // loop on created elements
5798 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5800 const SMDS_MeshElement* sourceElem = gens( iElem );
5801 if ( !sourceElem ) {
5802 MESSAGE("generateGroups(): NULL source element");
5805 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5806 if ( groupsOldNew.empty() ) {
5807 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5808 ++iElem; // skip all elements made by sourceElem
5811 // collect all elements made by sourceElem
5812 list< const SMDS_MeshElement* > resultElems;
5813 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5814 if ( resElem != sourceElem )
5815 resultElems.push_back( resElem );
5816 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5817 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5818 if ( resElem != sourceElem )
5819 resultElems.push_back( resElem );
5820 // do not generate element groups from node ones
5821 if ( sourceElem->GetType() == SMDSAbs_Node &&
5822 elems( iElem )->GetType() != SMDSAbs_Node )
5825 // add resultElems to groups made by ones the sourceElem belongs to
5826 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5827 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5829 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5830 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5832 SMDS_MeshGroup* & newGroup = gOldNew->second;
5833 if ( !newGroup )// create a new group
5836 string name = oldGroup->GetStoreName();
5837 if ( !targetMesh ) {
5841 while ( !groupNames.insert( name ).second ) // name exists
5847 TCollection_AsciiString nbStr(nb+1);
5848 name.resize( name.rfind('_')+1 );
5849 name += nbStr.ToCString();
5856 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5858 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5859 newGroup = & groupDS->SMDSGroup();
5860 newGroupIDs->push_back( id );
5863 // fill in a new group
5864 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5865 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5866 newGroup->Add( *resElemIt );
5869 } // loop on created elements
5870 }// loop on nodes and elements
5875 //================================================================================
5877 * \brief Return list of group of nodes close to each other within theTolerance
5878 * Search among theNodes or in the whole mesh if theNodes is empty using
5879 * an Octree algorithm
5881 //================================================================================
5883 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5884 const double theTolerance,
5885 TListOfListOfNodes & theGroupsOfNodes)
5887 myLastCreatedElems.Clear();
5888 myLastCreatedNodes.Clear();
5890 set<const SMDS_MeshNode*> nodes;
5891 if ( theNodes.empty() )
5892 { // get all nodes in the mesh
5893 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5894 while ( nIt->more() )
5895 nodes.insert( nodes.end(),nIt->next());
5900 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5904 //=======================================================================
5906 * \brief Implementation of search for the node closest to point
5908 //=======================================================================
5910 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5912 //---------------------------------------------------------------------
5914 * \brief Constructor
5916 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5918 myMesh = ( SMESHDS_Mesh* ) theMesh;
5920 set<const SMDS_MeshNode*> nodes;
5922 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5923 while ( nIt->more() )
5924 nodes.insert( nodes.end(), nIt->next() );
5926 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5928 // get max size of a leaf box
5929 SMESH_OctreeNode* tree = myOctreeNode;
5930 while ( !tree->isLeaf() )
5932 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5936 myHalfLeafSize = tree->maxSize() / 2.;
5939 //---------------------------------------------------------------------
5941 * \brief Move node and update myOctreeNode accordingly
5943 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5945 myOctreeNode->UpdateByMoveNode( node, toPnt );
5946 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5949 //---------------------------------------------------------------------
5951 * \brief Do it's job
5953 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5955 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5956 map<double, const SMDS_MeshNode*> dist2Nodes;
5957 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5958 if ( !dist2Nodes.empty() )
5959 return dist2Nodes.begin()->second;
5960 list<const SMDS_MeshNode*> nodes;
5961 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5963 double minSqDist = DBL_MAX;
5964 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5966 // sort leafs by their distance from thePnt
5967 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5968 TDistTreeMap treeMap;
5969 list< SMESH_OctreeNode* > treeList;
5970 list< SMESH_OctreeNode* >::iterator trIt;
5971 treeList.push_back( myOctreeNode );
5973 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5974 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5976 SMESH_OctreeNode* tree = *trIt;
5977 if ( !tree->isLeaf() ) // put children to the queue
5979 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5980 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5981 while ( cIt->more() )
5982 treeList.push_back( cIt->next() );
5984 else if ( tree->NbNodes() ) // put a tree to the treeMap
5986 const Bnd_B3d& box = tree->getBox();
5987 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5988 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5989 if ( !it_in.second ) // not unique distance to box center
5990 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5993 // find distance after which there is no sense to check tree's
5994 double sqLimit = DBL_MAX;
5995 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5996 if ( treeMap.size() > 5 ) {
5997 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5998 const Bnd_B3d& box = closestTree->getBox();
5999 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6000 sqLimit = limit * limit;
6002 // get all nodes from trees
6003 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6004 if ( sqDist_tree->first > sqLimit )
6006 SMESH_OctreeNode* tree = sqDist_tree->second;
6007 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6010 // find closest among nodes
6011 minSqDist = DBL_MAX;
6012 const SMDS_MeshNode* closestNode = 0;
6013 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6014 for ( ; nIt != nodes.end(); ++nIt ) {
6015 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6016 if ( minSqDist > sqDist ) {
6024 //---------------------------------------------------------------------
6028 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6030 //---------------------------------------------------------------------
6032 * \brief Return the node tree
6034 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6037 SMESH_OctreeNode* myOctreeNode;
6038 SMESHDS_Mesh* myMesh;
6039 double myHalfLeafSize; // max size of a leaf box
6042 //=======================================================================
6044 * \brief Return SMESH_NodeSearcher
6046 //=======================================================================
6048 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6050 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6053 // ========================================================================
6054 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6056 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6057 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6058 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6060 //=======================================================================
6062 * \brief Octal tree of bounding boxes of elements
6064 //=======================================================================
6066 class ElementBndBoxTree : public SMESH_Octree
6070 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6071 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6072 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6073 ~ElementBndBoxTree();
6076 ElementBndBoxTree() {}
6077 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6078 void buildChildrenData();
6079 Bnd_B3d* buildRootBox();
6081 //!< Bounding box of element
6082 struct ElementBox : public Bnd_B3d
6084 const SMDS_MeshElement* _element;
6085 int _refCount; // an ElementBox can be included in several tree branches
6086 ElementBox(const SMDS_MeshElement* elem);
6088 vector< ElementBox* > _elements;
6091 //================================================================================
6093 * \brief ElementBndBoxTree creation
6095 //================================================================================
6097 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6098 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6100 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6101 _elements.reserve( nbElems );
6103 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6104 while ( elemIt->more() )
6105 _elements.push_back( new ElementBox( elemIt->next() ));
6107 if ( _elements.size() > MaxNbElemsInLeaf )
6113 //================================================================================
6117 //================================================================================
6119 ElementBndBoxTree::~ElementBndBoxTree()
6121 for ( int i = 0; i < _elements.size(); ++i )
6122 if ( --_elements[i]->_refCount <= 0 )
6123 delete _elements[i];
6126 //================================================================================
6128 * \brief Return the maximal box
6130 //================================================================================
6132 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6134 Bnd_B3d* box = new Bnd_B3d;
6135 for ( int i = 0; i < _elements.size(); ++i )
6136 box->Add( *_elements[i] );
6140 //================================================================================
6142 * \brief Redistrubute element boxes among children
6144 //================================================================================
6146 void ElementBndBoxTree::buildChildrenData()
6148 for ( int i = 0; i < _elements.size(); ++i )
6150 for (int j = 0; j < 8; j++)
6152 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6154 _elements[i]->_refCount++;
6155 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6158 _elements[i]->_refCount--;
6162 for (int j = 0; j < 8; j++)
6164 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6165 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6166 child->myIsLeaf = true;
6168 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6169 child->_elements.resize( child->_elements.size() ); // compact
6173 //================================================================================
6175 * \brief Return elements which can include the point
6177 //================================================================================
6179 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6180 TIDSortedElemSet& foundElems)
6182 if ( level() && getBox().IsOut( point.XYZ() ))
6187 for ( int i = 0; i < _elements.size(); ++i )
6188 if ( !_elements[i]->IsOut( point.XYZ() ))
6189 foundElems.insert( _elements[i]->_element );
6193 for (int i = 0; i < 8; i++)
6194 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6198 //================================================================================
6200 * \brief Return elements which can be intersected by the line
6202 //================================================================================
6204 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6205 TIDSortedElemSet& foundElems)
6207 if ( level() && getBox().IsOut( line ))
6212 for ( int i = 0; i < _elements.size(); ++i )
6213 if ( !_elements[i]->IsOut( line ))
6214 foundElems.insert( _elements[i]->_element );
6218 for (int i = 0; i < 8; i++)
6219 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6223 //================================================================================
6225 * \brief Construct the element box
6227 //================================================================================
6229 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6233 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6234 while ( nIt->more() )
6235 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6236 Enlarge( NodeRadius );
6241 //=======================================================================
6243 * \brief Implementation of search for the elements by point and
6244 * of classification of point in 2D mesh
6246 //=======================================================================
6248 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6250 SMESHDS_Mesh* _mesh;
6251 ElementBndBoxTree* _ebbTree;
6252 SMESH_NodeSearcherImpl* _nodeSearcher;
6253 SMDSAbs_ElementType _elementType;
6255 bool _outerFacesFound;
6256 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6258 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6259 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6260 ~SMESH_ElementSearcherImpl()
6262 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6263 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6265 virtual int FindElementsByPoint(const gp_Pnt& point,
6266 SMDSAbs_ElementType type,
6267 vector< const SMDS_MeshElement* >& foundElements);
6268 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6270 double getTolerance();
6271 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6272 const double tolerance, double & param);
6273 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6274 bool isOuterBoundary(const SMDS_MeshElement* face) const
6276 return _outerFaces.empty() || _outerFaces.count(face);
6278 struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6280 const SMDS_MeshElement* _face;
6282 bool _coincides; //!< the line lays in face plane
6283 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6284 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6286 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6289 TIDSortedElemSet _faces;
6290 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6291 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6295 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6297 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6298 << ", _coincides="<<i._coincides << ")";
6301 //=======================================================================
6303 * \brief define tolerance for search
6305 //=======================================================================
6307 double SMESH_ElementSearcherImpl::getTolerance()
6309 if ( _tolerance < 0 )
6311 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6314 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6316 double boxSize = _nodeSearcher->getTree()->maxSize();
6317 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6319 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6321 double boxSize = _ebbTree->maxSize();
6322 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6324 if ( _tolerance == 0 )
6326 // define tolerance by size of a most complex element
6327 int complexType = SMDSAbs_Volume;
6328 while ( complexType > SMDSAbs_All &&
6329 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6331 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6334 if ( complexType == int( SMDSAbs_Node ))
6336 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6338 if ( meshInfo.NbNodes() > 2 )
6339 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6343 const SMDS_MeshElement* elem =
6344 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6345 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6346 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6347 while ( nodeIt->more() )
6349 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6350 elemSize = max( dist, elemSize );
6353 _tolerance = 1e-6 * elemSize;
6359 //================================================================================
6361 * \brief Find intersection of the line and an edge of face and return parameter on line
6363 //================================================================================
6365 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6366 const SMDS_MeshElement* face,
6373 GeomAPI_ExtremaCurveCurve anExtCC;
6374 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6376 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6377 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6379 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6380 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6381 anExtCC.Init( lineCurve, edge);
6382 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6384 Quantity_Parameter pl, pe;
6385 anExtCC.LowerDistanceParameters( pl, pe );
6387 if ( ++nbInts == 2 )
6391 if ( nbInts > 0 ) param /= nbInts;
6394 //================================================================================
6396 * \brief Find all faces belonging to the outer boundary of mesh
6398 //================================================================================
6400 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6402 if ( _outerFacesFound ) return;
6404 // Collect all outer faces by passing from one outer face to another via their links
6405 // and BTW find out if there are internal faces at all.
6407 // checked links and links where outer boundary meets internal one
6408 set< SMESH_TLink > visitedLinks, seamLinks;
6410 // links to treat with already visited faces sharing them
6411 list < TFaceLink > startLinks;
6413 // load startLinks with the first outerFace
6414 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6415 _outerFaces.insert( outerFace );
6417 TIDSortedElemSet emptySet;
6418 while ( !startLinks.empty() )
6420 const SMESH_TLink& link = startLinks.front()._link;
6421 TIDSortedElemSet& faces = startLinks.front()._faces;
6423 outerFace = *faces.begin();
6424 // find other faces sharing the link
6425 const SMDS_MeshElement* f;
6426 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6429 // select another outer face among the found
6430 const SMDS_MeshElement* outerFace2 = 0;
6431 if ( faces.size() == 2 )
6433 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6435 else if ( faces.size() > 2 )
6437 seamLinks.insert( link );
6439 // link direction within the outerFace
6440 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6441 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6442 int i1 = outerFace->GetNodeIndex( link.node1() );
6443 int i2 = outerFace->GetNodeIndex( link.node2() );
6444 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6445 if ( rev ) n1n2.Reverse();
6447 gp_XYZ ofNorm, fNorm;
6448 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6450 // direction from the link inside outerFace
6451 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6452 // sort all other faces by angle with the dirInOF
6453 map< double, const SMDS_MeshElement* > angle2Face;
6454 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6455 for ( ; face != faces.end(); ++face )
6457 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6459 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6460 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6461 if ( angle < 0 ) angle += 2*PI;
6462 angle2Face.insert( make_pair( angle, *face ));
6464 if ( !angle2Face.empty() )
6465 outerFace2 = angle2Face.begin()->second;
6468 // store the found outer face and add its links to continue seaching from
6471 _outerFaces.insert( outerFace );
6472 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6473 for ( int i = 0; i < nbNodes; ++i )
6475 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6476 if ( visitedLinks.insert( link2 ).second )
6477 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6480 startLinks.pop_front();
6482 _outerFacesFound = true;
6484 if ( !seamLinks.empty() )
6486 // There are internal boundaries touching the outher one,
6487 // find all faces of internal boundaries in order to find
6488 // faces of boundaries of holes, if any.
6493 _outerFaces.clear();
6497 //=======================================================================
6499 * \brief Find elements of given type where the given point is IN or ON.
6500 * Returns nb of found elements and elements them-selves.
6502 * 'ALL' type means elements of any type excluding nodes and 0D elements
6504 //=======================================================================
6506 int SMESH_ElementSearcherImpl::
6507 FindElementsByPoint(const gp_Pnt& point,
6508 SMDSAbs_ElementType type,
6509 vector< const SMDS_MeshElement* >& foundElements)
6511 foundElements.clear();
6513 double tolerance = getTolerance();
6515 // =================================================================================
6516 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6518 if ( !_nodeSearcher )
6519 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6521 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6522 if ( !closeNode ) return foundElements.size();
6524 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6525 return foundElements.size(); // to far from any node
6527 if ( type == SMDSAbs_Node )
6529 foundElements.push_back( closeNode );
6533 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6534 while ( elemIt->more() )
6535 foundElements.push_back( elemIt->next() );
6538 // =================================================================================
6539 else // elements more complex than 0D
6541 if ( !_ebbTree || _elementType != type )
6543 if ( _ebbTree ) delete _ebbTree;
6544 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6546 TIDSortedElemSet suspectElems;
6547 _ebbTree->getElementsNearPoint( point, suspectElems );
6548 TIDSortedElemSet::iterator elem = suspectElems.begin();
6549 for ( ; elem != suspectElems.end(); ++elem )
6550 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6551 foundElements.push_back( *elem );
6553 return foundElements.size();
6556 //================================================================================
6558 * \brief Classify the given point in the closed 2D mesh
6560 //================================================================================
6562 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6564 double tolerance = getTolerance();
6565 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6567 if ( _ebbTree ) delete _ebbTree;
6568 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6570 // Algo: analyse transition of a line starting at the point through mesh boundary;
6571 // try three lines parallel to axis of the coordinate system and perform rough
6572 // analysis. If solution is not clear perform thorough analysis.
6574 const int nbAxes = 3;
6575 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6576 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6577 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6578 multimap< int, int > nbInt2Axis; // to find the simplest case
6579 for ( int axis = 0; axis < nbAxes; ++axis )
6581 gp_Ax1 lineAxis( point, axisDir[axis]);
6582 gp_Lin line ( lineAxis );
6584 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6585 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6587 // Intersect faces with the line
6589 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6590 TIDSortedElemSet::iterator face = suspectFaces.begin();
6591 for ( ; face != suspectFaces.end(); ++face )
6595 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6596 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6598 // perform intersection
6599 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6600 if ( !intersection.IsDone() )
6602 if ( intersection.IsInQuadric() )
6604 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6606 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6608 gp_Pnt intersectionPoint = intersection.Point(1);
6609 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6610 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6613 // Analyse intersections roughly
6615 int nbInter = u2inters.size();
6619 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6620 if ( nbInter == 1 ) // not closed mesh
6621 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6623 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6626 if ( (f<0) == (l<0) )
6629 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6630 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6631 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6634 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6636 if ( _outerFacesFound ) break; // pass to thorough analysis
6638 } // three attempts - loop on CS axes
6640 // Analyse intersections thoroughly.
6641 // We make two loops maximum, on the first one we only exclude touching intersections,
6642 // on the second, if situation is still unclear, we gather and use information on
6643 // position of faces (internal or outer). If faces position is already gathered,
6644 // we make the second loop right away.
6646 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6648 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6649 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6651 int axis = nb_axis->second;
6652 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6654 gp_Ax1 lineAxis( point, axisDir[axis]);
6655 gp_Lin line ( lineAxis );
6657 // add tangent intersections to u2inters
6659 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6660 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6661 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6662 u2inters.insert(make_pair( param, *tgtInt ));
6663 tangentInters[ axis ].clear();
6665 // Count intersections before and after the point excluding touching ones.
6666 // If hasPositionInfo we count intersections of outer boundary only
6668 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6669 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6670 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6671 bool ok = ! u_int1->second._coincides;
6672 while ( ok && u_int1 != u2inters.end() )
6674 double u = u_int1->first;
6675 bool touchingInt = false;
6676 if ( ++u_int2 != u2inters.end() )
6678 // skip intersections at the same point (if the line passes through edge or node)
6680 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6686 // skip tangent intersections
6688 const SMDS_MeshElement* prevFace = u_int1->second._face;
6689 while ( ok && u_int2->second._coincides )
6691 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6697 ok = ( u_int2 != u2inters.end() );
6702 // skip intersections at the same point after tangent intersections
6705 double u2 = u_int2->first;
6707 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6713 // decide if we skipped a touching intersection
6714 if ( nbSamePnt + nbTgt > 0 )
6716 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6717 map< double, TInters >::iterator u_int = u_int1;
6718 for ( ; u_int != u_int2; ++u_int )
6720 if ( u_int->second._coincides ) continue;
6721 double dot = u_int->second._faceNorm * line.Direction();
6722 if ( dot > maxDot ) maxDot = dot;
6723 if ( dot < minDot ) minDot = dot;
6725 touchingInt = ( minDot*maxDot < 0 );
6730 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6741 u_int1 = u_int2; // to next intersection
6743 } // loop on intersections with one line
6747 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6750 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6753 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6754 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6756 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6759 if ( (f<0) == (l<0) )
6762 if ( hasPositionInfo )
6763 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6765 } // loop on intersections of the tree lines - thorough analysis
6767 if ( !hasPositionInfo )
6769 // gather info on faces position - is face in the outer boundary or not
6770 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6771 findOuterBoundary( u2inters.begin()->second._face );
6774 } // two attempts - with and w/o faces position info in the mesh
6776 return TopAbs_UNKNOWN;
6779 //=======================================================================
6781 * \brief Return SMESH_ElementSearcher
6783 //=======================================================================
6785 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6787 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6790 //=======================================================================
6792 * \brief Return true if the point is IN or ON of the element
6794 //=======================================================================
6796 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6798 if ( element->GetType() == SMDSAbs_Volume)
6800 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6803 // get ordered nodes
6805 vector< gp_XYZ > xyz;
6807 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6808 if ( element->IsQuadratic() )
6809 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6810 nodeIt = f->interlacedNodesElemIterator();
6811 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6812 nodeIt = e->interlacedNodesElemIterator();
6814 while ( nodeIt->more() )
6815 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6817 int i, nbNodes = element->NbNodes();
6819 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6821 // compute face normal
6822 gp_Vec faceNorm(0,0,0);
6823 xyz.push_back( xyz.front() );
6824 for ( i = 0; i < nbNodes; ++i )
6826 gp_Vec edge1( xyz[i+1], xyz[i]);
6827 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6828 faceNorm += edge1 ^ edge2;
6830 double normSize = faceNorm.Magnitude();
6831 if ( normSize <= tol )
6833 // degenerated face: point is out if it is out of all face edges
6834 for ( i = 0; i < nbNodes; ++i )
6836 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6837 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6838 SMDS_MeshEdge edge( &n1, &n2 );
6839 if ( !isOut( &edge, point, tol ))
6844 faceNorm /= normSize;
6846 // check if the point lays on face plane
6847 gp_Vec n2p( xyz[0], point );
6848 if ( fabs( n2p * faceNorm ) > tol )
6849 return true; // not on face plane
6851 // check if point is out of face boundary:
6852 // define it by closest transition of a ray point->infinity through face boundary
6853 // on the face plane.
6854 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6855 // to find intersections of the ray with the boundary.
6857 gp_Vec plnNorm = ray ^ faceNorm;
6858 normSize = plnNorm.Magnitude();
6859 if ( normSize <= tol ) return false; // point coincides with the first node
6860 plnNorm /= normSize;
6861 // for each node of the face, compute its signed distance to the plane
6862 vector<double> dist( nbNodes + 1);
6863 for ( i = 0; i < nbNodes; ++i )
6865 gp_Vec n2p( xyz[i], point );
6866 dist[i] = n2p * plnNorm;
6868 dist.back() = dist.front();
6869 // find the closest intersection
6871 double rClosest, distClosest = 1e100;;
6873 for ( i = 0; i < nbNodes; ++i )
6876 if ( fabs( dist[i]) < tol )
6878 else if ( fabs( dist[i+1]) < tol )
6880 else if ( dist[i] * dist[i+1] < 0 )
6881 r = dist[i] / ( dist[i] - dist[i+1] );
6883 continue; // no intersection
6884 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6885 gp_Vec p2int ( point, pInt);
6886 if ( p2int * ray > -tol ) // right half-space
6888 double intDist = p2int.SquareMagnitude();
6889 if ( intDist < distClosest )
6894 distClosest = intDist;
6899 return true; // no intesections - out
6901 // analyse transition
6902 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6903 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6904 gp_Vec p2int ( point, pClosest );
6905 bool out = (edgeNorm * p2int) < -tol;
6906 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6909 // ray pass through a face node; analyze transition through an adjacent edge
6910 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6911 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6912 gp_Vec edgeAdjacent( p1, p2 );
6913 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6914 bool out2 = (edgeNorm2 * p2int) < -tol;
6916 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6917 return covexCorner ? (out || out2) : (out && out2);
6919 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6921 // point is out of edge if it is NOT ON any straight part of edge
6922 // (we consider quadratic edge as being composed of two straight parts)
6923 for ( i = 1; i < nbNodes; ++i )
6925 gp_Vec edge( xyz[i-1], xyz[i]);
6926 gp_Vec n1p ( xyz[i-1], point);
6927 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6930 gp_Vec n2p( xyz[i], point );
6931 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6933 return false; // point is ON this part
6937 // Node or 0D element -------------------------------------------------------------------------
6939 gp_Vec n2p ( xyz[0], point );
6940 return n2p.Magnitude() <= tol;
6945 //=======================================================================
6946 //function : SimplifyFace
6948 //=======================================================================
6949 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6950 vector<const SMDS_MeshNode *>& poly_nodes,
6951 vector<int>& quantities) const
6953 int nbNodes = faceNodes.size();
6958 set<const SMDS_MeshNode*> nodeSet;
6960 // get simple seq of nodes
6961 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6962 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6963 int iSimple = 0, nbUnique = 0;
6965 simpleNodes[iSimple++] = faceNodes[0];
6967 for (int iCur = 1; iCur < nbNodes; iCur++) {
6968 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6969 simpleNodes[iSimple++] = faceNodes[iCur];
6970 if (nodeSet.insert( faceNodes[iCur] ).second)
6974 int nbSimple = iSimple;
6975 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6985 bool foundLoop = (nbSimple > nbUnique);
6988 set<const SMDS_MeshNode*> loopSet;
6989 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6990 const SMDS_MeshNode* n = simpleNodes[iSimple];
6991 if (!loopSet.insert( n ).second) {
6995 int iC = 0, curLast = iSimple;
6996 for (; iC < curLast; iC++) {
6997 if (simpleNodes[iC] == n) break;
6999 int loopLen = curLast - iC;
7001 // create sub-element
7003 quantities.push_back(loopLen);
7004 for (; iC < curLast; iC++) {
7005 poly_nodes.push_back(simpleNodes[iC]);
7008 // shift the rest nodes (place from the first loop position)
7009 for (iC = curLast + 1; iC < nbSimple; iC++) {
7010 simpleNodes[iC - loopLen] = simpleNodes[iC];
7012 nbSimple -= loopLen;
7015 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7016 } // while (foundLoop)
7020 quantities.push_back(iSimple);
7021 for (int i = 0; i < iSimple; i++)
7022 poly_nodes.push_back(simpleNodes[i]);
7028 //=======================================================================
7029 //function : MergeNodes
7030 //purpose : In each group, the cdr of nodes are substituted by the first one
7032 //=======================================================================
7034 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7036 myLastCreatedElems.Clear();
7037 myLastCreatedNodes.Clear();
7039 SMESHDS_Mesh* aMesh = GetMeshDS();
7041 TNodeNodeMap nodeNodeMap; // node to replace - new node
7042 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7043 list< int > rmElemIds, rmNodeIds;
7045 // Fill nodeNodeMap and elems
7047 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7048 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7049 list<const SMDS_MeshNode*>& nodes = *grIt;
7050 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7051 const SMDS_MeshNode* nToKeep = *nIt;
7052 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7053 const SMDS_MeshNode* nToRemove = *nIt;
7054 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7055 if ( nToRemove != nToKeep ) {
7056 rmNodeIds.push_back( nToRemove->GetID() );
7057 AddToSameGroups( nToKeep, nToRemove, aMesh );
7060 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7061 while ( invElemIt->more() ) {
7062 const SMDS_MeshElement* elem = invElemIt->next();
7067 // Change element nodes or remove an element
7069 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7070 for ( ; eIt != elems.end(); eIt++ ) {
7071 const SMDS_MeshElement* elem = *eIt;
7072 int nbNodes = elem->NbNodes();
7073 int aShapeId = FindShape( elem );
7075 set<const SMDS_MeshNode*> nodeSet;
7076 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7077 int iUnique = 0, iCur = 0, nbRepl = 0;
7078 vector<int> iRepl( nbNodes );
7080 // get new seq of nodes
7081 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7082 while ( itN->more() ) {
7083 const SMDS_MeshNode* n =
7084 static_cast<const SMDS_MeshNode*>( itN->next() );
7086 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7087 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7089 // BUG 0020185: begin
7091 bool stopRecur = false;
7092 set<const SMDS_MeshNode*> nodesRecur;
7093 nodesRecur.insert(n);
7094 while (!stopRecur) {
7095 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7096 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7097 n = (*nnIt_i).second;
7098 if (!nodesRecur.insert(n).second) {
7099 // error: recursive dependancy
7108 iRepl[ nbRepl++ ] = iCur;
7110 curNodes[ iCur ] = n;
7111 bool isUnique = nodeSet.insert( n ).second;
7113 uniqueNodes[ iUnique++ ] = n;
7117 // Analyse element topology after replacement
7120 int nbUniqueNodes = nodeSet.size();
7121 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7122 // Polygons and Polyhedral volumes
7123 if (elem->IsPoly()) {
7125 if (elem->GetType() == SMDSAbs_Face) {
7127 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7129 for (; inode < nbNodes; inode++) {
7130 face_nodes[inode] = curNodes[inode];
7133 vector<const SMDS_MeshNode *> polygons_nodes;
7134 vector<int> quantities;
7135 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7139 for (int iface = 0; iface < nbNew - 1; iface++) {
7140 int nbNodes = quantities[iface];
7141 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7142 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7143 poly_nodes[ii] = polygons_nodes[inode];
7145 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7146 myLastCreatedElems.Append(newElem);
7148 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7150 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7153 rmElemIds.push_back(elem->GetID());
7157 else if (elem->GetType() == SMDSAbs_Volume) {
7158 // Polyhedral volume
7159 if (nbUniqueNodes < 4) {
7160 rmElemIds.push_back(elem->GetID());
7163 // each face has to be analized in order to check volume validity
7164 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7165 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7167 int nbFaces = aPolyedre->NbFaces();
7169 vector<const SMDS_MeshNode *> poly_nodes;
7170 vector<int> quantities;
7172 for (int iface = 1; iface <= nbFaces; iface++) {
7173 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7174 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7176 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7177 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7178 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7179 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7180 faceNode = (*nnIt).second;
7182 faceNodes[inode - 1] = faceNode;
7185 SimplifyFace(faceNodes, poly_nodes, quantities);
7188 if (quantities.size() > 3) {
7189 // to be done: remove coincident faces
7192 if (quantities.size() > 3)
7193 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7195 rmElemIds.push_back(elem->GetID());
7199 rmElemIds.push_back(elem->GetID());
7210 switch ( nbNodes ) {
7211 case 2: ///////////////////////////////////// EDGE
7212 isOk = false; break;
7213 case 3: ///////////////////////////////////// TRIANGLE
7214 isOk = false; break;
7216 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7218 else { //////////////////////////////////// QUADRANGLE
7219 if ( nbUniqueNodes < 3 )
7221 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7222 isOk = false; // opposite nodes stick
7225 case 6: ///////////////////////////////////// PENTAHEDRON
7226 if ( nbUniqueNodes == 4 ) {
7227 // ---------------------------------> tetrahedron
7229 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7230 // all top nodes stick: reverse a bottom
7231 uniqueNodes[ 0 ] = curNodes [ 1 ];
7232 uniqueNodes[ 1 ] = curNodes [ 0 ];
7234 else if (nbRepl == 3 &&
7235 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7236 // all bottom nodes stick: set a top before
7237 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7238 uniqueNodes[ 0 ] = curNodes [ 3 ];
7239 uniqueNodes[ 1 ] = curNodes [ 4 ];
7240 uniqueNodes[ 2 ] = curNodes [ 5 ];
7242 else if (nbRepl == 4 &&
7243 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7244 // a lateral face turns into a line: reverse a bottom
7245 uniqueNodes[ 0 ] = curNodes [ 1 ];
7246 uniqueNodes[ 1 ] = curNodes [ 0 ];
7251 else if ( nbUniqueNodes == 5 ) {
7252 // PENTAHEDRON --------------------> 2 tetrahedrons
7253 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7254 // a bottom node sticks with a linked top one
7256 SMDS_MeshElement* newElem =
7257 aMesh->AddVolume(curNodes[ 3 ],
7260 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7261 myLastCreatedElems.Append(newElem);
7263 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7264 // 2. : reverse a bottom
7265 uniqueNodes[ 0 ] = curNodes [ 1 ];
7266 uniqueNodes[ 1 ] = curNodes [ 0 ];
7276 if(elem->IsQuadratic()) { // Quadratic quadrangle
7289 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7290 uniqueNodes[0] = curNodes[0];
7291 uniqueNodes[1] = curNodes[2];
7292 uniqueNodes[2] = curNodes[3];
7293 uniqueNodes[3] = curNodes[5];
7294 uniqueNodes[4] = curNodes[6];
7295 uniqueNodes[5] = curNodes[7];
7298 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7299 uniqueNodes[0] = curNodes[0];
7300 uniqueNodes[1] = curNodes[1];
7301 uniqueNodes[2] = curNodes[2];
7302 uniqueNodes[3] = curNodes[4];
7303 uniqueNodes[4] = curNodes[5];
7304 uniqueNodes[5] = curNodes[6];
7307 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7308 uniqueNodes[0] = curNodes[1];
7309 uniqueNodes[1] = curNodes[2];
7310 uniqueNodes[2] = curNodes[3];
7311 uniqueNodes[3] = curNodes[5];
7312 uniqueNodes[4] = curNodes[6];
7313 uniqueNodes[5] = curNodes[0];
7316 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7317 uniqueNodes[0] = curNodes[0];
7318 uniqueNodes[1] = curNodes[1];
7319 uniqueNodes[2] = curNodes[3];
7320 uniqueNodes[3] = curNodes[4];
7321 uniqueNodes[4] = curNodes[6];
7322 uniqueNodes[5] = curNodes[7];
7325 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7326 uniqueNodes[0] = curNodes[0];
7327 uniqueNodes[1] = curNodes[2];
7328 uniqueNodes[2] = curNodes[3];
7329 uniqueNodes[3] = curNodes[1];
7330 uniqueNodes[4] = curNodes[6];
7331 uniqueNodes[5] = curNodes[7];
7334 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7335 uniqueNodes[0] = curNodes[0];
7336 uniqueNodes[1] = curNodes[1];
7337 uniqueNodes[2] = curNodes[2];
7338 uniqueNodes[3] = curNodes[4];
7339 uniqueNodes[4] = curNodes[5];
7340 uniqueNodes[5] = curNodes[7];
7343 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7344 uniqueNodes[0] = curNodes[0];
7345 uniqueNodes[1] = curNodes[1];
7346 uniqueNodes[2] = curNodes[3];
7347 uniqueNodes[3] = curNodes[4];
7348 uniqueNodes[4] = curNodes[2];
7349 uniqueNodes[5] = curNodes[7];
7352 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7353 uniqueNodes[0] = curNodes[0];
7354 uniqueNodes[1] = curNodes[1];
7355 uniqueNodes[2] = curNodes[2];
7356 uniqueNodes[3] = curNodes[4];
7357 uniqueNodes[4] = curNodes[5];
7358 uniqueNodes[5] = curNodes[3];
7364 //////////////////////////////////// HEXAHEDRON
7366 SMDS_VolumeTool hexa (elem);
7367 hexa.SetExternalNormal();
7368 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7369 //////////////////////// ---> tetrahedron
7370 for ( int iFace = 0; iFace < 6; iFace++ ) {
7371 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7372 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7373 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7374 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7375 // one face turns into a point ...
7376 int iOppFace = hexa.GetOppFaceIndex( iFace );
7377 ind = hexa.GetFaceNodesIndices( iOppFace );
7379 iUnique = 2; // reverse a tetrahedron bottom
7380 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7381 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7383 else if ( iUnique >= 0 )
7384 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7386 if ( nbStick == 1 ) {
7387 // ... and the opposite one - into a triangle.
7389 ind = hexa.GetFaceNodesIndices( iFace );
7390 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7397 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7398 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7399 for ( int iFace = 0; iFace < 6; iFace++ ) {
7400 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7401 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7402 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7403 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7404 // one face turns into a point ...
7405 int iOppFace = hexa.GetOppFaceIndex( iFace );
7406 ind = hexa.GetFaceNodesIndices( iOppFace );
7408 iUnique = 2; // reverse a tetrahedron 1 bottom
7409 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7410 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7412 else if ( iUnique >= 0 )
7413 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7415 if ( nbStick == 0 ) {
7416 // ... and the opposite one is a quadrangle
7418 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7419 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7422 SMDS_MeshElement* newElem =
7423 aMesh->AddVolume(curNodes[ind[ 0 ]],
7426 curNodes[indTop[ 0 ]]);
7427 myLastCreatedElems.Append(newElem);
7429 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7436 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7437 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7438 // find indices of quad and tri faces
7439 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7440 for ( iFace = 0; iFace < 6; iFace++ ) {
7441 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7443 for ( iCur = 0; iCur < 4; iCur++ )
7444 nodeSet.insert( curNodes[ind[ iCur ]] );
7445 nbUniqueNodes = nodeSet.size();
7446 if ( nbUniqueNodes == 3 )
7447 iTriFace[ nbTri++ ] = iFace;
7448 else if ( nbUniqueNodes == 4 )
7449 iQuadFace[ nbQuad++ ] = iFace;
7451 if (nbQuad == 2 && nbTri == 4 &&
7452 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7453 // 2 opposite quadrangles stuck with a diagonal;
7454 // sample groups of merged indices: (0-4)(2-6)
7455 // --------------------------------------------> 2 tetrahedrons
7456 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7457 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7458 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7459 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7460 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7461 // stuck with 0-2 diagonal
7469 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7470 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7471 // stuck with 1-3 diagonal
7483 uniqueNodes[ 0 ] = curNodes [ i0 ];
7484 uniqueNodes[ 1 ] = curNodes [ i1d ];
7485 uniqueNodes[ 2 ] = curNodes [ i3d ];
7486 uniqueNodes[ 3 ] = curNodes [ i0t ];
7489 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7493 myLastCreatedElems.Append(newElem);
7495 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7498 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7499 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7500 // --------------------------------------------> prism
7501 // find 2 opposite triangles
7503 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7504 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7505 // find indices of kept and replaced nodes
7506 // and fill unique nodes of 2 opposite triangles
7507 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7508 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7509 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7510 // fill unique nodes
7513 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7514 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7515 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7517 // iCur of a linked node of the opposite face (make normals co-directed):
7518 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7519 // check that correspondent corners of triangles are linked
7520 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7523 uniqueNodes[ iUnique ] = n;
7524 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7533 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7539 } // switch ( nbNodes )
7541 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7544 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7545 // Change nodes of polyedre
7546 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7547 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7549 int nbFaces = aPolyedre->NbFaces();
7551 vector<const SMDS_MeshNode *> poly_nodes;
7552 vector<int> quantities (nbFaces);
7554 for (int iface = 1; iface <= nbFaces; iface++) {
7555 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7556 quantities[iface - 1] = nbFaceNodes;
7558 for (inode = 1; inode <= nbFaceNodes; inode++) {
7559 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7561 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7562 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7563 curNode = (*nnIt).second;
7565 poly_nodes.push_back(curNode);
7568 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7572 // Change regular element or polygon
7573 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7577 // Remove invalid regular element or invalid polygon
7578 rmElemIds.push_back( elem->GetID() );
7581 } // loop on elements
7583 // Remove equal nodes and bad elements
7585 Remove( rmNodeIds, true );
7586 Remove( rmElemIds, false );
7591 // ========================================================
7592 // class : SortableElement
7593 // purpose : allow sorting elements basing on their nodes
7594 // ========================================================
7595 class SortableElement : public set <const SMDS_MeshElement*>
7599 SortableElement( const SMDS_MeshElement* theElem )
7602 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7603 while ( nodeIt->more() )
7604 this->insert( nodeIt->next() );
7607 const SMDS_MeshElement* Get() const
7610 void Set(const SMDS_MeshElement* e) const
7615 mutable const SMDS_MeshElement* myElem;
7618 //=======================================================================
7619 //function : FindEqualElements
7620 //purpose : Return list of group of elements built on the same nodes.
7621 // Search among theElements or in the whole mesh if theElements is empty
7622 //=======================================================================
7623 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7624 TListOfListOfElementsID & theGroupsOfElementsID)
7626 myLastCreatedElems.Clear();
7627 myLastCreatedNodes.Clear();
7629 typedef set<const SMDS_MeshElement*> TElemsSet;
7630 typedef map< SortableElement, int > TMapOfNodeSet;
7631 typedef list<int> TGroupOfElems;
7634 if ( theElements.empty() )
7635 { // get all elements in the mesh
7636 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7637 while ( eIt->more() )
7638 elems.insert( elems.end(), eIt->next());
7641 elems = theElements;
7643 vector< TGroupOfElems > arrayOfGroups;
7644 TGroupOfElems groupOfElems;
7645 TMapOfNodeSet mapOfNodeSet;
7647 TElemsSet::iterator elemIt = elems.begin();
7648 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7649 const SMDS_MeshElement* curElem = *elemIt;
7650 SortableElement SE(curElem);
7653 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7654 if( !(pp.second) ) {
7655 TMapOfNodeSet::iterator& itSE = pp.first;
7656 ind = (*itSE).second;
7657 arrayOfGroups[ind].push_back(curElem->GetID());
7660 groupOfElems.clear();
7661 groupOfElems.push_back(curElem->GetID());
7662 arrayOfGroups.push_back(groupOfElems);
7667 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7668 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7669 groupOfElems = *groupIt;
7670 if ( groupOfElems.size() > 1 ) {
7671 groupOfElems.sort();
7672 theGroupsOfElementsID.push_back(groupOfElems);
7677 //=======================================================================
7678 //function : MergeElements
7679 //purpose : In each given group, substitute all elements by the first one.
7680 //=======================================================================
7682 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7684 myLastCreatedElems.Clear();
7685 myLastCreatedNodes.Clear();
7687 typedef list<int> TListOfIDs;
7688 TListOfIDs rmElemIds; // IDs of elems to remove
7690 SMESHDS_Mesh* aMesh = GetMeshDS();
7692 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7693 while ( groupsIt != theGroupsOfElementsID.end() ) {
7694 TListOfIDs& aGroupOfElemID = *groupsIt;
7695 aGroupOfElemID.sort();
7696 int elemIDToKeep = aGroupOfElemID.front();
7697 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7698 aGroupOfElemID.pop_front();
7699 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7700 while ( idIt != aGroupOfElemID.end() ) {
7701 int elemIDToRemove = *idIt;
7702 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7703 // add the kept element in groups of removed one (PAL15188)
7704 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7705 rmElemIds.push_back( elemIDToRemove );
7711 Remove( rmElemIds, false );
7714 //=======================================================================
7715 //function : MergeEqualElements
7716 //purpose : Remove all but one of elements built on the same nodes.
7717 //=======================================================================
7719 void SMESH_MeshEditor::MergeEqualElements()
7721 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7722 to merge equal elements in the whole mesh */
7723 TListOfListOfElementsID aGroupsOfElementsID;
7724 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7725 MergeElements(aGroupsOfElementsID);
7728 //=======================================================================
7729 //function : FindFaceInSet
7730 //purpose : Return a face having linked nodes n1 and n2 and which is
7731 // - not in avoidSet,
7732 // - in elemSet provided that !elemSet.empty()
7733 // i1 and i2 optionally returns indices of n1 and n2
7734 //=======================================================================
7736 const SMDS_MeshElement*
7737 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7738 const SMDS_MeshNode* n2,
7739 const TIDSortedElemSet& elemSet,
7740 const TIDSortedElemSet& avoidSet,
7746 const SMDS_MeshElement* face = 0;
7748 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7749 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7751 const SMDS_MeshElement* elem = invElemIt->next();
7752 if (avoidSet.count( elem ))
7754 if ( !elemSet.empty() && !elemSet.count( elem ))
7757 i1 = elem->GetNodeIndex( n1 );
7758 // find a n2 linked to n1
7759 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7760 for ( int di = -1; di < 2 && !face; di += 2 )
7762 i2 = (i1+di+nbN) % nbN;
7763 if ( elem->GetNode( i2 ) == n2 )
7766 if ( !face && elem->IsQuadratic())
7768 // analysis for quadratic elements using all nodes
7769 const SMDS_QuadraticFaceOfNodes* F =
7770 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7771 // use special nodes iterator
7772 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7773 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7774 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7776 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7777 if ( n1 == prevN && n2 == n )
7781 else if ( n2 == prevN && n1 == n )
7783 face = elem; swap( i1, i2 );
7789 if ( n1ind ) *n1ind = i1;
7790 if ( n2ind ) *n2ind = i2;
7794 //=======================================================================
7795 //function : findAdjacentFace
7797 //=======================================================================
7799 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7800 const SMDS_MeshNode* n2,
7801 const SMDS_MeshElement* elem)
7803 TIDSortedElemSet elemSet, avoidSet;
7805 avoidSet.insert ( elem );
7806 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7809 //=======================================================================
7810 //function : FindFreeBorder
7812 //=======================================================================
7814 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7816 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7817 const SMDS_MeshNode* theSecondNode,
7818 const SMDS_MeshNode* theLastNode,
7819 list< const SMDS_MeshNode* > & theNodes,
7820 list< const SMDS_MeshElement* >& theFaces)
7822 if ( !theFirstNode || !theSecondNode )
7824 // find border face between theFirstNode and theSecondNode
7825 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7829 theFaces.push_back( curElem );
7830 theNodes.push_back( theFirstNode );
7831 theNodes.push_back( theSecondNode );
7833 //vector<const SMDS_MeshNode*> nodes;
7834 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7835 TIDSortedElemSet foundElems;
7836 bool needTheLast = ( theLastNode != 0 );
7838 while ( nStart != theLastNode ) {
7839 if ( nStart == theFirstNode )
7840 return !needTheLast;
7842 // find all free border faces sharing form nStart
7844 list< const SMDS_MeshElement* > curElemList;
7845 list< const SMDS_MeshNode* > nStartList;
7846 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7847 while ( invElemIt->more() ) {
7848 const SMDS_MeshElement* e = invElemIt->next();
7849 if ( e == curElem || foundElems.insert( e ).second ) {
7851 int iNode = 0, nbNodes = e->NbNodes();
7852 //const SMDS_MeshNode* nodes[nbNodes+1];
7853 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7855 if(e->IsQuadratic()) {
7856 const SMDS_QuadraticFaceOfNodes* F =
7857 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7858 // use special nodes iterator
7859 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7860 while( anIter->more() ) {
7861 nodes[ iNode++ ] = anIter->next();
7865 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7866 while ( nIt->more() )
7867 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7869 nodes[ iNode ] = nodes[ 0 ];
7871 for ( iNode = 0; iNode < nbNodes; iNode++ )
7872 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7873 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7874 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7876 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7877 curElemList.push_back( e );
7881 // analyse the found
7883 int nbNewBorders = curElemList.size();
7884 if ( nbNewBorders == 0 ) {
7885 // no free border furthermore
7886 return !needTheLast;
7888 else if ( nbNewBorders == 1 ) {
7889 // one more element found
7891 nStart = nStartList.front();
7892 curElem = curElemList.front();
7893 theFaces.push_back( curElem );
7894 theNodes.push_back( nStart );
7897 // several continuations found
7898 list< const SMDS_MeshElement* >::iterator curElemIt;
7899 list< const SMDS_MeshNode* >::iterator nStartIt;
7900 // check if one of them reached the last node
7901 if ( needTheLast ) {
7902 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7903 curElemIt!= curElemList.end();
7904 curElemIt++, nStartIt++ )
7905 if ( *nStartIt == theLastNode ) {
7906 theFaces.push_back( *curElemIt );
7907 theNodes.push_back( *nStartIt );
7911 // find the best free border by the continuations
7912 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7913 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7914 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7915 curElemIt!= curElemList.end();
7916 curElemIt++, nStartIt++ )
7918 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7919 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7920 // find one more free border
7921 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7925 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7926 // choice: clear a worse one
7927 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7928 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7929 contNodes[ iWorse ].clear();
7930 contFaces[ iWorse ].clear();
7933 if ( contNodes[0].empty() && contNodes[1].empty() )
7936 // append the best free border
7937 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7938 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7939 theNodes.pop_back(); // remove nIgnore
7940 theNodes.pop_back(); // remove nStart
7941 theFaces.pop_back(); // remove curElem
7942 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7943 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7944 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7945 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7948 } // several continuations found
7949 } // while ( nStart != theLastNode )
7954 //=======================================================================
7955 //function : CheckFreeBorderNodes
7956 //purpose : Return true if the tree nodes are on a free border
7957 //=======================================================================
7959 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7960 const SMDS_MeshNode* theNode2,
7961 const SMDS_MeshNode* theNode3)
7963 list< const SMDS_MeshNode* > nodes;
7964 list< const SMDS_MeshElement* > faces;
7965 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7968 //=======================================================================
7969 //function : SewFreeBorder
7971 //=======================================================================
7973 SMESH_MeshEditor::Sew_Error
7974 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7975 const SMDS_MeshNode* theBordSecondNode,
7976 const SMDS_MeshNode* theBordLastNode,
7977 const SMDS_MeshNode* theSideFirstNode,
7978 const SMDS_MeshNode* theSideSecondNode,
7979 const SMDS_MeshNode* theSideThirdNode,
7980 const bool theSideIsFreeBorder,
7981 const bool toCreatePolygons,
7982 const bool toCreatePolyedrs)
7984 myLastCreatedElems.Clear();
7985 myLastCreatedNodes.Clear();
7987 MESSAGE("::SewFreeBorder()");
7988 Sew_Error aResult = SEW_OK;
7990 // ====================================
7991 // find side nodes and elements
7992 // ====================================
7994 list< const SMDS_MeshNode* > nSide[ 2 ];
7995 list< const SMDS_MeshElement* > eSide[ 2 ];
7996 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7997 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8001 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8002 nSide[0], eSide[0])) {
8003 MESSAGE(" Free Border 1 not found " );
8004 aResult = SEW_BORDER1_NOT_FOUND;
8006 if (theSideIsFreeBorder) {
8009 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8010 nSide[1], eSide[1])) {
8011 MESSAGE(" Free Border 2 not found " );
8012 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8015 if ( aResult != SEW_OK )
8018 if (!theSideIsFreeBorder) {
8022 // -------------------------------------------------------------------------
8024 // 1. If nodes to merge are not coincident, move nodes of the free border
8025 // from the coord sys defined by the direction from the first to last
8026 // nodes of the border to the correspondent sys of the side 2
8027 // 2. On the side 2, find the links most co-directed with the correspondent
8028 // links of the free border
8029 // -------------------------------------------------------------------------
8031 // 1. Since sewing may brake if there are volumes to split on the side 2,
8032 // we wont move nodes but just compute new coordinates for them
8033 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8034 TNodeXYZMap nBordXYZ;
8035 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8036 list< const SMDS_MeshNode* >::iterator nBordIt;
8038 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8039 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8040 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8041 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8042 double tol2 = 1.e-8;
8043 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8044 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8045 // Need node movement.
8047 // find X and Z axes to create trsf
8048 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8050 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8052 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8055 gp_Ax3 toBordAx( Pb1, Zb, X );
8056 gp_Ax3 fromSideAx( Ps1, Zs, X );
8057 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8059 gp_Trsf toBordSys, fromSide2Sys;
8060 toBordSys.SetTransformation( toBordAx );
8061 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8062 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8065 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8066 const SMDS_MeshNode* n = *nBordIt;
8067 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8068 toBordSys.Transforms( xyz );
8069 fromSide2Sys.Transforms( xyz );
8070 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8074 // just insert nodes XYZ in the nBordXYZ map
8075 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8076 const SMDS_MeshNode* n = *nBordIt;
8077 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8081 // 2. On the side 2, find the links most co-directed with the correspondent
8082 // links of the free border
8084 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8085 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8086 sideNodes.push_back( theSideFirstNode );
8088 bool hasVolumes = false;
8089 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8090 set<long> foundSideLinkIDs, checkedLinkIDs;
8091 SMDS_VolumeTool volume;
8092 //const SMDS_MeshNode* faceNodes[ 4 ];
8094 const SMDS_MeshNode* sideNode;
8095 const SMDS_MeshElement* sideElem;
8096 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8097 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8098 nBordIt = bordNodes.begin();
8100 // border node position and border link direction to compare with
8101 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8102 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8103 // choose next side node by link direction or by closeness to
8104 // the current border node:
8105 bool searchByDir = ( *nBordIt != theBordLastNode );
8107 // find the next node on the Side 2
8109 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8111 checkedLinkIDs.clear();
8112 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8114 // loop on inverse elements of current node (prevSideNode) on the Side 2
8115 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8116 while ( invElemIt->more() )
8118 const SMDS_MeshElement* elem = invElemIt->next();
8119 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8120 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8121 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8122 bool isVolume = volume.Set( elem );
8123 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8124 if ( isVolume ) // --volume
8126 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8127 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8128 if(elem->IsQuadratic()) {
8129 const SMDS_QuadraticFaceOfNodes* F =
8130 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8131 // use special nodes iterator
8132 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8133 while( anIter->more() ) {
8134 nodes[ iNode ] = anIter->next();
8135 if ( nodes[ iNode++ ] == prevSideNode )
8136 iPrevNode = iNode - 1;
8140 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8141 while ( nIt->more() ) {
8142 nodes[ iNode ] = cast2Node( nIt->next() );
8143 if ( nodes[ iNode++ ] == prevSideNode )
8144 iPrevNode = iNode - 1;
8147 // there are 2 links to check
8152 // loop on links, to be precise, on the second node of links
8153 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8154 const SMDS_MeshNode* n = nodes[ iNode ];
8156 if ( !volume.IsLinked( n, prevSideNode ))
8160 if ( iNode ) // a node before prevSideNode
8161 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8162 else // a node after prevSideNode
8163 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8165 // check if this link was already used
8166 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8167 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8168 if (!isJustChecked &&
8169 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8171 // test a link geometrically
8172 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8173 bool linkIsBetter = false;
8174 double dot = 0.0, dist = 0.0;
8175 if ( searchByDir ) { // choose most co-directed link
8176 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8177 linkIsBetter = ( dot > maxDot );
8179 else { // choose link with the node closest to bordPos
8180 dist = ( nextXYZ - bordPos ).SquareModulus();
8181 linkIsBetter = ( dist < minDist );
8183 if ( linkIsBetter ) {
8192 } // loop on inverse elements of prevSideNode
8195 MESSAGE(" Cant find path by links of the Side 2 ");
8196 return SEW_BAD_SIDE_NODES;
8198 sideNodes.push_back( sideNode );
8199 sideElems.push_back( sideElem );
8200 foundSideLinkIDs.insert ( linkID );
8201 prevSideNode = sideNode;
8203 if ( *nBordIt == theBordLastNode )
8204 searchByDir = false;
8206 // find the next border link to compare with
8207 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8208 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8209 // move to next border node if sideNode is before forward border node (bordPos)
8210 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8211 prevBordNode = *nBordIt;
8213 bordPos = nBordXYZ[ *nBordIt ];
8214 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8215 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8219 while ( sideNode != theSideSecondNode );
8221 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8222 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8223 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8225 } // end nodes search on the side 2
8227 // ============================
8228 // sew the border to the side 2
8229 // ============================
8231 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8232 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8234 TListOfListOfNodes nodeGroupsToMerge;
8235 if ( nbNodes[0] == nbNodes[1] ||
8236 ( theSideIsFreeBorder && !theSideThirdNode)) {
8238 // all nodes are to be merged
8240 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8241 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8242 nIt[0]++, nIt[1]++ )
8244 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8245 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8246 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8251 // insert new nodes into the border and the side to get equal nb of segments
8253 // get normalized parameters of nodes on the borders
8254 //double param[ 2 ][ maxNbNodes ];
8256 param[0] = new double [ maxNbNodes ];
8257 param[1] = new double [ maxNbNodes ];
8259 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8260 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8261 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8262 const SMDS_MeshNode* nPrev = *nIt;
8263 double bordLength = 0;
8264 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8265 const SMDS_MeshNode* nCur = *nIt;
8266 gp_XYZ segment (nCur->X() - nPrev->X(),
8267 nCur->Y() - nPrev->Y(),
8268 nCur->Z() - nPrev->Z());
8269 double segmentLen = segment.Modulus();
8270 bordLength += segmentLen;
8271 param[ iBord ][ iNode ] = bordLength;
8274 // normalize within [0,1]
8275 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8276 param[ iBord ][ iNode ] /= bordLength;
8280 // loop on border segments
8281 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8282 int i[ 2 ] = { 0, 0 };
8283 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8284 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8286 TElemOfNodeListMap insertMap;
8287 TElemOfNodeListMap::iterator insertMapIt;
8289 // key: elem to insert nodes into
8290 // value: 2 nodes to insert between + nodes to be inserted
8292 bool next[ 2 ] = { false, false };
8294 // find min adjacent segment length after sewing
8295 double nextParam = 10., prevParam = 0;
8296 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8297 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8298 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8299 if ( i[ iBord ] > 0 )
8300 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8302 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8303 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8304 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8306 // choose to insert or to merge nodes
8307 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8308 if ( Abs( du ) <= minSegLen * 0.2 ) {
8311 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8312 const SMDS_MeshNode* n0 = *nIt[0];
8313 const SMDS_MeshNode* n1 = *nIt[1];
8314 nodeGroupsToMerge.back().push_back( n1 );
8315 nodeGroupsToMerge.back().push_back( n0 );
8316 // position of node of the border changes due to merge
8317 param[ 0 ][ i[0] ] += du;
8318 // move n1 for the sake of elem shape evaluation during insertion.
8319 // n1 will be removed by MergeNodes() anyway
8320 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8321 next[0] = next[1] = true;
8326 int intoBord = ( du < 0 ) ? 0 : 1;
8327 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8328 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8329 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8330 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8331 if ( intoBord == 1 ) {
8332 // move node of the border to be on a link of elem of the side
8333 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8334 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8335 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8336 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8337 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8339 insertMapIt = insertMap.find( elem );
8340 bool notFound = ( insertMapIt == insertMap.end() );
8341 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8343 // insert into another link of the same element:
8344 // 1. perform insertion into the other link of the elem
8345 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8346 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8347 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8348 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8349 // 2. perform insertion into the link of adjacent faces
8351 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8353 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8357 if (toCreatePolyedrs) {
8358 // perform insertion into the links of adjacent volumes
8359 UpdateVolumes(n12, n22, nodeList);
8361 // 3. find an element appeared on n1 and n2 after the insertion
8362 insertMap.erase( elem );
8363 elem = findAdjacentFace( n1, n2, 0 );
8365 if ( notFound || otherLink ) {
8366 // add element and nodes of the side into the insertMap
8367 insertMapIt = insertMap.insert
8368 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8369 (*insertMapIt).second.push_back( n1 );
8370 (*insertMapIt).second.push_back( n2 );
8372 // add node to be inserted into elem
8373 (*insertMapIt).second.push_back( nIns );
8374 next[ 1 - intoBord ] = true;
8377 // go to the next segment
8378 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8379 if ( next[ iBord ] ) {
8380 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8382 nPrev[ iBord ] = *nIt[ iBord ];
8383 nIt[ iBord ]++; i[ iBord ]++;
8387 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8389 // perform insertion of nodes into elements
8391 for (insertMapIt = insertMap.begin();
8392 insertMapIt != insertMap.end();
8395 const SMDS_MeshElement* elem = (*insertMapIt).first;
8396 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8397 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8398 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8400 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8402 if ( !theSideIsFreeBorder ) {
8403 // look for and insert nodes into the faces adjacent to elem
8405 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8407 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8412 if (toCreatePolyedrs) {
8413 // perform insertion into the links of adjacent volumes
8414 UpdateVolumes(n1, n2, nodeList);
8420 } // end: insert new nodes
8422 MergeNodes ( nodeGroupsToMerge );
8427 //=======================================================================
8428 //function : InsertNodesIntoLink
8429 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8430 // and theBetweenNode2 and split theElement
8431 //=======================================================================
8433 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8434 const SMDS_MeshNode* theBetweenNode1,
8435 const SMDS_MeshNode* theBetweenNode2,
8436 list<const SMDS_MeshNode*>& theNodesToInsert,
8437 const bool toCreatePoly)
8439 if ( theFace->GetType() != SMDSAbs_Face ) return;
8441 // find indices of 2 link nodes and of the rest nodes
8442 int iNode = 0, il1, il2, i3, i4;
8443 il1 = il2 = i3 = i4 = -1;
8444 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8445 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8447 if(theFace->IsQuadratic()) {
8448 const SMDS_QuadraticFaceOfNodes* F =
8449 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8450 // use special nodes iterator
8451 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8452 while( anIter->more() ) {
8453 const SMDS_MeshNode* n = anIter->next();
8454 if ( n == theBetweenNode1 )
8456 else if ( n == theBetweenNode2 )
8462 nodes[ iNode++ ] = n;
8466 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8467 while ( nodeIt->more() ) {
8468 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8469 if ( n == theBetweenNode1 )
8471 else if ( n == theBetweenNode2 )
8477 nodes[ iNode++ ] = n;
8480 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8483 // arrange link nodes to go one after another regarding the face orientation
8484 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8485 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8490 aNodesToInsert.reverse();
8492 // check that not link nodes of a quadrangles are in good order
8493 int nbFaceNodes = theFace->NbNodes();
8494 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8500 if (toCreatePoly || theFace->IsPoly()) {
8503 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8505 // add nodes of face up to first node of link
8508 if(theFace->IsQuadratic()) {
8509 const SMDS_QuadraticFaceOfNodes* F =
8510 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8511 // use special nodes iterator
8512 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8513 while( anIter->more() && !isFLN ) {
8514 const SMDS_MeshNode* n = anIter->next();
8515 poly_nodes[iNode++] = n;
8516 if (n == nodes[il1]) {
8520 // add nodes to insert
8521 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8522 for (; nIt != aNodesToInsert.end(); nIt++) {
8523 poly_nodes[iNode++] = *nIt;
8525 // add nodes of face starting from last node of link
8526 while ( anIter->more() ) {
8527 poly_nodes[iNode++] = anIter->next();
8531 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8532 while ( nodeIt->more() && !isFLN ) {
8533 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8534 poly_nodes[iNode++] = n;
8535 if (n == nodes[il1]) {
8539 // add nodes to insert
8540 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8541 for (; nIt != aNodesToInsert.end(); nIt++) {
8542 poly_nodes[iNode++] = *nIt;
8544 // add nodes of face starting from last node of link
8545 while ( nodeIt->more() ) {
8546 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8547 poly_nodes[iNode++] = n;
8551 // edit or replace the face
8552 SMESHDS_Mesh *aMesh = GetMeshDS();
8554 if (theFace->IsPoly()) {
8555 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8558 int aShapeId = FindShape( theFace );
8560 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8561 myLastCreatedElems.Append(newElem);
8562 if ( aShapeId && newElem )
8563 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8565 aMesh->RemoveElement(theFace);
8570 if( !theFace->IsQuadratic() ) {
8572 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8573 int nbLinkNodes = 2 + aNodesToInsert.size();
8574 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8575 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8576 linkNodes[ 0 ] = nodes[ il1 ];
8577 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8578 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8579 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8580 linkNodes[ iNode++ ] = *nIt;
8582 // decide how to split a quadrangle: compare possible variants
8583 // and choose which of splits to be a quadrangle
8584 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8585 if ( nbFaceNodes == 3 ) {
8586 iBestQuad = nbSplits;
8589 else if ( nbFaceNodes == 4 ) {
8590 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8591 double aBestRate = DBL_MAX;
8592 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8594 double aBadRate = 0;
8595 // evaluate elements quality
8596 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8597 if ( iSplit == iQuad ) {
8598 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8602 aBadRate += getBadRate( &quad, aCrit );
8605 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8607 nodes[ iSplit < iQuad ? i4 : i3 ]);
8608 aBadRate += getBadRate( &tria, aCrit );
8612 if ( aBadRate < aBestRate ) {
8614 aBestRate = aBadRate;
8619 // create new elements
8620 SMESHDS_Mesh *aMesh = GetMeshDS();
8621 int aShapeId = FindShape( theFace );
8624 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8625 SMDS_MeshElement* newElem = 0;
8626 if ( iSplit == iBestQuad )
8627 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8632 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8634 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8635 myLastCreatedElems.Append(newElem);
8636 if ( aShapeId && newElem )
8637 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8640 // change nodes of theFace
8641 const SMDS_MeshNode* newNodes[ 4 ];
8642 newNodes[ 0 ] = linkNodes[ i1 ];
8643 newNodes[ 1 ] = linkNodes[ i2 ];
8644 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8645 newNodes[ 3 ] = nodes[ i4 ];
8646 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8647 } // end if(!theFace->IsQuadratic())
8648 else { // theFace is quadratic
8649 // we have to split theFace on simple triangles and one simple quadrangle
8651 int nbshift = tmp*2;
8652 // shift nodes in nodes[] by nbshift
8654 for(i=0; i<nbshift; i++) {
8655 const SMDS_MeshNode* n = nodes[0];
8656 for(j=0; j<nbFaceNodes-1; j++) {
8657 nodes[j] = nodes[j+1];
8659 nodes[nbFaceNodes-1] = n;
8661 il1 = il1 - nbshift;
8662 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8663 // n0 n1 n2 n0 n1 n2
8664 // +-----+-----+ +-----+-----+
8673 // create new elements
8674 SMESHDS_Mesh *aMesh = GetMeshDS();
8675 int aShapeId = FindShape( theFace );
8678 if(nbFaceNodes==6) { // quadratic triangle
8679 SMDS_MeshElement* newElem =
8680 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8681 myLastCreatedElems.Append(newElem);
8682 if ( aShapeId && newElem )
8683 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8684 if(theFace->IsMediumNode(nodes[il1])) {
8685 // create quadrangle
8686 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8687 myLastCreatedElems.Append(newElem);
8688 if ( aShapeId && newElem )
8689 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8695 // create quadrangle
8696 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8697 myLastCreatedElems.Append(newElem);
8698 if ( aShapeId && newElem )
8699 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8705 else { // nbFaceNodes==8 - quadratic quadrangle
8706 SMDS_MeshElement* newElem =
8707 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8708 myLastCreatedElems.Append(newElem);
8709 if ( aShapeId && newElem )
8710 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8711 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8712 myLastCreatedElems.Append(newElem);
8713 if ( aShapeId && newElem )
8714 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8715 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8716 myLastCreatedElems.Append(newElem);
8717 if ( aShapeId && newElem )
8718 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8719 if(theFace->IsMediumNode(nodes[il1])) {
8720 // create quadrangle
8721 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8722 myLastCreatedElems.Append(newElem);
8723 if ( aShapeId && newElem )
8724 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8730 // create quadrangle
8731 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8732 myLastCreatedElems.Append(newElem);
8733 if ( aShapeId && newElem )
8734 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8740 // create needed triangles using n1,n2,n3 and inserted nodes
8741 int nbn = 2 + aNodesToInsert.size();
8742 //const SMDS_MeshNode* aNodes[nbn];
8743 vector<const SMDS_MeshNode*> aNodes(nbn);
8744 aNodes[0] = nodes[n1];
8745 aNodes[nbn-1] = nodes[n2];
8746 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8747 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8748 aNodes[iNode++] = *nIt;
8750 for(i=1; i<nbn; i++) {
8751 SMDS_MeshElement* newElem =
8752 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8753 myLastCreatedElems.Append(newElem);
8754 if ( aShapeId && newElem )
8755 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8757 // remove old quadratic face
8758 aMesh->RemoveElement(theFace);
8762 //=======================================================================
8763 //function : UpdateVolumes
8765 //=======================================================================
8766 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8767 const SMDS_MeshNode* theBetweenNode2,
8768 list<const SMDS_MeshNode*>& theNodesToInsert)
8770 myLastCreatedElems.Clear();
8771 myLastCreatedNodes.Clear();
8773 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8774 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8775 const SMDS_MeshElement* elem = invElemIt->next();
8777 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8778 SMDS_VolumeTool aVolume (elem);
8779 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8782 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8783 int iface, nbFaces = aVolume.NbFaces();
8784 vector<const SMDS_MeshNode *> poly_nodes;
8785 vector<int> quantities (nbFaces);
8787 for (iface = 0; iface < nbFaces; iface++) {
8788 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8789 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8790 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8792 for (int inode = 0; inode < nbFaceNodes; inode++) {
8793 poly_nodes.push_back(faceNodes[inode]);
8795 if (nbInserted == 0) {
8796 if (faceNodes[inode] == theBetweenNode1) {
8797 if (faceNodes[inode + 1] == theBetweenNode2) {
8798 nbInserted = theNodesToInsert.size();
8800 // add nodes to insert
8801 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8802 for (; nIt != theNodesToInsert.end(); nIt++) {
8803 poly_nodes.push_back(*nIt);
8807 else if (faceNodes[inode] == theBetweenNode2) {
8808 if (faceNodes[inode + 1] == theBetweenNode1) {
8809 nbInserted = theNodesToInsert.size();
8811 // add nodes to insert in reversed order
8812 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8814 for (; nIt != theNodesToInsert.begin(); nIt--) {
8815 poly_nodes.push_back(*nIt);
8817 poly_nodes.push_back(*nIt);
8824 quantities[iface] = nbFaceNodes + nbInserted;
8827 // Replace or update the volume
8828 SMESHDS_Mesh *aMesh = GetMeshDS();
8830 if (elem->IsPoly()) {
8831 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8835 int aShapeId = FindShape( elem );
8837 SMDS_MeshElement* newElem =
8838 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8839 myLastCreatedElems.Append(newElem);
8840 if (aShapeId && newElem)
8841 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8843 aMesh->RemoveElement(elem);
8848 //=======================================================================
8850 * \brief Convert elements contained in a submesh to quadratic
8851 * \retval int - nb of checked elements
8853 //=======================================================================
8855 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8856 SMESH_MesherHelper& theHelper,
8857 const bool theForce3d)
8860 if( !theSm ) return nbElem;
8862 const bool notFromGroups = false;
8863 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8864 while(ElemItr->more())
8867 const SMDS_MeshElement* elem = ElemItr->next();
8868 if( !elem || elem->IsQuadratic() ) continue;
8870 int id = elem->GetID();
8871 int nbNodes = elem->NbNodes();
8872 vector<const SMDS_MeshNode *> aNds (nbNodes);
8874 for(int i = 0; i < nbNodes; i++)
8876 aNds[i] = elem->GetNode(i);
8878 SMDSAbs_ElementType aType = elem->GetType();
8880 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8882 const SMDS_MeshElement* NewElem = 0;
8888 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8896 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8899 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8906 case SMDSAbs_Volume :
8911 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8914 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8917 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8920 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8921 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8931 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8933 theSm->AddElement( NewElem );
8938 //=======================================================================
8939 //function : ConvertToQuadratic
8941 //=======================================================================
8942 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8944 SMESHDS_Mesh* meshDS = GetMeshDS();
8946 SMESH_MesherHelper aHelper(*myMesh);
8947 aHelper.SetIsQuadratic( true );
8948 const bool notFromGroups = false;
8950 int nbCheckedElems = 0;
8951 if ( myMesh->HasShapeToMesh() )
8953 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8955 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8956 while ( smIt->more() ) {
8957 SMESH_subMesh* sm = smIt->next();
8958 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8959 aHelper.SetSubShape( sm->GetSubShape() );
8960 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8965 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8966 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8968 SMESHDS_SubMesh *smDS = 0;
8969 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8970 while(aEdgeItr->more())
8972 const SMDS_MeshEdge* edge = aEdgeItr->next();
8973 if(edge && !edge->IsQuadratic())
8975 int id = edge->GetID();
8976 const SMDS_MeshNode* n1 = edge->GetNode(0);
8977 const SMDS_MeshNode* n2 = edge->GetNode(1);
8979 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8981 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8982 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8985 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8986 while(aFaceItr->more())
8988 const SMDS_MeshFace* face = aFaceItr->next();
8989 if(!face || face->IsQuadratic() ) continue;
8991 int id = face->GetID();
8992 int nbNodes = face->NbNodes();
8993 vector<const SMDS_MeshNode *> aNds (nbNodes);
8995 for(int i = 0; i < nbNodes; i++)
8997 aNds[i] = face->GetNode(i);
9000 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9002 SMDS_MeshFace * NewFace = 0;
9006 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9009 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9014 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9016 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9017 while(aVolumeItr->more())
9019 const SMDS_MeshVolume* volume = aVolumeItr->next();
9020 if(!volume || volume->IsQuadratic() ) continue;
9022 int id = volume->GetID();
9023 int nbNodes = volume->NbNodes();
9024 vector<const SMDS_MeshNode *> aNds (nbNodes);
9026 for(int i = 0; i < nbNodes; i++)
9028 aNds[i] = volume->GetNode(i);
9031 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9033 SMDS_MeshVolume * NewVolume = 0;
9037 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9038 aNds[3], id, theForce3d );
9041 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9042 aNds[3], aNds[4], id, theForce3d);
9045 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9046 aNds[3], aNds[4], aNds[5], id, theForce3d);
9049 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9050 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9055 ReplaceElemInGroups(volume, NewVolume, meshDS);
9058 if ( !theForce3d ) {
9059 aHelper.SetSubShape(0); // apply to the whole mesh
9060 aHelper.FixQuadraticElements();
9064 //=======================================================================
9066 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9067 * \retval int - nb of checked elements
9069 //=======================================================================
9071 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9072 SMDS_ElemIteratorPtr theItr,
9073 const int theShapeID)
9076 SMESHDS_Mesh* meshDS = GetMeshDS();
9077 const bool notFromGroups = false;
9079 while( theItr->more() )
9081 const SMDS_MeshElement* elem = theItr->next();
9083 if( elem && elem->IsQuadratic())
9085 int id = elem->GetID();
9086 int nbNodes = elem->NbNodes();
9087 vector<const SMDS_MeshNode *> aNds, mediumNodes;
9088 aNds.reserve( nbNodes );
9089 mediumNodes.reserve( nbNodes );
9091 for(int i = 0; i < nbNodes; i++)
9093 const SMDS_MeshNode* n = elem->GetNode(i);
9095 if( elem->IsMediumNode( n ) )
9096 mediumNodes.push_back( n );
9098 aNds.push_back( n );
9100 if( aNds.empty() ) continue;
9101 SMDSAbs_ElementType aType = elem->GetType();
9103 //remove old quadratic element
9104 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9106 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9107 ReplaceElemInGroups(elem, NewElem, meshDS);
9108 if( theSm && NewElem )
9109 theSm->AddElement( NewElem );
9111 // remove medium nodes
9112 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9113 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9114 const SMDS_MeshNode* n = *nIt;
9115 if ( n->NbInverseElements() == 0 ) {
9116 if ( n->GetPosition()->GetShapeId() != theShapeID )
9117 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9118 ( n->GetPosition()->GetShapeId() ));
9120 meshDS->RemoveFreeNode( n, theSm );
9128 //=======================================================================
9129 //function : ConvertFromQuadratic
9131 //=======================================================================
9132 bool SMESH_MeshEditor::ConvertFromQuadratic()
9134 int nbCheckedElems = 0;
9135 if ( myMesh->HasShapeToMesh() )
9137 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9139 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9140 while ( smIt->more() ) {
9141 SMESH_subMesh* sm = smIt->next();
9142 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9143 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9149 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9150 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9152 SMESHDS_SubMesh *aSM = 0;
9153 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9159 //=======================================================================
9160 //function : SewSideElements
9162 //=======================================================================
9164 SMESH_MeshEditor::Sew_Error
9165 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9166 TIDSortedElemSet& theSide2,
9167 const SMDS_MeshNode* theFirstNode1,
9168 const SMDS_MeshNode* theFirstNode2,
9169 const SMDS_MeshNode* theSecondNode1,
9170 const SMDS_MeshNode* theSecondNode2)
9172 myLastCreatedElems.Clear();
9173 myLastCreatedNodes.Clear();
9175 MESSAGE ("::::SewSideElements()");
9176 if ( theSide1.size() != theSide2.size() )
9177 return SEW_DIFF_NB_OF_ELEMENTS;
9179 Sew_Error aResult = SEW_OK;
9181 // 1. Build set of faces representing each side
9182 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9183 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9185 // =======================================================================
9186 // 1. Build set of faces representing each side:
9187 // =======================================================================
9188 // a. build set of nodes belonging to faces
9189 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9190 // c. create temporary faces representing side of volumes if correspondent
9191 // face does not exist
9193 SMESHDS_Mesh* aMesh = GetMeshDS();
9194 SMDS_Mesh aTmpFacesMesh;
9195 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9196 set<const SMDS_MeshElement*> volSet1, volSet2;
9197 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9198 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9199 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9200 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9201 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9202 int iSide, iFace, iNode;
9204 for ( iSide = 0; iSide < 2; iSide++ ) {
9205 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9206 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9207 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9208 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9209 set<const SMDS_MeshElement*>::iterator vIt;
9210 TIDSortedElemSet::iterator eIt;
9211 set<const SMDS_MeshNode*>::iterator nIt;
9213 // check that given nodes belong to given elements
9214 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9215 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9216 int firstIndex = -1, secondIndex = -1;
9217 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9218 const SMDS_MeshElement* elem = *eIt;
9219 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9220 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9221 if ( firstIndex > -1 && secondIndex > -1 ) break;
9223 if ( firstIndex < 0 || secondIndex < 0 ) {
9224 // we can simply return until temporary faces created
9225 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9228 // -----------------------------------------------------------
9229 // 1a. Collect nodes of existing faces
9230 // and build set of face nodes in order to detect missing
9231 // faces corresponing to sides of volumes
9232 // -----------------------------------------------------------
9234 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9236 // loop on the given element of a side
9237 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9238 //const SMDS_MeshElement* elem = *eIt;
9239 const SMDS_MeshElement* elem = *eIt;
9240 if ( elem->GetType() == SMDSAbs_Face ) {
9241 faceSet->insert( elem );
9242 set <const SMDS_MeshNode*> faceNodeSet;
9243 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9244 while ( nodeIt->more() ) {
9245 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9246 nodeSet->insert( n );
9247 faceNodeSet.insert( n );
9249 setOfFaceNodeSet.insert( faceNodeSet );
9251 else if ( elem->GetType() == SMDSAbs_Volume )
9252 volSet->insert( elem );
9254 // ------------------------------------------------------------------------------
9255 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9256 // ------------------------------------------------------------------------------
9258 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9259 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9260 while ( fIt->more() ) { // loop on faces sharing a node
9261 const SMDS_MeshElement* f = fIt->next();
9262 if ( faceSet->find( f ) == faceSet->end() ) {
9263 // check if all nodes are in nodeSet and
9264 // complete setOfFaceNodeSet if they are
9265 set <const SMDS_MeshNode*> faceNodeSet;
9266 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9267 bool allInSet = true;
9268 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9269 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9270 if ( nodeSet->find( n ) == nodeSet->end() )
9273 faceNodeSet.insert( n );
9276 faceSet->insert( f );
9277 setOfFaceNodeSet.insert( faceNodeSet );
9283 // -------------------------------------------------------------------------
9284 // 1c. Create temporary faces representing sides of volumes if correspondent
9285 // face does not exist
9286 // -------------------------------------------------------------------------
9288 if ( !volSet->empty() ) {
9289 //int nodeSetSize = nodeSet->size();
9291 // loop on given volumes
9292 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9293 SMDS_VolumeTool vol (*vIt);
9294 // loop on volume faces: find free faces
9295 // --------------------------------------
9296 list<const SMDS_MeshElement* > freeFaceList;
9297 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9298 if ( !vol.IsFreeFace( iFace ))
9300 // check if there is already a face with same nodes in a face set
9301 const SMDS_MeshElement* aFreeFace = 0;
9302 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9303 int nbNodes = vol.NbFaceNodes( iFace );
9304 set <const SMDS_MeshNode*> faceNodeSet;
9305 vol.GetFaceNodes( iFace, faceNodeSet );
9306 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9308 // no such a face is given but it still can exist, check it
9309 if ( nbNodes == 3 ) {
9310 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9312 else if ( nbNodes == 4 ) {
9313 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9316 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9317 aFreeFace = aMesh->FindFace(poly_nodes);
9321 // create a temporary face
9322 if ( nbNodes == 3 ) {
9323 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9325 else if ( nbNodes == 4 ) {
9326 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9329 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9330 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9334 freeFaceList.push_back( aFreeFace );
9336 } // loop on faces of a volume
9338 // choose one of several free faces
9339 // --------------------------------------
9340 if ( freeFaceList.size() > 1 ) {
9341 // choose a face having max nb of nodes shared by other elems of a side
9342 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9343 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9344 while ( fIt != freeFaceList.end() ) { // loop on free faces
9345 int nbSharedNodes = 0;
9346 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9347 while ( nodeIt->more() ) { // loop on free face nodes
9348 const SMDS_MeshNode* n =
9349 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9350 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9351 while ( invElemIt->more() ) {
9352 const SMDS_MeshElement* e = invElemIt->next();
9353 if ( faceSet->find( e ) != faceSet->end() )
9355 if ( elemSet->find( e ) != elemSet->end() )
9359 if ( nbSharedNodes >= maxNbNodes ) {
9360 maxNbNodes = nbSharedNodes;
9364 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9366 if ( freeFaceList.size() > 1 )
9368 // could not choose one face, use another way
9369 // choose a face most close to the bary center of the opposite side
9370 gp_XYZ aBC( 0., 0., 0. );
9371 set <const SMDS_MeshNode*> addedNodes;
9372 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9373 eIt = elemSet2->begin();
9374 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9375 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9376 while ( nodeIt->more() ) { // loop on free face nodes
9377 const SMDS_MeshNode* n =
9378 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9379 if ( addedNodes.insert( n ).second )
9380 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9383 aBC /= addedNodes.size();
9384 double minDist = DBL_MAX;
9385 fIt = freeFaceList.begin();
9386 while ( fIt != freeFaceList.end() ) { // loop on free faces
9388 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9389 while ( nodeIt->more() ) { // loop on free face nodes
9390 const SMDS_MeshNode* n =
9391 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9392 gp_XYZ p( n->X(),n->Y(),n->Z() );
9393 dist += ( aBC - p ).SquareModulus();
9395 if ( dist < minDist ) {
9397 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9400 fIt = freeFaceList.erase( fIt++ );
9403 } // choose one of several free faces of a volume
9405 if ( freeFaceList.size() == 1 ) {
9406 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9407 faceSet->insert( aFreeFace );
9408 // complete a node set with nodes of a found free face
9409 // for ( iNode = 0; iNode < ; iNode++ )
9410 // nodeSet->insert( fNodes[ iNode ] );
9413 } // loop on volumes of a side
9415 // // complete a set of faces if new nodes in a nodeSet appeared
9416 // // ----------------------------------------------------------
9417 // if ( nodeSetSize != nodeSet->size() ) {
9418 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9419 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9420 // while ( fIt->more() ) { // loop on faces sharing a node
9421 // const SMDS_MeshElement* f = fIt->next();
9422 // if ( faceSet->find( f ) == faceSet->end() ) {
9423 // // check if all nodes are in nodeSet and
9424 // // complete setOfFaceNodeSet if they are
9425 // set <const SMDS_MeshNode*> faceNodeSet;
9426 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9427 // bool allInSet = true;
9428 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9429 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9430 // if ( nodeSet->find( n ) == nodeSet->end() )
9431 // allInSet = false;
9433 // faceNodeSet.insert( n );
9435 // if ( allInSet ) {
9436 // faceSet->insert( f );
9437 // setOfFaceNodeSet.insert( faceNodeSet );
9443 } // Create temporary faces, if there are volumes given
9446 if ( faceSet1.size() != faceSet2.size() ) {
9447 // delete temporary faces: they are in reverseElements of actual nodes
9448 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9449 while ( tmpFaceIt->more() )
9450 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9451 MESSAGE("Diff nb of faces");
9452 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9455 // ============================================================
9456 // 2. Find nodes to merge:
9457 // bind a node to remove to a node to put instead
9458 // ============================================================
9460 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9461 if ( theFirstNode1 != theFirstNode2 )
9462 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9463 if ( theSecondNode1 != theSecondNode2 )
9464 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9466 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9467 set< long > linkIdSet; // links to process
9468 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9470 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9471 list< NLink > linkList[2];
9472 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9473 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9474 // loop on links in linkList; find faces by links and append links
9475 // of the found faces to linkList
9476 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9477 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9478 NLink link[] = { *linkIt[0], *linkIt[1] };
9479 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9480 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9483 // by links, find faces in the face sets,
9484 // and find indices of link nodes in the found faces;
9485 // in a face set, there is only one or no face sharing a link
9486 // ---------------------------------------------------------------
9488 const SMDS_MeshElement* face[] = { 0, 0 };
9489 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9490 vector<const SMDS_MeshNode*> fnodes1(9);
9491 vector<const SMDS_MeshNode*> fnodes2(9);
9492 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9493 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9494 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9495 int iLinkNode[2][2];
9496 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9497 const SMDS_MeshNode* n1 = link[iSide].first;
9498 const SMDS_MeshNode* n2 = link[iSide].second;
9499 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9500 set< const SMDS_MeshElement* > fMap;
9501 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9502 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9503 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9504 while ( fIt->more() ) { // loop on faces sharing a node
9505 const SMDS_MeshElement* f = fIt->next();
9506 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9507 ! fMap.insert( f ).second ) // f encounters twice
9509 if ( face[ iSide ] ) {
9510 MESSAGE( "2 faces per link " );
9511 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9515 faceSet->erase( f );
9516 // get face nodes and find ones of a link
9521 fnodes1.resize(f->NbNodes()+1);
9522 notLinkNodes1.resize(f->NbNodes()-2);
9525 fnodes2.resize(f->NbNodes()+1);
9526 notLinkNodes2.resize(f->NbNodes()-2);
9529 if(!f->IsQuadratic()) {
9530 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9531 while ( nIt->more() ) {
9532 const SMDS_MeshNode* n =
9533 static_cast<const SMDS_MeshNode*>( nIt->next() );
9535 iLinkNode[ iSide ][ 0 ] = iNode;
9537 else if ( n == n2 ) {
9538 iLinkNode[ iSide ][ 1 ] = iNode;
9540 //else if ( notLinkNodes[ iSide ][ 0 ] )
9541 // notLinkNodes[ iSide ][ 1 ] = n;
9543 // notLinkNodes[ iSide ][ 0 ] = n;
9547 notLinkNodes1[nbl] = n;
9548 //notLinkNodes1.push_back(n);
9550 notLinkNodes2[nbl] = n;
9551 //notLinkNodes2.push_back(n);
9553 //faceNodes[ iSide ][ iNode++ ] = n;
9555 fnodes1[iNode++] = n;
9558 fnodes2[iNode++] = n;
9562 else { // f->IsQuadratic()
9563 const SMDS_QuadraticFaceOfNodes* F =
9564 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9565 // use special nodes iterator
9566 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9567 while ( anIter->more() ) {
9568 const SMDS_MeshNode* n =
9569 static_cast<const SMDS_MeshNode*>( anIter->next() );
9571 iLinkNode[ iSide ][ 0 ] = iNode;
9573 else if ( n == n2 ) {
9574 iLinkNode[ iSide ][ 1 ] = iNode;
9579 notLinkNodes1[nbl] = n;
9582 notLinkNodes2[nbl] = n;
9586 fnodes1[iNode++] = n;
9589 fnodes2[iNode++] = n;
9593 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9595 fnodes1[iNode] = fnodes1[0];
9598 fnodes2[iNode] = fnodes1[0];
9605 // check similarity of elements of the sides
9606 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9607 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9608 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9609 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9612 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9614 break; // do not return because it s necessary to remove tmp faces
9617 // set nodes to merge
9618 // -------------------
9620 if ( face[0] && face[1] ) {
9621 int nbNodes = face[0]->NbNodes();
9622 if ( nbNodes != face[1]->NbNodes() ) {
9623 MESSAGE("Diff nb of face nodes");
9624 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9625 break; // do not return because it s necessary to remove tmp faces
9627 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9628 if ( nbNodes == 3 ) {
9629 //nReplaceMap.insert( TNodeNodeMap::value_type
9630 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9631 nReplaceMap.insert( TNodeNodeMap::value_type
9632 ( notLinkNodes1[0], notLinkNodes2[0] ));
9635 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9636 // analyse link orientation in faces
9637 int i1 = iLinkNode[ iSide ][ 0 ];
9638 int i2 = iLinkNode[ iSide ][ 1 ];
9639 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9640 // if notLinkNodes are the first and the last ones, then
9641 // their order does not correspond to the link orientation
9642 if (( i1 == 1 && i2 == 2 ) ||
9643 ( i1 == 2 && i2 == 1 ))
9644 reverse[ iSide ] = !reverse[ iSide ];
9646 if ( reverse[0] == reverse[1] ) {
9647 //nReplaceMap.insert( TNodeNodeMap::value_type
9648 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9649 //nReplaceMap.insert( TNodeNodeMap::value_type
9650 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9651 for(int nn=0; nn<nbNodes-2; nn++) {
9652 nReplaceMap.insert( TNodeNodeMap::value_type
9653 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9657 //nReplaceMap.insert( TNodeNodeMap::value_type
9658 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9659 //nReplaceMap.insert( TNodeNodeMap::value_type
9660 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9661 for(int nn=0; nn<nbNodes-2; nn++) {
9662 nReplaceMap.insert( TNodeNodeMap::value_type
9663 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9668 // add other links of the faces to linkList
9669 // -----------------------------------------
9671 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9672 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9673 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9674 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9675 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9676 if ( !iter_isnew.second ) { // already in a set: no need to process
9677 linkIdSet.erase( iter_isnew.first );
9679 else // new in set == encountered for the first time: add
9681 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9682 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9683 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9684 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9685 linkList[0].push_back ( NLink( n1, n2 ));
9686 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9690 } // loop on link lists
9692 if ( aResult == SEW_OK &&
9693 ( linkIt[0] != linkList[0].end() ||
9694 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9695 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9696 " " << (faceSetPtr[1]->empty()));
9697 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9700 // ====================================================================
9701 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9702 // ====================================================================
9704 // delete temporary faces: they are in reverseElements of actual nodes
9705 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9706 while ( tmpFaceIt->more() )
9707 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9709 if ( aResult != SEW_OK)
9712 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9713 // loop on nodes replacement map
9714 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9715 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9716 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9717 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9718 nodeIDsToRemove.push_back( nToRemove->GetID() );
9719 // loop on elements sharing nToRemove
9720 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9721 while ( invElemIt->more() ) {
9722 const SMDS_MeshElement* e = invElemIt->next();
9723 // get a new suite of nodes: make replacement
9724 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9725 vector< const SMDS_MeshNode*> nodes( nbNodes );
9726 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9727 while ( nIt->more() ) {
9728 const SMDS_MeshNode* n =
9729 static_cast<const SMDS_MeshNode*>( nIt->next() );
9730 nnIt = nReplaceMap.find( n );
9731 if ( nnIt != nReplaceMap.end() ) {
9737 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9738 // elemIDsToRemove.push_back( e->GetID() );
9741 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9745 Remove( nodeIDsToRemove, true );
9750 //================================================================================
9752 * \brief Find corresponding nodes in two sets of faces
9753 * \param theSide1 - first face set
9754 * \param theSide2 - second first face
9755 * \param theFirstNode1 - a boundary node of set 1
9756 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9757 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9758 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9759 * \param nReplaceMap - output map of corresponding nodes
9760 * \retval bool - is a success or not
9762 //================================================================================
9765 //#define DEBUG_MATCHING_NODES
9768 SMESH_MeshEditor::Sew_Error
9769 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9770 set<const SMDS_MeshElement*>& theSide2,
9771 const SMDS_MeshNode* theFirstNode1,
9772 const SMDS_MeshNode* theFirstNode2,
9773 const SMDS_MeshNode* theSecondNode1,
9774 const SMDS_MeshNode* theSecondNode2,
9775 TNodeNodeMap & nReplaceMap)
9777 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9779 nReplaceMap.clear();
9780 if ( theFirstNode1 != theFirstNode2 )
9781 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9782 if ( theSecondNode1 != theSecondNode2 )
9783 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9785 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9786 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9788 list< NLink > linkList[2];
9789 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9790 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9792 // loop on links in linkList; find faces by links and append links
9793 // of the found faces to linkList
9794 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9795 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9796 NLink link[] = { *linkIt[0], *linkIt[1] };
9797 if ( linkSet.find( link[0] ) == linkSet.end() )
9800 // by links, find faces in the face sets,
9801 // and find indices of link nodes in the found faces;
9802 // in a face set, there is only one or no face sharing a link
9803 // ---------------------------------------------------------------
9805 const SMDS_MeshElement* face[] = { 0, 0 };
9806 list<const SMDS_MeshNode*> notLinkNodes[2];
9807 //bool reverse[] = { false, false }; // order of notLinkNodes
9809 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9811 const SMDS_MeshNode* n1 = link[iSide].first;
9812 const SMDS_MeshNode* n2 = link[iSide].second;
9813 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9814 set< const SMDS_MeshElement* > facesOfNode1;
9815 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9817 // during a loop of the first node, we find all faces around n1,
9818 // during a loop of the second node, we find one face sharing both n1 and n2
9819 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9820 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9821 while ( fIt->more() ) { // loop on faces sharing a node
9822 const SMDS_MeshElement* f = fIt->next();
9823 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9824 ! facesOfNode1.insert( f ).second ) // f encounters twice
9826 if ( face[ iSide ] ) {
9827 MESSAGE( "2 faces per link " );
9828 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9831 faceSet->erase( f );
9833 // get not link nodes
9834 int nbN = f->NbNodes();
9835 if ( f->IsQuadratic() )
9837 nbNodes[ iSide ] = nbN;
9838 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9839 int i1 = f->GetNodeIndex( n1 );
9840 int i2 = f->GetNodeIndex( n2 );
9841 int iEnd = nbN, iBeg = -1, iDelta = 1;
9842 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9844 std::swap( iEnd, iBeg ); iDelta = -1;
9849 if ( i == iEnd ) i = iBeg + iDelta;
9850 if ( i == i1 ) break;
9851 nodes.push_back ( f->GetNode( i ) );
9857 // check similarity of elements of the sides
9858 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9859 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9860 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9861 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9864 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9868 // set nodes to merge
9869 // -------------------
9871 if ( face[0] && face[1] ) {
9872 if ( nbNodes[0] != nbNodes[1] ) {
9873 MESSAGE("Diff nb of face nodes");
9874 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9876 #ifdef DEBUG_MATCHING_NODES
9877 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9878 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9879 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9881 int nbN = nbNodes[0];
9883 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9884 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9885 for ( int i = 0 ; i < nbN - 2; ++i ) {
9886 #ifdef DEBUG_MATCHING_NODES
9887 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9889 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9893 // add other links of the face 1 to linkList
9894 // -----------------------------------------
9896 const SMDS_MeshElement* f0 = face[0];
9897 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9898 for ( int i = 0; i < nbN; i++ )
9900 const SMDS_MeshNode* n2 = f0->GetNode( i );
9901 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9902 linkSet.insert( SMESH_TLink( n1, n2 ));
9903 if ( !iter_isnew.second ) { // already in a set: no need to process
9904 linkSet.erase( iter_isnew.first );
9906 else // new in set == encountered for the first time: add
9908 #ifdef DEBUG_MATCHING_NODES
9909 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9910 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9912 linkList[0].push_back ( NLink( n1, n2 ));
9913 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9918 } // loop on link lists
9923 //================================================================================
9925 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9926 \param theElems - the list of elements (edges or faces) to be replicated
9927 The nodes for duplication could be found from these elements
9928 \param theNodesNot - list of nodes to NOT replicate
9929 \param theAffectedElems - the list of elements (cells and edges) to which the
9930 replicated nodes should be associated to.
9931 \return TRUE if operation has been completed successfully, FALSE otherwise
9933 //================================================================================
9935 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9936 const TIDSortedElemSet& theNodesNot,
9937 const TIDSortedElemSet& theAffectedElems )
9939 myLastCreatedElems.Clear();
9940 myLastCreatedNodes.Clear();
9942 if ( theElems.size() == 0 )
9945 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9950 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9951 // duplicate elements and nodes
9952 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9953 // replce nodes by duplications
9954 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9958 //================================================================================
9960 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9961 \param theMeshDS - mesh instance
9962 \param theElems - the elements replicated or modified (nodes should be changed)
9963 \param theNodesNot - nodes to NOT replicate
9964 \param theNodeNodeMap - relation of old node to new created node
9965 \param theIsDoubleElem - flag os to replicate element or modify
9966 \return TRUE if operation has been completed successfully, FALSE otherwise
9968 //================================================================================
9970 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9971 const TIDSortedElemSet& theElems,
9972 const TIDSortedElemSet& theNodesNot,
9973 std::map< const SMDS_MeshNode*,
9974 const SMDS_MeshNode* >& theNodeNodeMap,
9975 const bool theIsDoubleElem )
9977 // iterate on through element and duplicate them (by nodes duplication)
9979 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9980 for ( ; elemItr != theElems.end(); ++elemItr )
9982 const SMDS_MeshElement* anElem = *elemItr;
9986 bool isDuplicate = false;
9987 // duplicate nodes to duplicate element
9988 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9989 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9991 while ( anIter->more() )
9994 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9995 SMDS_MeshNode* aNewNode = aCurrNode;
9996 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9997 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9998 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10001 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10002 theNodeNodeMap[ aCurrNode ] = aNewNode;
10003 myLastCreatedNodes.Append( aNewNode );
10005 isDuplicate |= (aCurrNode != aNewNode);
10006 newNodes[ ind++ ] = aNewNode;
10008 if ( !isDuplicate )
10011 if ( theIsDoubleElem )
10012 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10014 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10021 //================================================================================
10023 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10024 \param theNodes - identifiers of nodes to be doubled
10025 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10026 nodes. If list of element identifiers is empty then nodes are doubled but
10027 they not assigned to elements
10028 \return TRUE if operation has been completed successfully, FALSE otherwise
10030 //================================================================================
10032 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10033 const std::list< int >& theListOfModifiedElems )
10035 myLastCreatedElems.Clear();
10036 myLastCreatedNodes.Clear();
10038 if ( theListOfNodes.size() == 0 )
10041 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10045 // iterate through nodes and duplicate them
10047 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10049 std::list< int >::const_iterator aNodeIter;
10050 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10052 int aCurr = *aNodeIter;
10053 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10059 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10062 anOldNodeToNewNode[ aNode ] = aNewNode;
10063 myLastCreatedNodes.Append( aNewNode );
10067 // Create map of new nodes for modified elements
10069 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10071 std::list< int >::const_iterator anElemIter;
10072 for ( anElemIter = theListOfModifiedElems.begin();
10073 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10075 int aCurr = *anElemIter;
10076 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10080 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10082 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10084 while ( anIter->more() )
10086 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10087 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10089 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10090 aNodeArr[ ind++ ] = aNewNode;
10093 aNodeArr[ ind++ ] = aCurrNode;
10095 anElemToNodes[ anElem ] = aNodeArr;
10098 // Change nodes of elements
10100 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10101 anElemToNodesIter = anElemToNodes.begin();
10102 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10104 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10105 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10107 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10115 //================================================================================
10117 \brief Check if element located inside shape
10118 \return TRUE if IN or ON shape, FALSE otherwise
10120 //================================================================================
10122 template<class Classifier>
10123 bool isInside(const SMDS_MeshElement* theElem,
10124 Classifier& theClassifier,
10125 const double theTol)
10127 gp_XYZ centerXYZ (0, 0, 0);
10128 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10129 while (aNodeItr->more())
10130 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10132 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10133 theClassifier.Perform(aPnt, theTol);
10134 TopAbs_State aState = theClassifier.State();
10135 return (aState == TopAbs_IN || aState == TopAbs_ON );
10138 //================================================================================
10140 * \brief Classifier of the 3D point on the TopoDS_Face
10141 * with interaface suitable for isInside()
10143 //================================================================================
10145 struct _FaceClassifier
10147 Extrema_ExtPS _extremum;
10148 BRepAdaptor_Surface _surface;
10149 TopAbs_State _state;
10151 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10153 _extremum.Initialize( _surface,
10154 _surface.FirstUParameter(), _surface.LastUParameter(),
10155 _surface.FirstVParameter(), _surface.LastVParameter(),
10156 _surface.Tolerance(), _surface.Tolerance() );
10158 void Perform(const gp_Pnt& aPnt, double theTol)
10160 _state = TopAbs_OUT;
10161 _extremum.Perform(aPnt);
10162 if ( _extremum.IsDone() )
10163 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10164 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10166 TopAbs_State State() const
10173 //================================================================================
10175 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10176 \param theElems - group of of elements (edges or faces) to be replicated
10177 \param theNodesNot - group of nodes not to replicate
10178 \param theShape - shape to detect affected elements (element which geometric center
10179 located on or inside shape).
10180 The replicated nodes should be associated to affected elements.
10181 \return TRUE if operation has been completed successfully, FALSE otherwise
10183 //================================================================================
10185 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10186 const TIDSortedElemSet& theNodesNot,
10187 const TopoDS_Shape& theShape )
10189 if ( theShape.IsNull() )
10192 const double aTol = Precision::Confusion();
10193 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10194 auto_ptr<_FaceClassifier> aFaceClassifier;
10195 if ( theShape.ShapeType() == TopAbs_SOLID )
10197 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10198 bsc3d->PerformInfinitePoint(aTol);
10200 else if (theShape.ShapeType() == TopAbs_FACE )
10202 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10205 // iterates on indicated elements and get elements by back references from their nodes
10206 TIDSortedElemSet anAffected;
10207 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10208 for ( ; elemItr != theElems.end(); ++elemItr )
10210 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10214 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10215 while ( nodeItr->more() )
10217 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10218 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10220 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10221 while ( backElemItr->more() )
10223 const SMDS_MeshElement* curElem = backElemItr->next();
10224 if ( curElem && theElems.find(curElem) == theElems.end() &&
10226 isInside( curElem, *bsc3d, aTol ) :
10227 isInside( curElem, *aFaceClassifier, aTol )))
10228 anAffected.insert( curElem );
10232 return DoubleNodes( theElems, theNodesNot, anAffected );
10235 //================================================================================
10237 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10238 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10239 * \return TRUE if operation has been completed successfully, FALSE otherwise
10241 //================================================================================
10243 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10245 // iterates on volume elements and detect all free faces on them
10246 SMESHDS_Mesh* aMesh = GetMeshDS();
10249 //bool res = false;
10250 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10251 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10254 const SMDS_MeshVolume* volume = vIt->next();
10255 SMDS_VolumeTool vTool( volume );
10256 vTool.SetExternalNormal();
10257 const bool isPoly = volume->IsPoly();
10258 const bool isQuad = volume->IsQuadratic();
10259 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10261 if (!vTool.IsFreeFace(iface))
10264 vector<const SMDS_MeshNode *> nodes;
10265 int nbFaceNodes = vTool.NbFaceNodes(iface);
10266 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10268 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10269 nodes.push_back(faceNodes[inode]);
10271 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10272 nodes.push_back(faceNodes[inode]);
10274 // add new face based on volume nodes
10275 if (aMesh->FindFace( nodes ) ) {
10277 continue; // face already exsist
10279 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10283 return ( nbFree==(nbExisted+nbCreated) );