1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
49 #include "utilities.h"
51 #include <BRepAdaptor_Surface.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <BRep_Tool.hxx>
55 #include <Extrema_GenExtPS.hxx>
56 #include <Extrema_POnCurv.hxx>
57 #include <Extrema_POnSurf.hxx>
58 #include <GC_MakeSegment.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <GeomAPI_ExtremaCurveCurve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Surface.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_Quadric.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
76 #include <TopoDS_Face.hxx>
82 #include <gp_Trsf.hxx>
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
97 using namespace SMESH::Controls;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
102 //=======================================================================
103 //function : SMESH_MeshEditor
105 //=======================================================================
107 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
108 :myMesh( theMesh ) // theMesh may be NULL
112 //=======================================================================
116 //=======================================================================
119 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
120 const SMDSAbs_ElementType type,
124 SMDS_MeshElement* e = 0;
125 int nbnode = node.size();
126 SMESHDS_Mesh* mesh = GetMeshDS();
128 case SMDSAbs_0DElement:
130 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
131 else e = mesh->Add0DElement (node[0] );
135 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
136 else e = mesh->AddEdge (node[0], node[1] );
137 else if ( nbnode == 3 )
138 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
139 else e = mesh->AddEdge (node[0], node[1], node[2] );
144 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145 else e = mesh->AddFace (node[0], node[1], node[2] );
146 else if (nbnode == 4)
147 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
149 else if (nbnode == 6)
150 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151 node[4], node[5], ID);
152 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
154 else if (nbnode == 8)
155 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156 node[4], node[5], node[6], node[7], ID);
157 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
158 node[4], node[5], node[6], node[7] );
160 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
161 else e = mesh->AddPolygonalFace (node );
167 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
169 else if (nbnode == 5)
170 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
174 else if (nbnode == 6)
175 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176 node[4], node[5], ID);
177 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
179 else if (nbnode == 8)
180 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181 node[4], node[5], node[6], node[7], ID);
182 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7] );
184 else if (nbnode == 10)
185 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186 node[4], node[5], node[6], node[7],
187 node[8], node[9], ID);
188 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7],
191 else if (nbnode == 13)
192 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193 node[4], node[5], node[6], node[7],
194 node[8], node[9], node[10],node[11],
196 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
197 node[4], node[5], node[6], node[7],
198 node[8], node[9], node[10],node[11],
200 else if (nbnode == 15)
201 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
202 node[4], node[5], node[6], node[7],
203 node[8], node[9], node[10],node[11],
204 node[12],node[13],node[14],ID);
205 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
206 node[4], node[5], node[6], node[7],
207 node[8], node[9], node[10],node[11],
208 node[12],node[13],node[14] );
209 else if (nbnode == 20)
210 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211 node[4], node[5], node[6], node[7],
212 node[8], node[9], node[10],node[11],
213 node[12],node[13],node[14],node[15],
214 node[16],node[17],node[18],node[19],ID);
215 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
216 node[4], node[5], node[6], node[7],
217 node[8], node[9], node[10],node[11],
218 node[12],node[13],node[14],node[15],
219 node[16],node[17],node[18],node[19] );
225 //=======================================================================
229 //=======================================================================
231 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
232 const SMDSAbs_ElementType type,
236 vector<const SMDS_MeshNode*> nodes;
237 nodes.reserve( nodeIDs.size() );
238 vector<int>::const_iterator id = nodeIDs.begin();
239 while ( id != nodeIDs.end() ) {
240 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
241 nodes.push_back( node );
245 return AddElement( nodes, type, isPoly, ID );
248 //=======================================================================
250 //purpose : Remove a node or an element.
251 // Modify a compute state of sub-meshes which become empty
252 //=======================================================================
254 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
257 myLastCreatedElems.Clear();
258 myLastCreatedNodes.Clear();
260 SMESHDS_Mesh* aMesh = GetMeshDS();
261 set< SMESH_subMesh *> smmap;
264 list<int>::const_iterator it = theIDs.begin();
265 for ( ; it != theIDs.end(); it++ ) {
266 const SMDS_MeshElement * elem;
268 elem = aMesh->FindNode( *it );
270 elem = aMesh->FindElement( *it );
274 // Notify VERTEX sub-meshes about modification
276 const SMDS_MeshNode* node = cast2Node( elem );
277 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
278 if ( int aShapeID = node->GetPosition()->GetShapeId() )
279 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
282 // Find sub-meshes to notify about modification
283 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
284 // while ( nodeIt->more() ) {
285 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
286 // const SMDS_PositionPtr& aPosition = node->GetPosition();
287 // if ( aPosition.get() ) {
288 // if ( int aShapeID = aPosition->GetShapeId() ) {
289 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290 // smmap.insert( sm );
297 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
299 aMesh->RemoveElement( elem );
303 // Notify sub-meshes about modification
304 if ( !smmap.empty() ) {
305 set< SMESH_subMesh *>::iterator smIt;
306 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
307 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
310 // // Check if the whole mesh becomes empty
311 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
312 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
317 //=======================================================================
318 //function : FindShape
319 //purpose : Return an index of the shape theElem is on
320 // or zero if a shape not found
321 //=======================================================================
323 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
325 myLastCreatedElems.Clear();
326 myLastCreatedNodes.Clear();
328 SMESHDS_Mesh * aMesh = GetMeshDS();
329 if ( aMesh->ShapeToMesh().IsNull() )
332 if ( theElem->GetType() == SMDSAbs_Node ) {
333 const SMDS_PositionPtr& aPosition =
334 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
335 if ( aPosition.get() )
336 return aPosition->GetShapeId();
341 TopoDS_Shape aShape; // the shape a node is on
342 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
343 while ( nodeIt->more() ) {
344 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
345 const SMDS_PositionPtr& aPosition = node->GetPosition();
346 if ( aPosition.get() ) {
347 int aShapeID = aPosition->GetShapeId();
348 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
350 if ( sm->Contains( theElem ))
352 if ( aShape.IsNull() )
353 aShape = aMesh->IndexToShape( aShapeID );
356 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
361 // None of nodes is on a proper shape,
362 // find the shape among ancestors of aShape on which a node is
363 if ( aShape.IsNull() ) {
364 //MESSAGE ("::FindShape() - NONE node is on shape")
367 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
368 for ( ; ancIt.More(); ancIt.Next() ) {
369 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
370 if ( sm && sm->Contains( theElem ))
371 return aMesh->ShapeToIndex( ancIt.Value() );
374 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
378 //=======================================================================
379 //function : IsMedium
381 //=======================================================================
383 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
384 const SMDSAbs_ElementType typeToCheck)
386 bool isMedium = false;
387 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
388 while (it->more() && !isMedium ) {
389 const SMDS_MeshElement* elem = it->next();
390 isMedium = elem->IsMediumNode(node);
395 //=======================================================================
396 //function : ShiftNodesQuadTria
398 // Shift nodes in the array corresponded to quadratic triangle
399 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
400 //=======================================================================
401 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
403 const SMDS_MeshNode* nd1 = aNodes[0];
404 aNodes[0] = aNodes[1];
405 aNodes[1] = aNodes[2];
407 const SMDS_MeshNode* nd2 = aNodes[3];
408 aNodes[3] = aNodes[4];
409 aNodes[4] = aNodes[5];
413 //=======================================================================
414 //function : GetNodesFromTwoTria
416 // Shift nodes in the array corresponded to quadratic triangle
417 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
418 //=======================================================================
419 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
420 const SMDS_MeshElement * theTria2,
421 const SMDS_MeshNode* N1[],
422 const SMDS_MeshNode* N2[])
424 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
427 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
430 if(it->more()) return false;
431 it = theTria2->nodesIterator();
434 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
437 if(it->more()) return false;
439 int sames[3] = {-1,-1,-1};
451 if(nbsames!=2) return false;
453 ShiftNodesQuadTria(N1);
455 ShiftNodesQuadTria(N1);
458 i = sames[0] + sames[1] + sames[2];
460 ShiftNodesQuadTria(N2);
462 // now we receive following N1 and N2 (using numeration as above image)
463 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
464 // i.e. first nodes from both arrays determ new diagonal
468 //=======================================================================
469 //function : InverseDiag
470 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
471 // but having other common link.
472 // Return False if args are improper
473 //=======================================================================
475 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
476 const SMDS_MeshElement * theTria2 )
478 myLastCreatedElems.Clear();
479 myLastCreatedNodes.Clear();
481 if (!theTria1 || !theTria2)
484 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
485 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
488 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
489 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
493 // put nodes in array and find out indices of the same ones
494 const SMDS_MeshNode* aNodes [6];
495 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
497 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
498 while ( it->more() ) {
499 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
501 if ( i > 2 ) // theTria2
502 // find same node of theTria1
503 for ( int j = 0; j < 3; j++ )
504 if ( aNodes[ i ] == aNodes[ j ]) {
513 return false; // theTria1 is not a triangle
514 it = theTria2->nodesIterator();
516 if ( i == 6 && it->more() )
517 return false; // theTria2 is not a triangle
520 // find indices of 1,2 and of A,B in theTria1
521 int iA = 0, iB = 0, i1 = 0, i2 = 0;
522 for ( i = 0; i < 6; i++ ) {
523 if ( sameInd [ i ] == 0 )
530 // nodes 1 and 2 should not be the same
531 if ( aNodes[ i1 ] == aNodes[ i2 ] )
535 aNodes[ iA ] = aNodes[ i2 ];
537 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
539 //MESSAGE( theTria1 << theTria2 );
541 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
542 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
544 //MESSAGE( theTria1 << theTria2 );
548 } // end if(F1 && F2)
550 // check case of quadratic faces
551 const SMDS_QuadraticFaceOfNodes* QF1 =
552 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
553 if(!QF1) return false;
554 const SMDS_QuadraticFaceOfNodes* QF2 =
555 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
556 if(!QF2) return false;
559 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
560 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
568 const SMDS_MeshNode* N1 [6];
569 const SMDS_MeshNode* N2 [6];
570 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
572 // now we receive following N1 and N2 (using numeration as above image)
573 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
574 // i.e. first nodes from both arrays determ new diagonal
576 const SMDS_MeshNode* N1new [6];
577 const SMDS_MeshNode* N2new [6];
590 // replaces nodes in faces
591 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
592 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
597 //=======================================================================
598 //function : findTriangles
599 //purpose : find triangles sharing theNode1-theNode2 link
600 //=======================================================================
602 static bool findTriangles(const SMDS_MeshNode * theNode1,
603 const SMDS_MeshNode * theNode2,
604 const SMDS_MeshElement*& theTria1,
605 const SMDS_MeshElement*& theTria2)
607 if ( !theNode1 || !theNode2 ) return false;
609 theTria1 = theTria2 = 0;
611 set< const SMDS_MeshElement* > emap;
612 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
614 const SMDS_MeshElement* elem = it->next();
615 if ( elem->NbNodes() == 3 )
618 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
620 const SMDS_MeshElement* elem = it->next();
621 if ( emap.find( elem ) != emap.end() )
623 // theTria1 must be element with minimum ID
624 if( theTria1->GetID() < elem->GetID() ) {
637 return ( theTria1 && theTria2 );
640 //=======================================================================
641 //function : InverseDiag
642 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
643 // with ones built on the same 4 nodes but having other common link.
644 // Return false if proper faces not found
645 //=======================================================================
647 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
648 const SMDS_MeshNode * theNode2)
650 myLastCreatedElems.Clear();
651 myLastCreatedNodes.Clear();
653 MESSAGE( "::InverseDiag()" );
655 const SMDS_MeshElement *tr1, *tr2;
656 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
659 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
660 //if (!F1) return false;
661 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
662 //if (!F2) return false;
665 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
666 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
670 // put nodes in array
671 // and find indices of 1,2 and of A in tr1 and of B in tr2
672 int i, iA1 = 0, i1 = 0;
673 const SMDS_MeshNode* aNodes1 [3];
674 SMDS_ElemIteratorPtr it;
675 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
676 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
677 if ( aNodes1[ i ] == theNode1 )
678 iA1 = i; // node A in tr1
679 else if ( aNodes1[ i ] != theNode2 )
683 const SMDS_MeshNode* aNodes2 [3];
684 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
685 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
686 if ( aNodes2[ i ] == theNode2 )
687 iB2 = i; // node B in tr2
688 else if ( aNodes2[ i ] != theNode1 )
692 // nodes 1 and 2 should not be the same
693 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
697 aNodes1[ iA1 ] = aNodes2[ i2 ];
699 aNodes2[ iB2 ] = aNodes1[ i1 ];
701 //MESSAGE( tr1 << tr2 );
703 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
704 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
706 //MESSAGE( tr1 << tr2 );
711 // check case of quadratic faces
712 const SMDS_QuadraticFaceOfNodes* QF1 =
713 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
714 if(!QF1) return false;
715 const SMDS_QuadraticFaceOfNodes* QF2 =
716 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
717 if(!QF2) return false;
718 return InverseDiag(tr1,tr2);
721 //=======================================================================
722 //function : getQuadrangleNodes
723 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
724 // fusion of triangles tr1 and tr2 having shared link on
725 // theNode1 and theNode2
726 //=======================================================================
728 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
729 const SMDS_MeshNode * theNode1,
730 const SMDS_MeshNode * theNode2,
731 const SMDS_MeshElement * tr1,
732 const SMDS_MeshElement * tr2 )
734 if( tr1->NbNodes() != tr2->NbNodes() )
736 // find the 4-th node to insert into tr1
737 const SMDS_MeshNode* n4 = 0;
738 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
740 while ( !n4 && i<3 ) {
741 const SMDS_MeshNode * n = cast2Node( it->next() );
743 bool isDiag = ( n == theNode1 || n == theNode2 );
747 // Make an array of nodes to be in a quadrangle
748 int iNode = 0, iFirstDiag = -1;
749 it = tr1->nodesIterator();
752 const SMDS_MeshNode * n = cast2Node( it->next() );
754 bool isDiag = ( n == theNode1 || n == theNode2 );
756 if ( iFirstDiag < 0 )
758 else if ( iNode - iFirstDiag == 1 )
759 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
761 else if ( n == n4 ) {
762 return false; // tr1 and tr2 should not have all the same nodes
764 theQuadNodes[ iNode++ ] = n;
766 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
767 theQuadNodes[ iNode ] = n4;
772 //=======================================================================
773 //function : DeleteDiag
774 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
775 // with a quadrangle built on the same 4 nodes.
776 // Return false if proper faces not found
777 //=======================================================================
779 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
780 const SMDS_MeshNode * theNode2)
782 myLastCreatedElems.Clear();
783 myLastCreatedNodes.Clear();
785 MESSAGE( "::DeleteDiag()" );
787 const SMDS_MeshElement *tr1, *tr2;
788 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
791 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
792 //if (!F1) return false;
793 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
794 //if (!F2) return false;
797 const SMDS_MeshNode* aNodes [ 4 ];
798 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
801 //MESSAGE( endl << tr1 << tr2 );
803 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
804 myLastCreatedElems.Append(tr1);
805 GetMeshDS()->RemoveElement( tr2 );
807 //MESSAGE( endl << tr1 );
812 // check case of quadratic faces
813 const SMDS_QuadraticFaceOfNodes* QF1 =
814 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
815 if(!QF1) return false;
816 const SMDS_QuadraticFaceOfNodes* QF2 =
817 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
818 if(!QF2) return false;
821 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
822 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
830 const SMDS_MeshNode* N1 [6];
831 const SMDS_MeshNode* N2 [6];
832 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
834 // now we receive following N1 and N2 (using numeration as above image)
835 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
836 // i.e. first nodes from both arrays determ new diagonal
838 const SMDS_MeshNode* aNodes[8];
848 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
849 myLastCreatedElems.Append(tr1);
850 GetMeshDS()->RemoveElement( tr2 );
852 // remove middle node (9)
853 GetMeshDS()->RemoveNode( N1[4] );
858 //=======================================================================
859 //function : Reorient
860 //purpose : Reverse theElement orientation
861 //=======================================================================
863 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
865 myLastCreatedElems.Clear();
866 myLastCreatedNodes.Clear();
870 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
871 if ( !it || !it->more() )
874 switch ( theElem->GetType() ) {
878 if(!theElem->IsQuadratic()) {
879 int i = theElem->NbNodes();
880 vector<const SMDS_MeshNode*> aNodes( i );
882 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
883 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
886 // quadratic elements
887 if(theElem->GetType()==SMDSAbs_Edge) {
888 vector<const SMDS_MeshNode*> aNodes(3);
889 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
890 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
891 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
892 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
895 int nbn = theElem->NbNodes();
896 vector<const SMDS_MeshNode*> aNodes(nbn);
897 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
899 for(; i<nbn/2; i++) {
900 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
902 for(i=0; i<nbn/2; i++) {
903 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
905 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
909 case SMDSAbs_Volume: {
910 if (theElem->IsPoly()) {
911 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
912 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
914 MESSAGE("Warning: bad volumic element");
918 int nbFaces = aPolyedre->NbFaces();
919 vector<const SMDS_MeshNode *> poly_nodes;
920 vector<int> quantities (nbFaces);
922 // reverse each face of the polyedre
923 for (int iface = 1; iface <= nbFaces; iface++) {
924 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
925 quantities[iface - 1] = nbFaceNodes;
927 for (inode = nbFaceNodes; inode >= 1; inode--) {
928 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
929 poly_nodes.push_back(curNode);
933 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
937 SMDS_VolumeTool vTool;
938 if ( !vTool.Set( theElem ))
941 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
950 //=======================================================================
951 //function : getBadRate
953 //=======================================================================
955 static double getBadRate (const SMDS_MeshElement* theElem,
956 SMESH::Controls::NumericalFunctorPtr& theCrit)
958 SMESH::Controls::TSequenceOfXYZ P;
959 if ( !theElem || !theCrit->GetPoints( theElem, P ))
961 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
962 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
965 //=======================================================================
966 //function : QuadToTri
967 //purpose : Cut quadrangles into triangles.
968 // theCrit is used to select a diagonal to cut
969 //=======================================================================
971 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
972 SMESH::Controls::NumericalFunctorPtr theCrit)
974 myLastCreatedElems.Clear();
975 myLastCreatedNodes.Clear();
977 MESSAGE( "::QuadToTri()" );
979 if ( !theCrit.get() )
982 SMESHDS_Mesh * aMesh = GetMeshDS();
984 Handle(Geom_Surface) surface;
985 SMESH_MesherHelper helper( *GetMesh() );
987 TIDSortedElemSet::iterator itElem;
988 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
989 const SMDS_MeshElement* elem = *itElem;
990 if ( !elem || elem->GetType() != SMDSAbs_Face )
992 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
995 // retrieve element nodes
996 const SMDS_MeshNode* aNodes [8];
997 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
999 while ( itN->more() )
1000 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1002 // compare two sets of possible triangles
1003 double aBadRate1, aBadRate2; // to what extent a set is bad
1004 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1005 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1006 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1008 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1009 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1010 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1012 int aShapeId = FindShape( elem );
1013 const SMDS_MeshElement* newElem = 0;
1015 if( !elem->IsQuadratic() ) {
1017 // split liner quadrangle
1019 if ( aBadRate1 <= aBadRate2 ) {
1020 // tr1 + tr2 is better
1021 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1022 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1025 // tr3 + tr4 is better
1026 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1027 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1032 // split quadratic quadrangle
1034 // get surface elem is on
1035 if ( aShapeId != helper.GetSubShapeID() ) {
1039 shape = aMesh->IndexToShape( aShapeId );
1040 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1041 TopoDS_Face face = TopoDS::Face( shape );
1042 surface = BRep_Tool::Surface( face );
1043 if ( !surface.IsNull() )
1044 helper.SetSubShape( shape );
1048 const SMDS_MeshNode* aNodes [8];
1049 const SMDS_MeshNode* inFaceNode = 0;
1050 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1052 while ( itN->more() ) {
1053 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1054 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1055 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1057 inFaceNode = aNodes[ i-1 ];
1060 // find middle point for (0,1,2,3)
1061 // and create a node in this point;
1063 if ( surface.IsNull() ) {
1065 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1069 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1072 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1074 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1076 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1077 myLastCreatedNodes.Append(newN);
1079 // create a new element
1080 const SMDS_MeshNode* N[6];
1081 if ( aBadRate1 <= aBadRate2 ) {
1088 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1089 aNodes[6], aNodes[7], newN );
1098 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1099 aNodes[7], aNodes[4], newN );
1101 aMesh->ChangeElementNodes( elem, N, 6 );
1105 // care of a new element
1107 myLastCreatedElems.Append(newElem);
1108 AddToSameGroups( newElem, elem, aMesh );
1110 // put a new triangle on the same shape
1112 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1117 //=======================================================================
1118 //function : BestSplit
1119 //purpose : Find better diagonal for cutting.
1120 //=======================================================================
1122 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1123 SMESH::Controls::NumericalFunctorPtr theCrit)
1125 myLastCreatedElems.Clear();
1126 myLastCreatedNodes.Clear();
1131 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1134 if( theQuad->NbNodes()==4 ||
1135 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1137 // retrieve element nodes
1138 const SMDS_MeshNode* aNodes [4];
1139 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1141 //while (itN->more())
1143 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1145 // compare two sets of possible triangles
1146 double aBadRate1, aBadRate2; // to what extent a set is bad
1147 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1148 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1149 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1151 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1152 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1153 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1155 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1156 return 1; // diagonal 1-3
1158 return 2; // diagonal 2-4
1165 // Methods of splitting volumes into tetra
1167 const int theHexTo5_1[5*4+1] =
1169 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1171 const int theHexTo5_2[5*4+1] =
1173 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1175 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1177 const int theHexTo6_1[6*4+1] =
1179 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
1181 const int theHexTo6_2[6*4+1] =
1183 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
1185 const int theHexTo6_3[6*4+1] =
1187 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
1189 const int theHexTo6_4[6*4+1] =
1191 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
1193 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1195 const int thePyraTo2_1[2*4+1] =
1197 0, 1, 2, 4, 0, 2, 3, 4, -1
1199 const int thePyraTo2_2[2*4+1] =
1201 1, 2, 3, 4, 1, 3, 0, 4, -1
1203 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1205 const int thePentaTo3_1[3*4+1] =
1207 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1209 const int thePentaTo3_2[3*4+1] =
1211 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1213 const int thePentaTo3_3[3*4+1] =
1215 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1217 const int thePentaTo3_4[3*4+1] =
1219 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1221 const int thePentaTo3_5[3*4+1] =
1223 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1225 const int thePentaTo3_6[3*4+1] =
1227 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1229 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1230 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1232 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1235 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1236 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1237 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1242 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1243 bool _baryNode; //!< additional node is to be created at cell barycenter
1244 bool _ownConn; //!< to delete _connectivity in destructor
1246 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1247 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1248 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1249 bool hasFacet( const TTriangleFacet& facet ) const
1251 const int* tetConn = _connectivity;
1252 for ( ; tetConn[0] >= 0; tetConn += 4 )
1253 if (( facet.contains( tetConn[0] ) +
1254 facet.contains( tetConn[1] ) +
1255 facet.contains( tetConn[2] ) +
1256 facet.contains( tetConn[3] )) == 3 )
1262 //=======================================================================
1264 * \brief return TSplitMethod for the given element
1266 //=======================================================================
1268 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1270 int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1272 // Find out how adjacent volumes are split
1274 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1275 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1276 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1278 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1279 maxTetConnSize += 4 * ( nbNodes - 2 );
1280 if ( nbNodes < 4 ) continue;
1282 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1283 const int* nInd = vol.GetFaceNodesIndices( iF );
1286 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1287 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1288 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1289 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1293 int iCom = 0; // common node of triangle faces to split into
1294 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1296 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1297 nInd[ iQ * ( (iCom+1)%nbNodes )],
1298 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1299 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1300 nInd[ iQ * ( (iCom+2)%nbNodes )],
1301 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1302 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1304 triaSplits.push_back( t012 );
1305 triaSplits.push_back( t023 );
1310 if ( !triaSplits.empty() )
1311 hasAdjacentSplits = true;
1314 // Among variants of split method select one compliant with adjacent volumes
1316 TSplitMethod method;
1317 if ( !vol.Element()->IsPoly() )
1319 int nbVariants = 2, nbTet = 0;
1320 const int** connVariants = 0;
1321 switch ( vol.Element()->GetEntityType() )
1323 case SMDSEntity_Hexa:
1324 case SMDSEntity_Quad_Hexa:
1325 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1326 connVariants = theHexTo5, nbTet = 5;
1328 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1330 case SMDSEntity_Pyramid:
1331 case SMDSEntity_Quad_Pyramid:
1332 connVariants = thePyraTo2; nbTet = 2;
1334 case SMDSEntity_Penta:
1335 case SMDSEntity_Quad_Penta:
1336 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1341 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1343 // check method compliancy with adjacent tetras,
1344 // all found splits must be among facets of tetras described by this method
1345 method = TSplitMethod( nbTet, connVariants[variant] );
1346 if ( hasAdjacentSplits && method._nbTetra > 0 )
1348 bool facetCreated = true;
1349 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1351 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1352 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1353 facetCreated = method.hasFacet( *facet );
1355 if ( !facetCreated )
1356 method = TSplitMethod(0); // incompatible method
1360 if ( method._nbTetra < 1 )
1362 // No standard method is applicable, use a generic solution:
1363 // each facet of a volume is split into triangles and
1364 // each of triangles and a volume barycenter form a tetrahedron.
1366 int* connectivity = new int[ maxTetConnSize + 1 ];
1367 method._connectivity = connectivity;
1368 method._ownConn = true;
1369 method._baryNode = true;
1372 int baryCenInd = vol.NbNodes();
1373 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1375 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1376 const int* nInd = vol.GetFaceNodesIndices( iF );
1377 // find common node of triangle facets of tetra to create
1378 int iCommon = 0; // index in linear numeration
1379 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1380 if ( !triaSplits.empty() )
1383 const TTriangleFacet* facet = &triaSplits.front();
1384 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1385 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1386 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1389 else if ( nbNodes > 3 )
1391 // find the best method of splitting into triangles by aspect ratio
1392 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1393 map< double, int > badness2iCommon;
1394 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1395 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1396 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1397 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1399 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1400 nodes[ iQ*((iLast-1)%nbNodes)],
1401 nodes[ iQ*((iLast )%nbNodes)]);
1402 double badness = getBadRate( &tria, aspectRatio );
1403 badness2iCommon.insert( make_pair( badness, iCommon ));
1405 // use iCommon with lowest badness
1406 iCommon = badness2iCommon.begin()->second;
1408 if ( iCommon >= nbNodes )
1409 iCommon = 0; // something wrong
1410 // fill connectivity of tetra
1411 int nbTet = nbNodes - 2;
1412 for ( int i = 0; i < nbTet; ++i )
1414 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1415 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1416 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1417 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1418 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1419 connectivity[ connSize++ ] = baryCenInd;
1423 connectivity[ connSize++ ] = -1;
1427 //================================================================================
1429 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1431 //================================================================================
1433 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1435 // find the tetrahedron including the three nodes of facet
1436 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1437 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1438 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1439 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1440 while ( volIt1->more() )
1442 const SMDS_MeshElement* v = volIt1->next();
1443 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1445 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1446 while ( volIt2->more() )
1447 if ( v != volIt2->next() )
1449 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1450 while ( volIt3->more() )
1451 if ( v == volIt3->next() )
1458 //=======================================================================
1459 //function : SplitVolumesIntoTetra
1460 //purpose : Split volumic elements into tetrahedra.
1461 //=======================================================================
1463 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1464 const int theMethodFlags)
1466 // std-like iterator on coordinates of nodes of mesh element
1467 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1468 NXyzIterator xyzEnd;
1470 SMDS_VolumeTool volTool;
1471 SMESH_MesherHelper helper( *GetMesh());
1473 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1474 SMESHDS_SubMesh* fSubMesh = subMesh;
1476 SMESH_SequenceOfElemPtr newNodes, newElems;
1478 TIDSortedElemSet::const_iterator elem = theElems.begin();
1479 for ( ; elem != theElems.end(); ++elem )
1481 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1482 if ( geomType <= SMDSEntity_Quad_Tetra )
1483 continue; // tetra or face or ...
1485 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1487 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1488 if ( splitMethod._nbTetra < 1 ) continue;
1490 // find submesh to add new tetras in
1491 if ( !subMesh || !subMesh->Contains( *elem ))
1493 int shapeID = FindShape( *elem );
1494 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1495 subMesh = GetMeshDS()->MeshElements( shapeID );
1498 if ( (*elem)->IsQuadratic() )
1501 // add quadratic links to the helper
1502 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1504 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1505 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1506 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1508 helper.SetIsQuadratic( true );
1513 helper.SetIsQuadratic( false );
1515 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1516 if ( splitMethod._baryNode )
1518 // make a node at barycenter
1520 gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1521 SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1522 nodes.push_back( gcNode );
1523 newNodes.Append( gcNode );
1527 helper.SetElementsOnShape( true );
1528 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1529 const int* tetConn = splitMethod._connectivity;
1530 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1531 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1532 nodes[ tetConn[1] ],
1533 nodes[ tetConn[2] ],
1534 nodes[ tetConn[3] ]));
1536 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1538 // Split faces on sides of the split volume
1540 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1541 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1543 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1544 if ( nbNodes < 4 ) continue;
1546 // find an existing face
1547 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1548 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1549 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1551 // among possible triangles create ones discribed by split method
1552 const int* nInd = volTool.GetFaceNodesIndices( iF );
1553 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1554 int iCom = 0; // common node of triangle faces to split into
1555 list< TTriangleFacet > facets;
1556 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1558 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1559 nInd[ iQ * ( (iCom+1)%nbNodes )],
1560 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1561 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1562 nInd[ iQ * ( (iCom+2)%nbNodes )],
1563 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1564 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1566 facets.push_back( t012 );
1567 facets.push_back( t023 );
1568 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1569 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1570 nInd[ iQ * ((iLast-1)%nbNodes )],
1571 nInd[ iQ * ((iLast )%nbNodes )]));
1575 // find submesh to add new faces in
1576 if ( !fSubMesh || !fSubMesh->Contains( face ))
1578 int shapeID = FindShape( face );
1579 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1582 helper.SetElementsOnShape( false );
1583 vector< const SMDS_MeshElement* > triangles;
1584 list< TTriangleFacet >::iterator facet = facets.begin();
1585 for ( ; facet != facets.end(); ++facet )
1587 if ( !volTool.IsFaceExternal( iF ))
1588 swap( facet->_n2, facet->_n3 );
1589 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1590 volNodes[ facet->_n2 ],
1591 volNodes[ facet->_n3 ]));
1592 if ( triangles.back() && fSubMesh )
1593 fSubMesh->AddElement( triangles.back());
1594 newElems.Append( triangles.back() );
1596 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1597 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1600 } // loop on volume faces to split them into triangles
1602 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1604 } // loop on volumes to split
1606 myLastCreatedNodes = newNodes;
1607 myLastCreatedElems = newElems;
1610 //=======================================================================
1611 //function : AddToSameGroups
1612 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1613 //=======================================================================
1615 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1616 const SMDS_MeshElement* elemInGroups,
1617 SMESHDS_Mesh * aMesh)
1619 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1620 if (!groups.empty()) {
1621 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1622 for ( ; grIt != groups.end(); grIt++ ) {
1623 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1624 if ( group && group->Contains( elemInGroups ))
1625 group->SMDSGroup().Add( elemToAdd );
1631 //=======================================================================
1632 //function : RemoveElemFromGroups
1633 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1634 //=======================================================================
1635 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1636 SMESHDS_Mesh * aMesh)
1638 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1639 if (!groups.empty())
1641 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1642 for (; GrIt != groups.end(); GrIt++)
1644 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1645 if (!grp || grp->IsEmpty()) continue;
1646 grp->SMDSGroup().Remove(removeelem);
1651 //================================================================================
1653 * \brief Replace elemToRm by elemToAdd in the all groups
1655 //================================================================================
1657 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1658 const SMDS_MeshElement* elemToAdd,
1659 SMESHDS_Mesh * aMesh)
1661 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1662 if (!groups.empty()) {
1663 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1664 for ( ; grIt != groups.end(); grIt++ ) {
1665 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1666 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1667 group->SMDSGroup().Add( elemToAdd );
1672 //================================================================================
1674 * \brief Replace elemToRm by elemToAdd in the all groups
1676 //================================================================================
1678 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1679 const vector<const SMDS_MeshElement*>& elemToAdd,
1680 SMESHDS_Mesh * aMesh)
1682 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1683 if (!groups.empty())
1685 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1686 for ( ; grIt != groups.end(); grIt++ ) {
1687 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1688 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1689 for ( int i = 0; i < elemToAdd.size(); ++i )
1690 group->SMDSGroup().Add( elemToAdd[ i ] );
1695 //=======================================================================
1696 //function : QuadToTri
1697 //purpose : Cut quadrangles into triangles.
1698 // theCrit is used to select a diagonal to cut
1699 //=======================================================================
1701 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1702 const bool the13Diag)
1704 myLastCreatedElems.Clear();
1705 myLastCreatedNodes.Clear();
1707 MESSAGE( "::QuadToTri()" );
1709 SMESHDS_Mesh * aMesh = GetMeshDS();
1711 Handle(Geom_Surface) surface;
1712 SMESH_MesherHelper helper( *GetMesh() );
1714 TIDSortedElemSet::iterator itElem;
1715 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1716 const SMDS_MeshElement* elem = *itElem;
1717 if ( !elem || elem->GetType() != SMDSAbs_Face )
1719 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1720 if(!isquad) continue;
1722 if(elem->NbNodes()==4) {
1723 // retrieve element nodes
1724 const SMDS_MeshNode* aNodes [4];
1725 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1727 while ( itN->more() )
1728 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1730 int aShapeId = FindShape( elem );
1731 const SMDS_MeshElement* newElem = 0;
1733 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1734 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1737 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1738 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1740 myLastCreatedElems.Append(newElem);
1741 // put a new triangle on the same shape and add to the same groups
1743 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1744 AddToSameGroups( newElem, elem, aMesh );
1747 // Quadratic quadrangle
1749 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1751 // get surface elem is on
1752 int aShapeId = FindShape( elem );
1753 if ( aShapeId != helper.GetSubShapeID() ) {
1757 shape = aMesh->IndexToShape( aShapeId );
1758 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1759 TopoDS_Face face = TopoDS::Face( shape );
1760 surface = BRep_Tool::Surface( face );
1761 if ( !surface.IsNull() )
1762 helper.SetSubShape( shape );
1766 const SMDS_MeshNode* aNodes [8];
1767 const SMDS_MeshNode* inFaceNode = 0;
1768 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1770 while ( itN->more() ) {
1771 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1772 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1773 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1775 inFaceNode = aNodes[ i-1 ];
1779 // find middle point for (0,1,2,3)
1780 // and create a node in this point;
1782 if ( surface.IsNull() ) {
1784 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1788 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1791 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1793 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1795 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1796 myLastCreatedNodes.Append(newN);
1798 // create a new element
1799 const SMDS_MeshElement* newElem = 0;
1800 const SMDS_MeshNode* N[6];
1808 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1809 aNodes[6], aNodes[7], newN );
1818 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1819 aNodes[7], aNodes[4], newN );
1821 myLastCreatedElems.Append(newElem);
1822 aMesh->ChangeElementNodes( elem, N, 6 );
1823 // put a new triangle on the same shape and add to the same groups
1825 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1826 AddToSameGroups( newElem, elem, aMesh );
1833 //=======================================================================
1834 //function : getAngle
1836 //=======================================================================
1838 double getAngle(const SMDS_MeshElement * tr1,
1839 const SMDS_MeshElement * tr2,
1840 const SMDS_MeshNode * n1,
1841 const SMDS_MeshNode * n2)
1843 double angle = 2*PI; // bad angle
1846 SMESH::Controls::TSequenceOfXYZ P1, P2;
1847 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1848 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1851 if(!tr1->IsQuadratic())
1852 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1854 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1855 if ( N1.SquareMagnitude() <= gp::Resolution() )
1857 if(!tr2->IsQuadratic())
1858 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1860 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1861 if ( N2.SquareMagnitude() <= gp::Resolution() )
1864 // find the first diagonal node n1 in the triangles:
1865 // take in account a diagonal link orientation
1866 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1867 for ( int t = 0; t < 2; t++ ) {
1868 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1869 int i = 0, iDiag = -1;
1870 while ( it->more()) {
1871 const SMDS_MeshElement *n = it->next();
1872 if ( n == n1 || n == n2 )
1876 if ( i - iDiag == 1 )
1877 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1885 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1888 angle = N1.Angle( N2 );
1893 // =================================================
1894 // class generating a unique ID for a pair of nodes
1895 // and able to return nodes by that ID
1896 // =================================================
1900 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1901 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1904 long GetLinkID (const SMDS_MeshNode * n1,
1905 const SMDS_MeshNode * n2) const
1907 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1910 bool GetNodes (const long theLinkID,
1911 const SMDS_MeshNode* & theNode1,
1912 const SMDS_MeshNode* & theNode2) const
1914 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1915 if ( !theNode1 ) return false;
1916 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1917 if ( !theNode2 ) return false;
1923 const SMESHDS_Mesh* myMesh;
1928 //=======================================================================
1929 //function : TriToQuad
1930 //purpose : Fuse neighbour triangles into quadrangles.
1931 // theCrit is used to select a neighbour to fuse with.
1932 // theMaxAngle is a max angle between element normals at which
1933 // fusion is still performed.
1934 //=======================================================================
1936 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1937 SMESH::Controls::NumericalFunctorPtr theCrit,
1938 const double theMaxAngle)
1940 myLastCreatedElems.Clear();
1941 myLastCreatedNodes.Clear();
1943 MESSAGE( "::TriToQuad()" );
1945 if ( !theCrit.get() )
1948 SMESHDS_Mesh * aMesh = GetMeshDS();
1950 // Prepare data for algo: build
1951 // 1. map of elements with their linkIDs
1952 // 2. map of linkIDs with their elements
1954 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1955 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1956 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1957 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1959 TIDSortedElemSet::iterator itElem;
1960 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1961 const SMDS_MeshElement* elem = *itElem;
1962 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1963 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1964 if(!IsTria) continue;
1966 // retrieve element nodes
1967 const SMDS_MeshNode* aNodes [4];
1968 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1971 aNodes[ i++ ] = cast2Node( itN->next() );
1972 aNodes[ 3 ] = aNodes[ 0 ];
1975 for ( i = 0; i < 3; i++ ) {
1976 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1977 // check if elements sharing a link can be fused
1978 itLE = mapLi_listEl.find( link );
1979 if ( itLE != mapLi_listEl.end() ) {
1980 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1982 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1983 //if ( FindShape( elem ) != FindShape( elem2 ))
1984 // continue; // do not fuse triangles laying on different shapes
1985 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1986 continue; // avoid making badly shaped quads
1987 (*itLE).second.push_back( elem );
1990 mapLi_listEl[ link ].push_back( elem );
1992 mapEl_setLi [ elem ].insert( link );
1995 // Clean the maps from the links shared by a sole element, ie
1996 // links to which only one element is bound in mapLi_listEl
1998 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1999 int nbElems = (*itLE).second.size();
2000 if ( nbElems < 2 ) {
2001 const SMDS_MeshElement* elem = (*itLE).second.front();
2002 SMESH_TLink link = (*itLE).first;
2003 mapEl_setLi[ elem ].erase( link );
2004 if ( mapEl_setLi[ elem ].empty() )
2005 mapEl_setLi.erase( elem );
2009 // Algo: fuse triangles into quadrangles
2011 while ( ! mapEl_setLi.empty() ) {
2012 // Look for the start element:
2013 // the element having the least nb of shared links
2014 const SMDS_MeshElement* startElem = 0;
2016 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2017 int nbLinks = (*itEL).second.size();
2018 if ( nbLinks < minNbLinks ) {
2019 startElem = (*itEL).first;
2020 minNbLinks = nbLinks;
2021 if ( minNbLinks == 1 )
2026 // search elements to fuse starting from startElem or links of elements
2027 // fused earlyer - startLinks
2028 list< SMESH_TLink > startLinks;
2029 while ( startElem || !startLinks.empty() ) {
2030 while ( !startElem && !startLinks.empty() ) {
2031 // Get an element to start, by a link
2032 SMESH_TLink linkId = startLinks.front();
2033 startLinks.pop_front();
2034 itLE = mapLi_listEl.find( linkId );
2035 if ( itLE != mapLi_listEl.end() ) {
2036 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2037 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2038 for ( ; itE != listElem.end() ; itE++ )
2039 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2041 mapLi_listEl.erase( itLE );
2046 // Get candidates to be fused
2047 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2048 const SMESH_TLink *link12, *link13;
2050 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2051 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2052 ASSERT( !setLi.empty() );
2053 set< SMESH_TLink >::iterator itLi;
2054 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2056 const SMESH_TLink & link = (*itLi);
2057 itLE = mapLi_listEl.find( link );
2058 if ( itLE == mapLi_listEl.end() )
2061 const SMDS_MeshElement* elem = (*itLE).second.front();
2063 elem = (*itLE).second.back();
2064 mapLi_listEl.erase( itLE );
2065 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2076 // add other links of elem to list of links to re-start from
2077 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2078 set< SMESH_TLink >::iterator it;
2079 for ( it = links.begin(); it != links.end(); it++ ) {
2080 const SMESH_TLink& link2 = (*it);
2081 if ( link2 != link )
2082 startLinks.push_back( link2 );
2086 // Get nodes of possible quadrangles
2087 const SMDS_MeshNode *n12 [4], *n13 [4];
2088 bool Ok12 = false, Ok13 = false;
2089 const SMDS_MeshNode *linkNode1, *linkNode2;
2091 linkNode1 = link12->first;
2092 linkNode2 = link12->second;
2093 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2097 linkNode1 = link13->first;
2098 linkNode2 = link13->second;
2099 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2103 // Choose a pair to fuse
2104 if ( Ok12 && Ok13 ) {
2105 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2106 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2107 double aBadRate12 = getBadRate( &quad12, theCrit );
2108 double aBadRate13 = getBadRate( &quad13, theCrit );
2109 if ( aBadRate13 < aBadRate12 )
2116 // and remove fused elems and removed links from the maps
2117 mapEl_setLi.erase( tr1 );
2119 mapEl_setLi.erase( tr2 );
2120 mapLi_listEl.erase( *link12 );
2121 if(tr1->NbNodes()==3) {
2122 if( tr1->GetID() < tr2->GetID() ) {
2123 aMesh->ChangeElementNodes( tr1, n12, 4 );
2124 myLastCreatedElems.Append(tr1);
2125 aMesh->RemoveElement( tr2 );
2128 aMesh->ChangeElementNodes( tr2, n12, 4 );
2129 myLastCreatedElems.Append(tr2);
2130 aMesh->RemoveElement( tr1);
2134 const SMDS_MeshNode* N1 [6];
2135 const SMDS_MeshNode* N2 [6];
2136 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2137 // now we receive following N1 and N2 (using numeration as above image)
2138 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2139 // i.e. first nodes from both arrays determ new diagonal
2140 const SMDS_MeshNode* aNodes[8];
2149 if( tr1->GetID() < tr2->GetID() ) {
2150 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2151 myLastCreatedElems.Append(tr1);
2152 GetMeshDS()->RemoveElement( tr2 );
2155 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2156 myLastCreatedElems.Append(tr2);
2157 GetMeshDS()->RemoveElement( tr1 );
2159 // remove middle node (9)
2160 GetMeshDS()->RemoveNode( N1[4] );
2164 mapEl_setLi.erase( tr3 );
2165 mapLi_listEl.erase( *link13 );
2166 if(tr1->NbNodes()==3) {
2167 if( tr1->GetID() < tr2->GetID() ) {
2168 aMesh->ChangeElementNodes( tr1, n13, 4 );
2169 myLastCreatedElems.Append(tr1);
2170 aMesh->RemoveElement( tr3 );
2173 aMesh->ChangeElementNodes( tr3, n13, 4 );
2174 myLastCreatedElems.Append(tr3);
2175 aMesh->RemoveElement( tr1 );
2179 const SMDS_MeshNode* N1 [6];
2180 const SMDS_MeshNode* N2 [6];
2181 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2182 // now we receive following N1 and N2 (using numeration as above image)
2183 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2184 // i.e. first nodes from both arrays determ new diagonal
2185 const SMDS_MeshNode* aNodes[8];
2194 if( tr1->GetID() < tr2->GetID() ) {
2195 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2196 myLastCreatedElems.Append(tr1);
2197 GetMeshDS()->RemoveElement( tr3 );
2200 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2201 myLastCreatedElems.Append(tr3);
2202 GetMeshDS()->RemoveElement( tr1 );
2204 // remove middle node (9)
2205 GetMeshDS()->RemoveNode( N1[4] );
2209 // Next element to fuse: the rejected one
2211 startElem = Ok12 ? tr3 : tr2;
2213 } // if ( startElem )
2214 } // while ( startElem || !startLinks.empty() )
2215 } // while ( ! mapEl_setLi.empty() )
2221 /*#define DUMPSO(txt) \
2222 // cout << txt << endl;
2223 //=============================================================================
2227 //=============================================================================
2228 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2232 int tmp = idNodes[ i1 ];
2233 idNodes[ i1 ] = idNodes[ i2 ];
2234 idNodes[ i2 ] = tmp;
2235 gp_Pnt Ptmp = P[ i1 ];
2238 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2241 //=======================================================================
2242 //function : SortQuadNodes
2243 //purpose : Set 4 nodes of a quadrangle face in a good order.
2244 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2246 //=======================================================================
2248 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2253 for ( i = 0; i < 4; i++ ) {
2254 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2256 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2259 gp_Vec V1(P[0], P[1]);
2260 gp_Vec V2(P[0], P[2]);
2261 gp_Vec V3(P[0], P[3]);
2263 gp_Vec Cross1 = V1 ^ V2;
2264 gp_Vec Cross2 = V2 ^ V3;
2267 if (Cross1.Dot(Cross2) < 0)
2272 if (Cross1.Dot(Cross2) < 0)
2276 swap ( i, i + 1, idNodes, P );
2278 // for ( int ii = 0; ii < 4; ii++ ) {
2279 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2280 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2286 //=======================================================================
2287 //function : SortHexaNodes
2288 //purpose : Set 8 nodes of a hexahedron in a good order.
2289 // Return success status
2290 //=======================================================================
2292 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2297 DUMPSO( "INPUT: ========================================");
2298 for ( i = 0; i < 8; i++ ) {
2299 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2300 if ( !n ) return false;
2301 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2302 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2304 DUMPSO( "========================================");
2307 set<int> faceNodes; // ids of bottom face nodes, to be found
2308 set<int> checkedId1; // ids of tried 2-nd nodes
2309 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2310 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2311 int iMin, iLoop1 = 0;
2313 // Loop to try the 2-nd nodes
2315 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2317 // Find not checked 2-nd node
2318 for ( i = 1; i < 8; i++ )
2319 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2320 int id1 = idNodes[i];
2321 swap ( 1, i, idNodes, P );
2322 checkedId1.insert ( id1 );
2326 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2327 // ie that all but meybe one (id3 which is on the same face) nodes
2328 // lay on the same side from the triangle plane.
2330 bool manyInPlane = false; // more than 4 nodes lay in plane
2332 while ( ++iLoop2 < 6 ) {
2334 // get 1-2-3 plane coeffs
2335 Standard_Real A, B, C, D;
2336 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2337 if ( N.SquareMagnitude() > gp::Resolution() )
2339 gp_Pln pln ( P[0], N );
2340 pln.Coefficients( A, B, C, D );
2342 // find the node (iMin) closest to pln
2343 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2345 for ( i = 3; i < 8; i++ ) {
2346 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2347 if ( fabs( dist[i] ) < minDist ) {
2348 minDist = fabs( dist[i] );
2351 if ( fabs( dist[i] ) <= tol )
2352 idInPln.insert( idNodes[i] );
2355 // there should not be more than 4 nodes in bottom plane
2356 if ( idInPln.size() > 1 )
2358 DUMPSO( "### idInPln.size() = " << idInPln.size());
2359 // idInPlane does not contain the first 3 nodes
2360 if ( manyInPlane || idInPln.size() == 5)
2361 return false; // all nodes in one plane
2364 // set the 1-st node to be not in plane
2365 for ( i = 3; i < 8; i++ ) {
2366 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2367 DUMPSO( "### Reset 0-th node");
2368 swap( 0, i, idNodes, P );
2373 // reset to re-check second nodes
2374 leastDist = DBL_MAX;
2378 break; // from iLoop2;
2381 // check that the other 4 nodes are on the same side
2382 bool sameSide = true;
2383 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2384 for ( i = 3; sameSide && i < 8; i++ ) {
2386 sameSide = ( isNeg == dist[i] <= 0.);
2389 // keep best solution
2390 if ( sameSide && minDist < leastDist ) {
2391 leastDist = minDist;
2393 faceNodes.insert( idNodes[ 1 ] );
2394 faceNodes.insert( idNodes[ 2 ] );
2395 faceNodes.insert( idNodes[ iMin ] );
2396 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2397 << " leastDist = " << leastDist);
2398 if ( leastDist <= DBL_MIN )
2403 // set next 3-d node to check
2404 int iNext = 2 + iLoop2;
2406 DUMPSO( "Try 2-nd");
2407 swap ( 2, iNext, idNodes, P );
2409 } // while ( iLoop2 < 6 )
2412 if ( faceNodes.empty() ) return false;
2414 // Put the faceNodes in proper places
2415 for ( i = 4; i < 8; i++ ) {
2416 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2417 // find a place to put
2419 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2421 DUMPSO( "Set faceNodes");
2422 swap ( iTo, i, idNodes, P );
2427 // Set nodes of the found bottom face in good order
2428 DUMPSO( " Found bottom face: ");
2429 i = SortQuadNodes( theMesh, idNodes );
2431 gp_Pnt Ptmp = P[ i ];
2436 // for ( int ii = 0; ii < 4; ii++ ) {
2437 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2438 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2441 // Gravity center of the top and bottom faces
2442 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2443 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2445 // Get direction from the bottom to the top face
2446 gp_Vec upDir ( aGCb, aGCt );
2447 Standard_Real upDirSize = upDir.Magnitude();
2448 if ( upDirSize <= gp::Resolution() ) return false;
2451 // Assure that the bottom face normal points up
2452 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2453 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2454 if ( Nb.Dot( upDir ) < 0 ) {
2455 DUMPSO( "Reverse bottom face");
2456 swap( 1, 3, idNodes, P );
2459 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2460 Standard_Real minDist = DBL_MAX;
2461 for ( i = 4; i < 8; i++ ) {
2462 // projection of P[i] to the plane defined by P[0] and upDir
2463 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2464 Standard_Real sqDist = P[0].SquareDistance( Pp );
2465 if ( sqDist < minDist ) {
2470 DUMPSO( "Set 4-th");
2471 swap ( 4, iMin, idNodes, P );
2473 // Set nodes of the top face in good order
2474 DUMPSO( "Sort top face");
2475 i = SortQuadNodes( theMesh, &idNodes[4] );
2478 gp_Pnt Ptmp = P[ i ];
2483 // Assure that direction of the top face normal is from the bottom face
2484 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2485 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2486 if ( Nt.Dot( upDir ) < 0 ) {
2487 DUMPSO( "Reverse top face");
2488 swap( 5, 7, idNodes, P );
2491 // DUMPSO( "OUTPUT: ========================================");
2492 // for ( i = 0; i < 8; i++ ) {
2493 // float *p = ugrid->GetPoint(idNodes[i]);
2494 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2500 //================================================================================
2502 * \brief Return nodes linked to the given one
2503 * \param theNode - the node
2504 * \param linkedNodes - the found nodes
2505 * \param type - the type of elements to check
2507 * Medium nodes are ignored
2509 //================================================================================
2511 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2512 TIDSortedElemSet & linkedNodes,
2513 SMDSAbs_ElementType type )
2515 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2516 while ( elemIt->more() )
2518 const SMDS_MeshElement* elem = elemIt->next();
2519 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2520 if ( elem->GetType() == SMDSAbs_Volume )
2522 SMDS_VolumeTool vol( elem );
2523 while ( nodeIt->more() ) {
2524 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2525 if ( theNode != n && vol.IsLinked( theNode, n ))
2526 linkedNodes.insert( n );
2531 for ( int i = 0; nodeIt->more(); ++i ) {
2532 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2533 if ( n == theNode ) {
2534 int iBefore = i - 1;
2536 if ( elem->IsQuadratic() ) {
2537 int nb = elem->NbNodes() / 2;
2538 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2539 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2541 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2542 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2549 //=======================================================================
2550 //function : laplacianSmooth
2551 //purpose : pulls theNode toward the center of surrounding nodes directly
2552 // connected to that node along an element edge
2553 //=======================================================================
2555 void laplacianSmooth(const SMDS_MeshNode* theNode,
2556 const Handle(Geom_Surface)& theSurface,
2557 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2559 // find surrounding nodes
2561 TIDSortedElemSet nodeSet;
2562 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2564 // compute new coodrs
2566 double coord[] = { 0., 0., 0. };
2567 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2568 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2569 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2570 if ( theSurface.IsNull() ) { // smooth in 3D
2571 coord[0] += node->X();
2572 coord[1] += node->Y();
2573 coord[2] += node->Z();
2575 else { // smooth in 2D
2576 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2577 gp_XY* uv = theUVMap[ node ];
2578 coord[0] += uv->X();
2579 coord[1] += uv->Y();
2582 int nbNodes = nodeSet.size();
2585 coord[0] /= nbNodes;
2586 coord[1] /= nbNodes;
2588 if ( !theSurface.IsNull() ) {
2589 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2590 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2591 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2597 coord[2] /= nbNodes;
2601 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2604 //=======================================================================
2605 //function : centroidalSmooth
2606 //purpose : pulls theNode toward the element-area-weighted centroid of the
2607 // surrounding elements
2608 //=======================================================================
2610 void centroidalSmooth(const SMDS_MeshNode* theNode,
2611 const Handle(Geom_Surface)& theSurface,
2612 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2614 gp_XYZ aNewXYZ(0.,0.,0.);
2615 SMESH::Controls::Area anAreaFunc;
2616 double totalArea = 0.;
2621 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2622 while ( elemIt->more() )
2624 const SMDS_MeshElement* elem = elemIt->next();
2627 gp_XYZ elemCenter(0.,0.,0.);
2628 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2629 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2630 int nn = elem->NbNodes();
2631 if(elem->IsQuadratic()) nn = nn/2;
2633 //while ( itN->more() ) {
2635 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2637 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2638 aNodePoints.push_back( aP );
2639 if ( !theSurface.IsNull() ) { // smooth in 2D
2640 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2641 gp_XY* uv = theUVMap[ aNode ];
2642 aP.SetCoord( uv->X(), uv->Y(), 0. );
2646 double elemArea = anAreaFunc.GetValue( aNodePoints );
2647 totalArea += elemArea;
2649 aNewXYZ += elemCenter * elemArea;
2651 aNewXYZ /= totalArea;
2652 if ( !theSurface.IsNull() ) {
2653 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2654 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2659 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2662 //=======================================================================
2663 //function : getClosestUV
2664 //purpose : return UV of closest projection
2665 //=======================================================================
2667 static bool getClosestUV (Extrema_GenExtPS& projector,
2668 const gp_Pnt& point,
2671 projector.Perform( point );
2672 if ( projector.IsDone() ) {
2673 double u, v, minVal = DBL_MAX;
2674 for ( int i = projector.NbExt(); i > 0; i-- )
2675 if ( projector.Value( i ) < minVal ) {
2676 minVal = projector.Value( i );
2677 projector.Point( i ).Parameter( u, v );
2679 result.SetCoord( u, v );
2685 //=======================================================================
2687 //purpose : Smooth theElements during theNbIterations or until a worst
2688 // element has aspect ratio <= theTgtAspectRatio.
2689 // Aspect Ratio varies in range [1.0, inf].
2690 // If theElements is empty, the whole mesh is smoothed.
2691 // theFixedNodes contains additionally fixed nodes. Nodes built
2692 // on edges and boundary nodes are always fixed.
2693 //=======================================================================
2695 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2696 set<const SMDS_MeshNode*> & theFixedNodes,
2697 const SmoothMethod theSmoothMethod,
2698 const int theNbIterations,
2699 double theTgtAspectRatio,
2702 myLastCreatedElems.Clear();
2703 myLastCreatedNodes.Clear();
2705 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2707 if ( theTgtAspectRatio < 1.0 )
2708 theTgtAspectRatio = 1.0;
2710 const double disttol = 1.e-16;
2712 SMESH::Controls::AspectRatio aQualityFunc;
2714 SMESHDS_Mesh* aMesh = GetMeshDS();
2716 if ( theElems.empty() ) {
2717 // add all faces to theElems
2718 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2719 while ( fIt->more() ) {
2720 const SMDS_MeshElement* face = fIt->next();
2721 theElems.insert( face );
2724 // get all face ids theElems are on
2725 set< int > faceIdSet;
2726 TIDSortedElemSet::iterator itElem;
2728 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2729 int fId = FindShape( *itElem );
2730 // check that corresponding submesh exists and a shape is face
2732 faceIdSet.find( fId ) == faceIdSet.end() &&
2733 aMesh->MeshElements( fId )) {
2734 TopoDS_Shape F = aMesh->IndexToShape( fId );
2735 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2736 faceIdSet.insert( fId );
2739 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2741 // ===============================================
2742 // smooth elements on each TopoDS_Face separately
2743 // ===============================================
2745 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2746 for ( ; fId != faceIdSet.rend(); ++fId ) {
2747 // get face surface and submesh
2748 Handle(Geom_Surface) surface;
2749 SMESHDS_SubMesh* faceSubMesh = 0;
2751 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2752 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2753 bool isUPeriodic = false, isVPeriodic = false;
2755 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2756 surface = BRep_Tool::Surface( face );
2757 faceSubMesh = aMesh->MeshElements( *fId );
2758 fToler2 = BRep_Tool::Tolerance( face );
2759 fToler2 *= fToler2 * 10.;
2760 isUPeriodic = surface->IsUPeriodic();
2762 vPeriod = surface->UPeriod();
2763 isVPeriodic = surface->IsVPeriodic();
2765 uPeriod = surface->VPeriod();
2766 surface->Bounds( u1, u2, v1, v2 );
2768 // ---------------------------------------------------------
2769 // for elements on a face, find movable and fixed nodes and
2770 // compute UV for them
2771 // ---------------------------------------------------------
2772 bool checkBoundaryNodes = false;
2773 bool isQuadratic = false;
2774 set<const SMDS_MeshNode*> setMovableNodes;
2775 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2776 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2777 list< const SMDS_MeshElement* > elemsOnFace;
2779 Extrema_GenExtPS projector;
2780 GeomAdaptor_Surface surfAdaptor;
2781 if ( !surface.IsNull() ) {
2782 surfAdaptor.Load( surface );
2783 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2785 int nbElemOnFace = 0;
2786 itElem = theElems.begin();
2787 // loop on not yet smoothed elements: look for elems on a face
2788 while ( itElem != theElems.end() ) {
2789 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2790 break; // all elements found
2792 const SMDS_MeshElement* elem = *itElem;
2793 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2794 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2798 elemsOnFace.push_back( elem );
2799 theElems.erase( itElem++ );
2803 isQuadratic = elem->IsQuadratic();
2805 // get movable nodes of elem
2806 const SMDS_MeshNode* node;
2807 SMDS_TypeOfPosition posType;
2808 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2809 int nn = 0, nbn = elem->NbNodes();
2810 if(elem->IsQuadratic())
2812 while ( nn++ < nbn ) {
2813 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2814 const SMDS_PositionPtr& pos = node->GetPosition();
2815 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2816 if (posType != SMDS_TOP_EDGE &&
2817 posType != SMDS_TOP_VERTEX &&
2818 theFixedNodes.find( node ) == theFixedNodes.end())
2820 // check if all faces around the node are on faceSubMesh
2821 // because a node on edge may be bound to face
2822 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2824 if ( faceSubMesh ) {
2825 while ( eIt->more() && all ) {
2826 const SMDS_MeshElement* e = eIt->next();
2827 all = faceSubMesh->Contains( e );
2831 setMovableNodes.insert( node );
2833 checkBoundaryNodes = true;
2835 if ( posType == SMDS_TOP_3DSPACE )
2836 checkBoundaryNodes = true;
2839 if ( surface.IsNull() )
2842 // get nodes to check UV
2843 list< const SMDS_MeshNode* > uvCheckNodes;
2844 itN = elem->nodesIterator();
2845 nn = 0; nbn = elem->NbNodes();
2846 if(elem->IsQuadratic())
2848 while ( nn++ < nbn ) {
2849 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2850 if ( uvMap.find( node ) == uvMap.end() )
2851 uvCheckNodes.push_back( node );
2852 // add nodes of elems sharing node
2853 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2854 // while ( eIt->more() ) {
2855 // const SMDS_MeshElement* e = eIt->next();
2856 // if ( e != elem ) {
2857 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2858 // while ( nIt->more() ) {
2859 // const SMDS_MeshNode* n =
2860 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2861 // if ( uvMap.find( n ) == uvMap.end() )
2862 // uvCheckNodes.push_back( n );
2868 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2869 for ( ; n != uvCheckNodes.end(); ++n ) {
2872 const SMDS_PositionPtr& pos = node->GetPosition();
2873 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2875 switch ( posType ) {
2876 case SMDS_TOP_FACE: {
2877 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2878 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2881 case SMDS_TOP_EDGE: {
2882 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2883 Handle(Geom2d_Curve) pcurve;
2884 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2885 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2886 if ( !pcurve.IsNull() ) {
2887 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2888 uv = pcurve->Value( u ).XY();
2892 case SMDS_TOP_VERTEX: {
2893 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2894 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2895 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2900 // check existing UV
2901 bool project = true;
2902 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2903 double dist1 = DBL_MAX, dist2 = 0;
2904 if ( posType != SMDS_TOP_3DSPACE ) {
2905 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2906 project = dist1 > fToler2;
2908 if ( project ) { // compute new UV
2910 if ( !getClosestUV( projector, pNode, newUV )) {
2911 MESSAGE("Node Projection Failed " << node);
2915 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2917 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2919 if ( posType != SMDS_TOP_3DSPACE )
2920 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2921 if ( dist2 < dist1 )
2925 // store UV in the map
2926 listUV.push_back( uv );
2927 uvMap.insert( make_pair( node, &listUV.back() ));
2929 } // loop on not yet smoothed elements
2931 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2932 checkBoundaryNodes = true;
2934 // fix nodes on mesh boundary
2936 if ( checkBoundaryNodes ) {
2937 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2938 map< NLink, int >::iterator link_nb;
2939 // put all elements links to linkNbMap
2940 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2941 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2942 const SMDS_MeshElement* elem = (*elemIt);
2943 int nbn = elem->NbNodes();
2944 if(elem->IsQuadratic())
2946 // loop on elem links: insert them in linkNbMap
2947 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2948 for ( int iN = 0; iN < nbn; ++iN ) {
2949 curNode = elem->GetNode( iN );
2951 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2952 else link = make_pair( prevNode , curNode );
2954 link_nb = linkNbMap.find( link );
2955 if ( link_nb == linkNbMap.end() )
2956 linkNbMap.insert( make_pair ( link, 1 ));
2961 // remove nodes that are in links encountered only once from setMovableNodes
2962 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2963 if ( link_nb->second == 1 ) {
2964 setMovableNodes.erase( link_nb->first.first );
2965 setMovableNodes.erase( link_nb->first.second );
2970 // -----------------------------------------------------
2971 // for nodes on seam edge, compute one more UV ( uvMap2 );
2972 // find movable nodes linked to nodes on seam and which
2973 // are to be smoothed using the second UV ( uvMap2 )
2974 // -----------------------------------------------------
2976 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2977 if ( !surface.IsNull() ) {
2978 TopExp_Explorer eExp( face, TopAbs_EDGE );
2979 for ( ; eExp.More(); eExp.Next() ) {
2980 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2981 if ( !BRep_Tool::IsClosed( edge, face ))
2983 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2984 if ( !sm ) continue;
2985 // find out which parameter varies for a node on seam
2988 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2989 if ( pcurve.IsNull() ) continue;
2990 uv1 = pcurve->Value( f );
2992 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2993 if ( pcurve.IsNull() ) continue;
2994 uv2 = pcurve->Value( f );
2995 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2997 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2998 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3000 // get nodes on seam and its vertices
3001 list< const SMDS_MeshNode* > seamNodes;
3002 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3003 while ( nSeamIt->more() ) {
3004 const SMDS_MeshNode* node = nSeamIt->next();
3005 if ( !isQuadratic || !IsMedium( node ))
3006 seamNodes.push_back( node );
3008 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3009 for ( ; vExp.More(); vExp.Next() ) {
3010 sm = aMesh->MeshElements( vExp.Current() );
3012 nSeamIt = sm->GetNodes();
3013 while ( nSeamIt->more() )
3014 seamNodes.push_back( nSeamIt->next() );
3017 // loop on nodes on seam
3018 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3019 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3020 const SMDS_MeshNode* nSeam = *noSeIt;
3021 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3022 if ( n_uv == uvMap.end() )
3025 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3026 // set the second UV
3027 listUV.push_back( *n_uv->second );
3028 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3029 if ( uvMap2.empty() )
3030 uvMap2 = uvMap; // copy the uvMap contents
3031 uvMap2[ nSeam ] = &listUV.back();
3033 // collect movable nodes linked to ones on seam in nodesNearSeam
3034 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3035 while ( eIt->more() ) {
3036 const SMDS_MeshElement* e = eIt->next();
3037 int nbUseMap1 = 0, nbUseMap2 = 0;
3038 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3039 int nn = 0, nbn = e->NbNodes();
3040 if(e->IsQuadratic()) nbn = nbn/2;
3041 while ( nn++ < nbn )
3043 const SMDS_MeshNode* n =
3044 static_cast<const SMDS_MeshNode*>( nIt->next() );
3046 setMovableNodes.find( n ) == setMovableNodes.end() )
3048 // add only nodes being closer to uv2 than to uv1
3049 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3050 0.5 * ( n->Y() + nSeam->Y() ),
3051 0.5 * ( n->Z() + nSeam->Z() ));
3053 getClosestUV( projector, pMid, uv );
3054 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3055 nodesNearSeam.insert( n );
3061 // for centroidalSmooth all element nodes must
3062 // be on one side of a seam
3063 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3064 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3066 while ( nn++ < nbn ) {
3067 const SMDS_MeshNode* n =
3068 static_cast<const SMDS_MeshNode*>( nIt->next() );
3069 setMovableNodes.erase( n );
3073 } // loop on nodes on seam
3074 } // loop on edge of a face
3075 } // if ( !face.IsNull() )
3077 if ( setMovableNodes.empty() ) {
3078 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3079 continue; // goto next face
3087 double maxRatio = -1., maxDisplacement = -1.;
3088 set<const SMDS_MeshNode*>::iterator nodeToMove;
3089 for ( it = 0; it < theNbIterations; it++ ) {
3090 maxDisplacement = 0.;
3091 nodeToMove = setMovableNodes.begin();
3092 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3093 const SMDS_MeshNode* node = (*nodeToMove);
3094 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3097 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3098 if ( theSmoothMethod == LAPLACIAN )
3099 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3101 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3103 // node displacement
3104 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3105 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3106 if ( aDispl > maxDisplacement )
3107 maxDisplacement = aDispl;
3109 // no node movement => exit
3110 //if ( maxDisplacement < 1.e-16 ) {
3111 if ( maxDisplacement < disttol ) {
3112 MESSAGE("-- no node movement --");
3116 // check elements quality
3118 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3119 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3120 const SMDS_MeshElement* elem = (*elemIt);
3121 if ( !elem || elem->GetType() != SMDSAbs_Face )
3123 SMESH::Controls::TSequenceOfXYZ aPoints;
3124 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3125 double aValue = aQualityFunc.GetValue( aPoints );
3126 if ( aValue > maxRatio )
3130 if ( maxRatio <= theTgtAspectRatio ) {
3131 MESSAGE("-- quality achived --");
3134 if (it+1 == theNbIterations) {
3135 MESSAGE("-- Iteration limit exceeded --");
3137 } // smoothing iterations
3139 MESSAGE(" Face id: " << *fId <<
3140 " Nb iterstions: " << it <<
3141 " Displacement: " << maxDisplacement <<
3142 " Aspect Ratio " << maxRatio);
3144 // ---------------------------------------
3145 // new nodes positions are computed,
3146 // record movement in DS and set new UV
3147 // ---------------------------------------
3148 nodeToMove = setMovableNodes.begin();
3149 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3150 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3151 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3152 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3153 if ( node_uv != uvMap.end() ) {
3154 gp_XY* uv = node_uv->second;
3156 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3160 // move medium nodes of quadratic elements
3163 SMESH_MesherHelper helper( *GetMesh() );
3164 if ( !face.IsNull() )
3165 helper.SetSubShape( face );
3166 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3167 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3168 const SMDS_QuadraticFaceOfNodes* QF =
3169 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3171 vector<const SMDS_MeshNode*> Ns;
3172 Ns.reserve(QF->NbNodes()+1);
3173 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3174 while ( anIter->more() )
3175 Ns.push_back( anIter->next() );
3176 Ns.push_back( Ns[0] );
3178 for(int i=0; i<QF->NbNodes(); i=i+2) {
3179 if ( !surface.IsNull() ) {
3180 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3181 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3182 gp_XY uv = ( uv1 + uv2 ) / 2.;
3183 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3184 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3187 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3188 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3189 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3191 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3192 fabs( Ns[i+1]->Y() - y ) > disttol ||
3193 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3194 // we have to move i+1 node
3195 aMesh->MoveNode( Ns[i+1], x, y, z );
3202 } // loop on face ids
3206 //=======================================================================
3207 //function : isReverse
3208 //purpose : Return true if normal of prevNodes is not co-directied with
3209 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3210 // iNotSame is where prevNodes and nextNodes are different
3211 //=======================================================================
3213 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3214 vector<const SMDS_MeshNode*> nextNodes,
3218 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3219 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3221 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3222 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3223 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3224 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3226 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3227 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3228 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3229 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3231 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3233 return (vA ^ vB) * vN < 0.0;
3236 //=======================================================================
3238 * \brief Create elements by sweeping an element
3239 * \param elem - element to sweep
3240 * \param newNodesItVec - nodes generated from each node of the element
3241 * \param newElems - generated elements
3242 * \param nbSteps - number of sweeping steps
3243 * \param srcElements - to append elem for each generated element
3245 //=======================================================================
3247 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3248 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3249 list<const SMDS_MeshElement*>& newElems,
3251 SMESH_SequenceOfElemPtr& srcElements)
3253 SMESHDS_Mesh* aMesh = GetMeshDS();
3255 // Loop on elem nodes:
3256 // find new nodes and detect same nodes indices
3257 int nbNodes = elem->NbNodes();
3258 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3259 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3260 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3261 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3263 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3264 vector<int> sames(nbNodes);
3265 vector<bool> issimple(nbNodes);
3267 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3268 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3269 const SMDS_MeshNode* node = nnIt->first;
3270 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3271 if ( listNewNodes.empty() ) {
3275 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3277 itNN[ iNode ] = listNewNodes.begin();
3278 prevNod[ iNode ] = node;
3279 nextNod[ iNode ] = listNewNodes.front();
3280 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3281 if ( prevNod[ iNode ] != nextNod [ iNode ])
3282 iNotSameNode = iNode;
3286 sames[nbSame++] = iNode;
3291 //cout<<" nbSame = "<<nbSame<<endl;
3292 if ( nbSame == nbNodes || nbSame > 2) {
3293 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3294 //INFOS( " Too many same nodes of element " << elem->GetID() );
3298 // if( elem->IsQuadratic() && nbSame>0 ) {
3299 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3303 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3304 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3306 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3307 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3308 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3312 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3313 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3314 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3315 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3317 // check element orientation
3319 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3320 //MESSAGE("Reversed elem " << elem );
3324 std::swap( iBeforeSame, iAfterSame );
3327 // make new elements
3328 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3330 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3331 if(issimple[iNode]) {
3332 nextNod[ iNode ] = *itNN[ iNode ];
3336 if( elem->GetType()==SMDSAbs_Node ) {
3337 // we have to use two nodes
3338 midlNod[ iNode ] = *itNN[ iNode ];
3340 nextNod[ iNode ] = *itNN[ iNode ];
3343 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3344 // we have to use each second node
3346 nextNod[ iNode ] = *itNN[ iNode ];
3350 // we have to use two nodes
3351 midlNod[ iNode ] = *itNN[ iNode ];
3353 nextNod[ iNode ] = *itNN[ iNode ];
3358 SMDS_MeshElement* aNewElem = 0;
3359 if(!elem->IsPoly()) {
3360 switch ( nbNodes ) {
3364 if ( nbSame == 0 ) {
3366 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3368 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3374 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3375 nextNod[ 1 ], nextNod[ 0 ] );
3377 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3378 nextNod[ iNotSameNode ] );
3382 case 3: { // TRIANGLE or quadratic edge
3383 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3385 if ( nbSame == 0 ) // --- pentahedron
3386 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3387 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3389 else if ( nbSame == 1 ) // --- pyramid
3390 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3391 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3392 nextNod[ iSameNode ]);
3394 else // 2 same nodes: --- tetrahedron
3395 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3396 nextNod[ iNotSameNode ]);
3398 else { // quadratic edge
3399 if(nbSame==0) { // quadratic quadrangle
3400 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3401 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3403 else if(nbSame==1) { // quadratic triangle
3405 return; // medium node on axis
3407 else if(sames[0]==0) {
3408 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3409 nextNod[2], midlNod[1], prevNod[2]);
3411 else { // sames[0]==1
3412 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3413 midlNod[0], nextNod[2], prevNod[2]);
3422 case 4: { // QUADRANGLE
3424 if ( nbSame == 0 ) // --- hexahedron
3425 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3426 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3428 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3429 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3430 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3431 nextNod[ iSameNode ]);
3432 newElems.push_back( aNewElem );
3433 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3434 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3435 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3437 else if ( nbSame == 2 ) { // pentahedron
3438 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3439 // iBeforeSame is same too
3440 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3441 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3442 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3444 // iAfterSame is same too
3445 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3446 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3447 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3451 case 6: { // quadratic triangle
3452 // create pentahedron with 15 nodes
3454 if(i0>0) { // reversed case
3455 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3456 nextNod[0], nextNod[2], nextNod[1],
3457 prevNod[5], prevNod[4], prevNod[3],
3458 nextNod[5], nextNod[4], nextNod[3],
3459 midlNod[0], midlNod[2], midlNod[1]);
3461 else { // not reversed case
3462 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3463 nextNod[0], nextNod[1], nextNod[2],
3464 prevNod[3], prevNod[4], prevNod[5],
3465 nextNod[3], nextNod[4], nextNod[5],
3466 midlNod[0], midlNod[1], midlNod[2]);
3469 else if(nbSame==1) {
3470 // 2d order pyramid of 13 nodes
3471 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3472 // int n12,int n23,int n34,int n41,
3473 // int n15,int n25,int n35,int n45, int ID);
3475 int n1,n4,n41,n15,n45;
3476 if(i0>0) { // reversed case
3477 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3478 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3484 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3485 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3490 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3491 nextNod[n4], prevNod[n4], prevNod[n5],
3492 midlNod[n1], nextNod[n41],
3493 midlNod[n4], prevNod[n41],
3494 prevNod[n15], nextNod[n15],
3495 nextNod[n45], prevNod[n45]);
3497 else if(nbSame==2) {
3498 // 2d order tetrahedron of 10 nodes
3499 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3500 // int n12,int n23,int n31,
3501 // int n14,int n24,int n34, int ID);
3502 int n1 = iNotSameNode;
3503 int n2,n3,n12,n23,n31;
3504 if(i0>0) { // reversed case
3505 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3506 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3512 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3513 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3518 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3519 prevNod[n12], prevNod[n23], prevNod[n31],
3520 midlNod[n1], nextNod[n12], nextNod[n31]);
3524 case 8: { // quadratic quadrangle
3526 // create hexahedron with 20 nodes
3527 if(i0>0) { // reversed case
3528 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3529 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3530 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3531 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3532 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3534 else { // not reversed case
3535 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3536 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3537 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3538 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3539 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3542 else if(nbSame==1) {
3543 // --- pyramid + pentahedron - can not be created since it is needed
3544 // additional middle node ot the center of face
3545 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3548 else if(nbSame==2) {
3549 // 2d order Pentahedron with 15 nodes
3550 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3551 // int n12,int n23,int n31,int n45,int n56,int n64,
3552 // int n14,int n25,int n36, int ID);
3554 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3555 // iBeforeSame is same too
3562 // iAfterSame is same too
3568 int n12,n45,n14,n25;
3569 if(i0>0) { //reversed case
3581 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3582 prevNod[n4], prevNod[n5], nextNod[n5],
3583 prevNod[n12], midlNod[n2], nextNod[n12],
3584 prevNod[n45], midlNod[n5], nextNod[n45],
3585 prevNod[n14], prevNod[n25], nextNod[n25]);
3590 // realized for extrusion only
3591 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3592 //vector<int> quantities (nbNodes + 2);
3594 //quantities[0] = nbNodes; // bottom of prism
3595 //for (int inode = 0; inode < nbNodes; inode++) {
3596 // polyedre_nodes[inode] = prevNod[inode];
3599 //quantities[1] = nbNodes; // top of prism
3600 //for (int inode = 0; inode < nbNodes; inode++) {
3601 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3604 //for (int iface = 0; iface < nbNodes; iface++) {
3605 // quantities[iface + 2] = 4;
3606 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3607 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3608 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3609 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3610 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3612 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3619 // realized for extrusion only
3620 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3621 vector<int> quantities (nbNodes + 2);
3623 quantities[0] = nbNodes; // bottom of prism
3624 for (int inode = 0; inode < nbNodes; inode++) {
3625 polyedre_nodes[inode] = prevNod[inode];
3628 quantities[1] = nbNodes; // top of prism
3629 for (int inode = 0; inode < nbNodes; inode++) {
3630 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3633 for (int iface = 0; iface < nbNodes; iface++) {
3634 quantities[iface + 2] = 4;
3635 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3636 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3637 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3638 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3639 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3641 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3645 newElems.push_back( aNewElem );
3646 myLastCreatedElems.Append(aNewElem);
3647 srcElements.Append( elem );
3650 // set new prev nodes
3651 for ( iNode = 0; iNode < nbNodes; iNode++ )
3652 prevNod[ iNode ] = nextNod[ iNode ];
3657 //=======================================================================
3659 * \brief Create 1D and 2D elements around swept elements
3660 * \param mapNewNodes - source nodes and ones generated from them
3661 * \param newElemsMap - source elements and ones generated from them
3662 * \param elemNewNodesMap - nodes generated from each node of each element
3663 * \param elemSet - all swept elements
3664 * \param nbSteps - number of sweeping steps
3665 * \param srcElements - to append elem for each generated element
3667 //=======================================================================
3669 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3670 TElemOfElemListMap & newElemsMap,
3671 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3672 TIDSortedElemSet& elemSet,
3674 SMESH_SequenceOfElemPtr& srcElements)
3676 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3677 SMESHDS_Mesh* aMesh = GetMeshDS();
3679 // Find nodes belonging to only one initial element - sweep them to get edges.
3681 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3682 for ( ; nList != mapNewNodes.end(); nList++ ) {
3683 const SMDS_MeshNode* node =
3684 static_cast<const SMDS_MeshNode*>( nList->first );
3685 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3686 int nbInitElems = 0;
3687 const SMDS_MeshElement* el = 0;
3688 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3689 while ( eIt->more() && nbInitElems < 2 ) {
3691 SMDSAbs_ElementType type = el->GetType();
3692 if ( type == SMDSAbs_Volume || type < highType ) continue;
3693 if ( type > highType ) {
3697 if ( elemSet.find(el) != elemSet.end() )
3700 if ( nbInitElems < 2 ) {
3701 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3702 if(!NotCreateEdge) {
3703 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3704 list<const SMDS_MeshElement*> newEdges;
3705 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3710 // Make a ceiling for each element ie an equal element of last new nodes.
3711 // Find free links of faces - make edges and sweep them into faces.
3713 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3714 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3715 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3716 const SMDS_MeshElement* elem = itElem->first;
3717 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3719 if ( elem->GetType() == SMDSAbs_Edge ) {
3720 // create a ceiling edge
3721 if (!elem->IsQuadratic()) {
3722 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3723 vecNewNodes[ 1 ]->second.back())) {
3724 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3725 vecNewNodes[ 1 ]->second.back()));
3726 srcElements.Append( myLastCreatedElems.Last() );
3730 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3731 vecNewNodes[ 1 ]->second.back(),
3732 vecNewNodes[ 2 ]->second.back())) {
3733 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3734 vecNewNodes[ 1 ]->second.back(),
3735 vecNewNodes[ 2 ]->second.back()));
3736 srcElements.Append( myLastCreatedElems.Last() );
3740 if ( elem->GetType() != SMDSAbs_Face )
3743 if(itElem->second.size()==0) continue;
3745 bool hasFreeLinks = false;
3747 TIDSortedElemSet avoidSet;
3748 avoidSet.insert( elem );
3750 set<const SMDS_MeshNode*> aFaceLastNodes;
3751 int iNode, nbNodes = vecNewNodes.size();
3752 if(!elem->IsQuadratic()) {
3753 // loop on the face nodes
3754 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3755 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3756 // look for free links of the face
3757 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3758 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3759 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3760 // check if a link is free
3761 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3762 hasFreeLinks = true;
3763 // make an edge and a ceiling for a new edge
3764 if ( !aMesh->FindEdge( n1, n2 )) {
3765 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3766 srcElements.Append( myLastCreatedElems.Last() );
3768 n1 = vecNewNodes[ iNode ]->second.back();
3769 n2 = vecNewNodes[ iNext ]->second.back();
3770 if ( !aMesh->FindEdge( n1, n2 )) {
3771 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3772 srcElements.Append( myLastCreatedElems.Last() );
3777 else { // elem is quadratic face
3778 int nbn = nbNodes/2;
3779 for ( iNode = 0; iNode < nbn; iNode++ ) {
3780 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3781 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3782 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3783 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3784 // check if a link is free
3785 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3786 hasFreeLinks = true;
3787 // make an edge and a ceiling for a new edge
3789 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3790 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3791 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3792 srcElements.Append( myLastCreatedElems.Last() );
3794 n1 = vecNewNodes[ iNode ]->second.back();
3795 n2 = vecNewNodes[ iNext ]->second.back();
3796 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3797 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3798 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3799 srcElements.Append( myLastCreatedElems.Last() );
3803 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3804 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3808 // sweep free links into faces
3810 if ( hasFreeLinks ) {
3811 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3812 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3814 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3815 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3816 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3817 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3819 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3820 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3822 while ( iVol++ < volNb ) v++;
3823 // find indices of free faces of a volume and their source edges
3824 list< int > freeInd;
3825 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3826 SMDS_VolumeTool vTool( *v );
3827 int iF, nbF = vTool.NbFaces();
3828 for ( iF = 0; iF < nbF; iF ++ ) {
3829 if (vTool.IsFreeFace( iF ) &&
3830 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3831 initNodeSet != faceNodeSet) // except an initial face
3833 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3835 freeInd.push_back( iF );
3836 // find source edge of a free face iF
3837 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3838 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3839 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3840 initNodeSet.begin(), initNodeSet.end(),
3841 commonNodes.begin());
3842 if ( (*v)->IsQuadratic() )
3843 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3845 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3847 if ( !srcEdges.back() )
3849 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3850 << iF << " of volume #" << vTool.ID() << endl;
3855 if ( freeInd.empty() )
3858 // create faces for all steps;
3859 // if such a face has been already created by sweep of edge,
3860 // assure that its orientation is OK
3861 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3863 vTool.SetExternalNormal();
3864 list< int >::iterator ind = freeInd.begin();
3865 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3866 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3868 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3869 int nbn = vTool.NbFaceNodes( *ind );
3871 case 3: { ///// triangle
3872 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3874 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3875 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3876 aMesh->ChangeElementNodes( f, nodes, nbn );
3879 case 4: { ///// quadrangle
3880 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3882 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3883 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3884 aMesh->ChangeElementNodes( f, nodes, nbn );
3888 if( (*v)->IsQuadratic() ) {
3889 if(nbn==6) { /////// quadratic triangle
3890 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3891 nodes[1], nodes[3], nodes[5] );
3893 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3894 nodes[1], nodes[3], nodes[5]));
3896 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3897 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3898 tmpnodes[0] = nodes[0];
3899 tmpnodes[1] = nodes[2];
3900 tmpnodes[2] = nodes[4];
3901 tmpnodes[3] = nodes[1];
3902 tmpnodes[4] = nodes[3];
3903 tmpnodes[5] = nodes[5];
3904 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3907 else { /////// quadratic quadrangle
3908 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3909 nodes[1], nodes[3], nodes[5], nodes[7] );
3911 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3912 nodes[1], nodes[3], nodes[5], nodes[7]));
3914 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3915 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3916 tmpnodes[0] = nodes[0];
3917 tmpnodes[1] = nodes[2];
3918 tmpnodes[2] = nodes[4];
3919 tmpnodes[3] = nodes[6];
3920 tmpnodes[4] = nodes[1];
3921 tmpnodes[5] = nodes[3];
3922 tmpnodes[6] = nodes[5];
3923 tmpnodes[7] = nodes[7];
3924 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3928 else { //////// polygon
3929 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3930 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3932 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3933 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3934 aMesh->ChangeElementNodes( f, nodes, nbn );
3937 while ( srcElements.Length() < myLastCreatedElems.Length() )
3938 srcElements.Append( *srcEdge );
3940 } // loop on free faces
3942 // go to the next volume
3944 while ( iVol++ < nbVolumesByStep ) v++;
3947 } // sweep free links into faces
3949 // Make a ceiling face with a normal external to a volume
3951 SMDS_VolumeTool lastVol( itElem->second.back() );
3953 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3955 lastVol.SetExternalNormal();
3956 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3957 int nbn = lastVol.NbFaceNodes( iF );
3960 if (!hasFreeLinks ||
3961 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3962 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3965 if (!hasFreeLinks ||
3966 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3967 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3970 if(itElem->second.back()->IsQuadratic()) {
3972 if (!hasFreeLinks ||
3973 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3974 nodes[1], nodes[3], nodes[5]) ) {
3975 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3976 nodes[1], nodes[3], nodes[5]));
3980 if (!hasFreeLinks ||
3981 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982 nodes[1], nodes[3], nodes[5], nodes[7]) )
3983 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3984 nodes[1], nodes[3], nodes[5], nodes[7]));
3988 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3989 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3990 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3994 while ( srcElements.Length() < myLastCreatedElems.Length() )
3995 srcElements.Append( myLastCreatedElems.Last() );
3997 } // loop on swept elements
4000 //=======================================================================
4001 //function : RotationSweep
4003 //=======================================================================
4005 SMESH_MeshEditor::PGroupIDs
4006 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4007 const gp_Ax1& theAxis,
4008 const double theAngle,
4009 const int theNbSteps,
4010 const double theTol,
4011 const bool theMakeGroups,
4012 const bool theMakeWalls)
4014 myLastCreatedElems.Clear();
4015 myLastCreatedNodes.Clear();
4017 // source elements for each generated one
4018 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4020 MESSAGE( "RotationSweep()");
4022 aTrsf.SetRotation( theAxis, theAngle );
4024 aTrsf2.SetRotation( theAxis, theAngle/2. );
4026 gp_Lin aLine( theAxis );
4027 double aSqTol = theTol * theTol;
4029 SMESHDS_Mesh* aMesh = GetMeshDS();
4031 TNodeOfNodeListMap mapNewNodes;
4032 TElemOfVecOfNnlmiMap mapElemNewNodes;
4033 TElemOfElemListMap newElemsMap;
4036 TIDSortedElemSet::iterator itElem;
4037 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4038 const SMDS_MeshElement* elem = *itElem;
4039 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4041 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4042 newNodesItVec.reserve( elem->NbNodes() );
4044 // loop on elem nodes
4045 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4046 while ( itN->more() ) {
4047 // check if a node has been already sweeped
4048 const SMDS_MeshNode* node = cast2Node( itN->next() );
4050 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4052 aXYZ.Coord( coord[0], coord[1], coord[2] );
4053 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4055 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4056 if ( nIt == mapNewNodes.end() ) {
4057 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4058 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4061 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4063 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4064 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4065 const SMDS_MeshNode * newNode = node;
4066 for ( int i = 0; i < theNbSteps; i++ ) {
4068 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4070 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4071 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4072 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4073 myLastCreatedNodes.Append(newNode);
4074 srcNodes.Append( node );
4075 listNewNodes.push_back( newNode );
4076 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4077 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4080 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4082 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4083 myLastCreatedNodes.Append(newNode);
4084 srcNodes.Append( node );
4085 listNewNodes.push_back( newNode );
4088 listNewNodes.push_back( newNode );
4089 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4090 listNewNodes.push_back( newNode );
4097 // if current elem is quadratic and current node is not medium
4098 // we have to check - may be it is needed to insert additional nodes
4099 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4100 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4101 if(listNewNodes.size()==theNbSteps) {
4102 listNewNodes.clear();
4104 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4106 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4107 const SMDS_MeshNode * newNode = node;
4109 for(int i = 0; i<theNbSteps; i++) {
4110 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4111 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4112 cout<<" 3 AddNode: "<<newNode;
4113 myLastCreatedNodes.Append(newNode);
4114 listNewNodes.push_back( newNode );
4115 srcNodes.Append( node );
4116 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4117 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4118 cout<<" 4 AddNode: "<<newNode;
4119 myLastCreatedNodes.Append(newNode);
4120 srcNodes.Append( node );
4121 listNewNodes.push_back( newNode );
4125 listNewNodes.push_back( newNode );
4131 newNodesItVec.push_back( nIt );
4133 // make new elements
4134 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4138 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4140 PGroupIDs newGroupIDs;
4141 if ( theMakeGroups )
4142 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4148 //=======================================================================
4149 //function : CreateNode
4151 //=======================================================================
4152 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4155 const double tolnode,
4156 SMESH_SequenceOfNode& aNodes)
4158 myLastCreatedElems.Clear();
4159 myLastCreatedNodes.Clear();
4162 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4164 // try to search in sequence of existing nodes
4165 // if aNodes.Length()>0 we 'nave to use given sequence
4166 // else - use all nodes of mesh
4167 if(aNodes.Length()>0) {
4169 for(i=1; i<=aNodes.Length(); i++) {
4170 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4171 if(P1.Distance(P2)<tolnode)
4172 return aNodes.Value(i);
4176 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4177 while(itn->more()) {
4178 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4179 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4180 if(P1.Distance(P2)<tolnode)
4185 // create new node and return it
4186 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4187 myLastCreatedNodes.Append(NewNode);
4192 //=======================================================================
4193 //function : ExtrusionSweep
4195 //=======================================================================
4197 SMESH_MeshEditor::PGroupIDs
4198 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4199 const gp_Vec& theStep,
4200 const int theNbSteps,
4201 TElemOfElemListMap& newElemsMap,
4202 const bool theMakeGroups,
4204 const double theTolerance)
4206 ExtrusParam aParams;
4207 aParams.myDir = gp_Dir(theStep);
4208 aParams.myNodes.Clear();
4209 aParams.mySteps = new TColStd_HSequenceOfReal;
4211 for(i=1; i<=theNbSteps; i++)
4212 aParams.mySteps->Append(theStep.Magnitude());
4215 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4219 //=======================================================================
4220 //function : ExtrusionSweep
4222 //=======================================================================
4224 SMESH_MeshEditor::PGroupIDs
4225 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4226 ExtrusParam& theParams,
4227 TElemOfElemListMap& newElemsMap,
4228 const bool theMakeGroups,
4230 const double theTolerance)
4232 myLastCreatedElems.Clear();
4233 myLastCreatedNodes.Clear();
4235 // source elements for each generated one
4236 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4238 SMESHDS_Mesh* aMesh = GetMeshDS();
4240 int nbsteps = theParams.mySteps->Length();
4242 TNodeOfNodeListMap mapNewNodes;
4243 //TNodeOfNodeVecMap mapNewNodes;
4244 TElemOfVecOfNnlmiMap mapElemNewNodes;
4245 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4248 TIDSortedElemSet::iterator itElem;
4249 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4250 // check element type
4251 const SMDS_MeshElement* elem = *itElem;
4252 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4255 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4256 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4257 newNodesItVec.reserve( elem->NbNodes() );
4259 // loop on elem nodes
4260 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4261 while ( itN->more() )
4263 // check if a node has been already sweeped
4264 const SMDS_MeshNode* node = cast2Node( itN->next() );
4265 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4266 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4267 if ( nIt == mapNewNodes.end() ) {
4268 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4269 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4270 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4271 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4272 //vecNewNodes.reserve(nbsteps);
4275 double coord[] = { node->X(), node->Y(), node->Z() };
4276 //int nbsteps = theParams.mySteps->Length();
4277 for ( int i = 0; i < nbsteps; i++ ) {
4278 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4279 // create additional node
4280 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4281 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4282 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4283 if( theFlags & EXTRUSION_FLAG_SEW ) {
4284 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4285 theTolerance, theParams.myNodes);
4286 listNewNodes.push_back( newNode );
4289 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4290 myLastCreatedNodes.Append(newNode);
4291 srcNodes.Append( node );
4292 listNewNodes.push_back( newNode );
4295 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4296 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4297 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4298 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4299 if( theFlags & EXTRUSION_FLAG_SEW ) {
4300 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4301 theTolerance, theParams.myNodes);
4302 listNewNodes.push_back( newNode );
4303 //vecNewNodes[i]=newNode;
4306 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4307 myLastCreatedNodes.Append(newNode);
4308 srcNodes.Append( node );
4309 listNewNodes.push_back( newNode );
4310 //vecNewNodes[i]=newNode;
4315 // if current elem is quadratic and current node is not medium
4316 // we have to check - may be it is needed to insert additional nodes
4317 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4318 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4319 if(listNewNodes.size()==nbsteps) {
4320 listNewNodes.clear();
4321 double coord[] = { node->X(), node->Y(), node->Z() };
4322 for ( int i = 0; i < nbsteps; i++ ) {
4323 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4324 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4325 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4326 if( theFlags & EXTRUSION_FLAG_SEW ) {
4327 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4328 theTolerance, theParams.myNodes);
4329 listNewNodes.push_back( newNode );
4332 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4333 myLastCreatedNodes.Append(newNode);
4334 srcNodes.Append( node );
4335 listNewNodes.push_back( newNode );
4337 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4338 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4339 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4340 if( theFlags & EXTRUSION_FLAG_SEW ) {
4341 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4342 theTolerance, theParams.myNodes);
4343 listNewNodes.push_back( newNode );
4346 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4347 myLastCreatedNodes.Append(newNode);
4348 srcNodes.Append( node );
4349 listNewNodes.push_back( newNode );
4355 newNodesItVec.push_back( nIt );
4357 // make new elements
4358 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4361 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4362 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4364 PGroupIDs newGroupIDs;
4365 if ( theMakeGroups )
4366 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4372 //=======================================================================
4373 //class : SMESH_MeshEditor_PathPoint
4374 //purpose : auxiliary class
4375 //=======================================================================
4376 class SMESH_MeshEditor_PathPoint {
4378 SMESH_MeshEditor_PathPoint() {
4379 myPnt.SetCoord(99., 99., 99.);
4380 myTgt.SetCoord(1.,0.,0.);
4384 void SetPnt(const gp_Pnt& aP3D){
4387 void SetTangent(const gp_Dir& aTgt){
4390 void SetAngle(const double& aBeta){
4393 void SetParameter(const double& aPrm){
4396 const gp_Pnt& Pnt()const{
4399 const gp_Dir& Tangent()const{
4402 double Angle()const{
4405 double Parameter()const{
4417 //=======================================================================
4418 //function : ExtrusionAlongTrack
4420 //=======================================================================
4421 SMESH_MeshEditor::Extrusion_Error
4422 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4423 SMESH_subMesh* theTrack,
4424 const SMDS_MeshNode* theN1,
4425 const bool theHasAngles,
4426 list<double>& theAngles,
4427 const bool theLinearVariation,
4428 const bool theHasRefPoint,
4429 const gp_Pnt& theRefPoint,
4430 const bool theMakeGroups)
4432 myLastCreatedElems.Clear();
4433 myLastCreatedNodes.Clear();
4436 std::list<double> aPrms;
4437 TIDSortedElemSet::iterator itElem;
4440 TopoDS_Edge aTrackEdge;
4441 TopoDS_Vertex aV1, aV2;
4443 SMDS_ElemIteratorPtr aItE;
4444 SMDS_NodeIteratorPtr aItN;
4445 SMDSAbs_ElementType aTypeE;
4447 TNodeOfNodeListMap mapNewNodes;
4450 aNbE = theElements.size();
4453 return EXTR_NO_ELEMENTS;
4455 // 1.1 Track Pattern
4458 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4460 aItE = pSubMeshDS->GetElements();
4461 while ( aItE->more() ) {
4462 const SMDS_MeshElement* pE = aItE->next();
4463 aTypeE = pE->GetType();
4464 // Pattern must contain links only
4465 if ( aTypeE != SMDSAbs_Edge )
4466 return EXTR_PATH_NOT_EDGE;
4469 list<SMESH_MeshEditor_PathPoint> fullList;
4471 const TopoDS_Shape& aS = theTrack->GetSubShape();
4472 // Sub shape for the Pattern must be an Edge or Wire
4473 if( aS.ShapeType() == TopAbs_EDGE ) {
4474 aTrackEdge = TopoDS::Edge( aS );
4475 // the Edge must not be degenerated
4476 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4477 return EXTR_BAD_PATH_SHAPE;
4478 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4479 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4480 const SMDS_MeshNode* aN1 = aItN->next();
4481 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4482 const SMDS_MeshNode* aN2 = aItN->next();
4483 // starting node must be aN1 or aN2
4484 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4485 return EXTR_BAD_STARTING_NODE;
4486 aItN = pSubMeshDS->GetNodes();
4487 while ( aItN->more() ) {
4488 const SMDS_MeshNode* pNode = aItN->next();
4489 const SMDS_EdgePosition* pEPos =
4490 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4491 double aT = pEPos->GetUParameter();
4492 aPrms.push_back( aT );
4494 //Extrusion_Error err =
4495 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4497 else if( aS.ShapeType() == TopAbs_WIRE ) {
4498 list< SMESH_subMesh* > LSM;
4499 TopTools_SequenceOfShape Edges;
4500 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4501 while(itSM->more()) {
4502 SMESH_subMesh* SM = itSM->next();
4504 const TopoDS_Shape& aS = SM->GetSubShape();
4507 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4508 int startNid = theN1->GetID();
4509 TColStd_MapOfInteger UsedNums;
4510 int NbEdges = Edges.Length();
4512 for(; i<=NbEdges; i++) {
4514 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4515 for(; itLSM!=LSM.end(); itLSM++) {
4517 if(UsedNums.Contains(k)) continue;
4518 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4519 SMESH_subMesh* locTrack = *itLSM;
4520 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4521 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4522 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4523 const SMDS_MeshNode* aN1 = aItN->next();
4524 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4525 const SMDS_MeshNode* aN2 = aItN->next();
4526 // starting node must be aN1 or aN2
4527 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4528 // 2. Collect parameters on the track edge
4530 aItN = locMeshDS->GetNodes();
4531 while ( aItN->more() ) {
4532 const SMDS_MeshNode* pNode = aItN->next();
4533 const SMDS_EdgePosition* pEPos =
4534 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4535 double aT = pEPos->GetUParameter();
4536 aPrms.push_back( aT );
4538 list<SMESH_MeshEditor_PathPoint> LPP;
4539 //Extrusion_Error err =
4540 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4541 LLPPs.push_back(LPP);
4543 // update startN for search following egde
4544 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4545 else startNid = aN1->GetID();
4549 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4550 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4551 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4552 for(; itPP!=firstList.end(); itPP++) {
4553 fullList.push_back( *itPP );
4555 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4556 fullList.pop_back();
4558 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4559 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4560 itPP = currList.begin();
4561 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4562 gp_Dir D1 = PP1.Tangent();
4563 gp_Dir D2 = PP2.Tangent();
4564 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4565 (D1.Z()+D2.Z())/2 ) );
4566 PP1.SetTangent(Dnew);
4567 fullList.push_back(PP1);
4569 for(; itPP!=firstList.end(); itPP++) {
4570 fullList.push_back( *itPP );
4572 PP1 = fullList.back();
4573 fullList.pop_back();
4575 // if wire not closed
4576 fullList.push_back(PP1);
4580 return EXTR_BAD_PATH_SHAPE;
4583 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4584 theHasRefPoint, theRefPoint, theMakeGroups);
4588 //=======================================================================
4589 //function : ExtrusionAlongTrack
4591 //=======================================================================
4592 SMESH_MeshEditor::Extrusion_Error
4593 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4594 SMESH_Mesh* theTrack,
4595 const SMDS_MeshNode* theN1,
4596 const bool theHasAngles,
4597 list<double>& theAngles,
4598 const bool theLinearVariation,
4599 const bool theHasRefPoint,
4600 const gp_Pnt& theRefPoint,
4601 const bool theMakeGroups)
4603 myLastCreatedElems.Clear();
4604 myLastCreatedNodes.Clear();
4607 std::list<double> aPrms;
4608 TIDSortedElemSet::iterator itElem;
4611 TopoDS_Edge aTrackEdge;
4612 TopoDS_Vertex aV1, aV2;
4614 SMDS_ElemIteratorPtr aItE;
4615 SMDS_NodeIteratorPtr aItN;
4616 SMDSAbs_ElementType aTypeE;
4618 TNodeOfNodeListMap mapNewNodes;
4621 aNbE = theElements.size();
4624 return EXTR_NO_ELEMENTS;
4626 // 1.1 Track Pattern
4629 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4631 aItE = pMeshDS->elementsIterator();
4632 while ( aItE->more() ) {
4633 const SMDS_MeshElement* pE = aItE->next();
4634 aTypeE = pE->GetType();
4635 // Pattern must contain links only
4636 if ( aTypeE != SMDSAbs_Edge )
4637 return EXTR_PATH_NOT_EDGE;
4640 list<SMESH_MeshEditor_PathPoint> fullList;
4642 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4643 // Sub shape for the Pattern must be an Edge or Wire
4644 if( aS.ShapeType() == TopAbs_EDGE ) {
4645 aTrackEdge = TopoDS::Edge( aS );
4646 // the Edge must not be degenerated
4647 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4648 return EXTR_BAD_PATH_SHAPE;
4649 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4650 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4651 const SMDS_MeshNode* aN1 = aItN->next();
4652 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4653 const SMDS_MeshNode* aN2 = aItN->next();
4654 // starting node must be aN1 or aN2
4655 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4656 return EXTR_BAD_STARTING_NODE;
4657 aItN = pMeshDS->nodesIterator();
4658 while ( aItN->more() ) {
4659 const SMDS_MeshNode* pNode = aItN->next();
4660 if( pNode==aN1 || pNode==aN2 ) continue;
4661 const SMDS_EdgePosition* pEPos =
4662 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4663 double aT = pEPos->GetUParameter();
4664 aPrms.push_back( aT );
4666 //Extrusion_Error err =
4667 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4669 else if( aS.ShapeType() == TopAbs_WIRE ) {
4670 list< SMESH_subMesh* > LSM;
4671 TopTools_SequenceOfShape Edges;
4672 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4673 for(; eExp.More(); eExp.Next()) {
4674 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4675 if( BRep_Tool::Degenerated(E) ) continue;
4676 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4682 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4683 int startNid = theN1->GetID();
4684 TColStd_MapOfInteger UsedNums;
4685 int NbEdges = Edges.Length();
4687 for(; i<=NbEdges; i++) {
4689 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4690 for(; itLSM!=LSM.end(); itLSM++) {
4692 if(UsedNums.Contains(k)) continue;
4693 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4694 SMESH_subMesh* locTrack = *itLSM;
4695 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4696 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4697 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4698 const SMDS_MeshNode* aN1 = aItN->next();
4699 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4700 const SMDS_MeshNode* aN2 = aItN->next();
4701 // starting node must be aN1 or aN2
4702 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4703 // 2. Collect parameters on the track edge
4705 aItN = locMeshDS->GetNodes();
4706 while ( aItN->more() ) {
4707 const SMDS_MeshNode* pNode = aItN->next();
4708 const SMDS_EdgePosition* pEPos =
4709 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4710 double aT = pEPos->GetUParameter();
4711 aPrms.push_back( aT );
4713 list<SMESH_MeshEditor_PathPoint> LPP;
4714 //Extrusion_Error err =
4715 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4716 LLPPs.push_back(LPP);
4718 // update startN for search following egde
4719 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4720 else startNid = aN1->GetID();
4724 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4725 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4726 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4727 for(; itPP!=firstList.end(); itPP++) {
4728 fullList.push_back( *itPP );
4730 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4731 fullList.pop_back();
4733 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4734 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4735 itPP = currList.begin();
4736 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4737 gp_Pnt P1 = PP1.Pnt();
4738 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4739 gp_Pnt P2 = PP2.Pnt();
4740 gp_Dir D1 = PP1.Tangent();
4741 gp_Dir D2 = PP2.Tangent();
4742 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4743 (D1.Z()+D2.Z())/2 ) );
4744 PP1.SetTangent(Dnew);
4745 fullList.push_back(PP1);
4747 for(; itPP!=currList.end(); itPP++) {
4748 fullList.push_back( *itPP );
4750 PP1 = fullList.back();
4751 fullList.pop_back();
4753 // if wire not closed
4754 fullList.push_back(PP1);
4758 return EXTR_BAD_PATH_SHAPE;
4761 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4762 theHasRefPoint, theRefPoint, theMakeGroups);
4766 //=======================================================================
4767 //function : MakeEdgePathPoints
4768 //purpose : auxilary for ExtrusionAlongTrack
4769 //=======================================================================
4770 SMESH_MeshEditor::Extrusion_Error
4771 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4772 const TopoDS_Edge& aTrackEdge,
4774 list<SMESH_MeshEditor_PathPoint>& LPP)
4776 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4778 aTolVec2=aTolVec*aTolVec;
4780 TopoDS_Vertex aV1, aV2;
4781 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4782 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4783 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4784 // 2. Collect parameters on the track edge
4785 aPrms.push_front( aT1 );
4786 aPrms.push_back( aT2 );
4789 if( FirstIsStart ) {
4800 SMESH_MeshEditor_PathPoint aPP;
4801 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4802 std::list<double>::iterator aItD = aPrms.begin();
4803 for(; aItD != aPrms.end(); ++aItD) {
4807 aC3D->D1( aT, aP3D, aVec );
4808 aL2 = aVec.SquareMagnitude();
4809 if ( aL2 < aTolVec2 )
4810 return EXTR_CANT_GET_TANGENT;
4811 gp_Dir aTgt( aVec );
4813 aPP.SetTangent( aTgt );
4814 aPP.SetParameter( aT );
4821 //=======================================================================
4822 //function : MakeExtrElements
4823 //purpose : auxilary for ExtrusionAlongTrack
4824 //=======================================================================
4825 SMESH_MeshEditor::Extrusion_Error
4826 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4827 list<SMESH_MeshEditor_PathPoint>& fullList,
4828 const bool theHasAngles,
4829 list<double>& theAngles,
4830 const bool theLinearVariation,
4831 const bool theHasRefPoint,
4832 const gp_Pnt& theRefPoint,
4833 const bool theMakeGroups)
4835 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4836 int aNbTP = fullList.size();
4837 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4839 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4840 LinearAngleVariation(aNbTP-1, theAngles);
4842 vector<double> aAngles( aNbTP );
4844 for(; j<aNbTP; ++j) {
4847 if ( theHasAngles ) {
4849 std::list<double>::iterator aItD = theAngles.begin();
4850 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4852 aAngles[j] = anAngle;
4855 // fill vector of path points with angles
4856 //aPPs.resize(fullList.size());
4858 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4859 for(; itPP!=fullList.end(); itPP++) {
4861 SMESH_MeshEditor_PathPoint PP = *itPP;
4862 PP.SetAngle(aAngles[j]);
4866 TNodeOfNodeListMap mapNewNodes;
4867 TElemOfVecOfNnlmiMap mapElemNewNodes;
4868 TElemOfElemListMap newElemsMap;
4869 TIDSortedElemSet::iterator itElem;
4872 SMDSAbs_ElementType aTypeE;
4873 // source elements for each generated one
4874 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4876 // 3. Center of rotation aV0
4877 gp_Pnt aV0 = theRefPoint;
4879 if ( !theHasRefPoint ) {
4881 aGC.SetCoord( 0.,0.,0. );
4883 itElem = theElements.begin();
4884 for ( ; itElem != theElements.end(); itElem++ ) {
4885 const SMDS_MeshElement* elem = *itElem;
4887 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4888 while ( itN->more() ) {
4889 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4894 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4895 list<const SMDS_MeshNode*> aLNx;
4896 mapNewNodes[node] = aLNx;
4898 gp_XYZ aXYZ( aX, aY, aZ );
4906 } // if (!theHasRefPoint) {
4907 mapNewNodes.clear();
4909 // 4. Processing the elements
4910 SMESHDS_Mesh* aMesh = GetMeshDS();
4912 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4913 // check element type
4914 const SMDS_MeshElement* elem = *itElem;
4915 aTypeE = elem->GetType();
4916 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4919 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4920 newNodesItVec.reserve( elem->NbNodes() );
4922 // loop on elem nodes
4924 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4925 while ( itN->more() )
4928 // check if a node has been already processed
4929 const SMDS_MeshNode* node =
4930 static_cast<const SMDS_MeshNode*>( itN->next() );
4931 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4932 if ( nIt == mapNewNodes.end() ) {
4933 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4934 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4937 aX = node->X(); aY = node->Y(); aZ = node->Z();
4939 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4940 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4941 gp_Ax1 anAx1, anAxT1T0;
4942 gp_Dir aDT1x, aDT0x, aDT1T0;
4947 aPN0.SetCoord(aX, aY, aZ);
4949 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4951 aDT0x= aPP0.Tangent();
4952 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4954 for ( j = 1; j < aNbTP; ++j ) {
4955 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4957 aDT1x = aPP1.Tangent();
4958 aAngle1x = aPP1.Angle();
4960 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4962 gp_Vec aV01x( aP0x, aP1x );
4963 aTrsf.SetTranslation( aV01x );
4966 aV1x = aV0x.Transformed( aTrsf );
4967 aPN1 = aPN0.Transformed( aTrsf );
4969 // rotation 1 [ T1,T0 ]
4970 aAngleT1T0=-aDT1x.Angle( aDT0x );
4971 if (fabs(aAngleT1T0) > aTolAng) {
4973 anAxT1T0.SetLocation( aV1x );
4974 anAxT1T0.SetDirection( aDT1T0 );
4975 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4977 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4981 if ( theHasAngles ) {
4982 anAx1.SetLocation( aV1x );
4983 anAx1.SetDirection( aDT1x );
4984 aTrsfRot.SetRotation( anAx1, aAngle1x );
4986 aPN1 = aPN1.Transformed( aTrsfRot );
4990 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4991 // create additional node
4992 double x = ( aPN1.X() + aPN0.X() )/2.;
4993 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4994 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4995 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4996 myLastCreatedNodes.Append(newNode);
4997 srcNodes.Append( node );
4998 listNewNodes.push_back( newNode );
5003 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5004 myLastCreatedNodes.Append(newNode);
5005 srcNodes.Append( node );
5006 listNewNodes.push_back( newNode );
5016 // if current elem is quadratic and current node is not medium
5017 // we have to check - may be it is needed to insert additional nodes
5018 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5019 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5020 if(listNewNodes.size()==aNbTP-1) {
5021 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5022 gp_XYZ P(node->X(), node->Y(), node->Z());
5023 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5025 for(i=0; i<aNbTP-1; i++) {
5026 const SMDS_MeshNode* N = *it;
5027 double x = ( N->X() + P.X() )/2.;
5028 double y = ( N->Y() + P.Y() )/2.;
5029 double z = ( N->Z() + P.Z() )/2.;
5030 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5031 srcNodes.Append( node );
5032 myLastCreatedNodes.Append(newN);
5035 P = gp_XYZ(N->X(),N->Y(),N->Z());
5037 listNewNodes.clear();
5038 for(i=0; i<2*(aNbTP-1); i++) {
5039 listNewNodes.push_back(aNodes[i]);
5045 newNodesItVec.push_back( nIt );
5047 // make new elements
5048 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5049 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5050 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5053 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5055 if ( theMakeGroups )
5056 generateGroups( srcNodes, srcElems, "extruded");
5062 //=======================================================================
5063 //function : LinearAngleVariation
5064 //purpose : auxilary for ExtrusionAlongTrack
5065 //=======================================================================
5066 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5067 list<double>& Angles)
5069 int nbAngles = Angles.size();
5070 if( nbSteps > nbAngles ) {
5071 vector<double> theAngles(nbAngles);
5072 list<double>::iterator it = Angles.begin();
5074 for(; it!=Angles.end(); it++) {
5076 theAngles[i] = (*it);
5079 double rAn2St = double( nbAngles ) / double( nbSteps );
5080 double angPrev = 0, angle;
5081 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5082 double angCur = rAn2St * ( iSt+1 );
5083 double angCurFloor = floor( angCur );
5084 double angPrevFloor = floor( angPrev );
5085 if ( angPrevFloor == angCurFloor )
5086 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5088 int iP = int( angPrevFloor );
5089 double angPrevCeil = ceil(angPrev);
5090 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5092 int iC = int( angCurFloor );
5093 if ( iC < nbAngles )
5094 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5096 iP = int( angPrevCeil );
5098 angle += theAngles[ iC ];
5100 res.push_back(angle);
5105 for(; it!=res.end(); it++)
5106 Angles.push_back( *it );
5111 //=======================================================================
5112 //function : Transform
5114 //=======================================================================
5116 SMESH_MeshEditor::PGroupIDs
5117 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5118 const gp_Trsf& theTrsf,
5120 const bool theMakeGroups,
5121 SMESH_Mesh* theTargetMesh)
5123 myLastCreatedElems.Clear();
5124 myLastCreatedNodes.Clear();
5126 bool needReverse = false;
5127 string groupPostfix;
5128 switch ( theTrsf.Form() ) {
5133 groupPostfix = "mirrored";
5136 groupPostfix = "rotated";
5138 case gp_Translation:
5139 groupPostfix = "translated";
5142 groupPostfix = "scaled";
5145 needReverse = false;
5146 groupPostfix = "transformed";
5149 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5150 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5151 SMESHDS_Mesh* aMesh = GetMeshDS();
5154 // map old node to new one
5155 TNodeNodeMap nodeMap;
5157 // elements sharing moved nodes; those of them which have all
5158 // nodes mirrored but are not in theElems are to be reversed
5159 TIDSortedElemSet inverseElemSet;
5161 // source elements for each generated one
5162 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5165 TIDSortedElemSet::iterator itElem;
5166 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5167 const SMDS_MeshElement* elem = *itElem;
5171 // loop on elem nodes
5172 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5173 while ( itN->more() ) {
5175 // check if a node has been already transformed
5176 const SMDS_MeshNode* node = cast2Node( itN->next() );
5177 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5178 nodeMap.insert( make_pair ( node, node ));
5179 if ( !n2n_isnew.second )
5183 coord[0] = node->X();
5184 coord[1] = node->Y();
5185 coord[2] = node->Z();
5186 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5187 if ( theTargetMesh ) {
5188 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5189 n2n_isnew.first->second = newNode;
5190 myLastCreatedNodes.Append(newNode);
5191 srcNodes.Append( node );
5193 else if ( theCopy ) {
5194 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5195 n2n_isnew.first->second = newNode;
5196 myLastCreatedNodes.Append(newNode);
5197 srcNodes.Append( node );
5200 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5201 // node position on shape becomes invalid
5202 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5203 ( SMDS_SpacePosition::originSpacePosition() );
5206 // keep inverse elements
5207 if ( !theCopy && !theTargetMesh && needReverse ) {
5208 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5209 while ( invElemIt->more() ) {
5210 const SMDS_MeshElement* iel = invElemIt->next();
5211 inverseElemSet.insert( iel );
5217 // either create new elements or reverse mirrored ones
5218 if ( !theCopy && !needReverse && !theTargetMesh )
5221 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5222 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5223 theElems.insert( *invElemIt );
5225 // replicate or reverse elements
5228 REV_TETRA = 0, // = nbNodes - 4
5229 REV_PYRAMID = 1, // = nbNodes - 4
5230 REV_PENTA = 2, // = nbNodes - 4
5232 REV_HEXA = 4, // = nbNodes - 4
5236 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5237 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5238 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5239 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5240 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5241 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5244 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5246 const SMDS_MeshElement* elem = *itElem;
5247 if ( !elem || elem->GetType() == SMDSAbs_Node )
5250 int nbNodes = elem->NbNodes();
5251 int elemType = elem->GetType();
5253 if (elem->IsPoly()) {
5254 // Polygon or Polyhedral Volume
5255 switch ( elemType ) {
5258 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5260 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5261 while (itN->more()) {
5262 const SMDS_MeshNode* node =
5263 static_cast<const SMDS_MeshNode*>(itN->next());
5264 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5265 if (nodeMapIt == nodeMap.end())
5266 break; // not all nodes transformed
5268 // reverse mirrored faces and volumes
5269 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5271 poly_nodes[iNode] = (*nodeMapIt).second;
5275 if ( iNode != nbNodes )
5276 continue; // not all nodes transformed
5278 if ( theTargetMesh ) {
5279 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5280 srcElems.Append( elem );
5282 else if ( theCopy ) {
5283 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5284 srcElems.Append( elem );
5287 aMesh->ChangePolygonNodes(elem, poly_nodes);
5291 case SMDSAbs_Volume:
5293 // ATTENTION: Reversing is not yet done!!!
5294 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5295 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5297 MESSAGE("Warning: bad volumic element");
5301 vector<const SMDS_MeshNode*> poly_nodes;
5302 vector<int> quantities;
5304 bool allTransformed = true;
5305 int nbFaces = aPolyedre->NbFaces();
5306 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5307 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5308 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5309 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5310 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5311 if (nodeMapIt == nodeMap.end()) {
5312 allTransformed = false; // not all nodes transformed
5314 poly_nodes.push_back((*nodeMapIt).second);
5317 quantities.push_back(nbFaceNodes);
5319 if ( !allTransformed )
5320 continue; // not all nodes transformed
5322 if ( theTargetMesh ) {
5323 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5324 srcElems.Append( elem );
5326 else if ( theCopy ) {
5327 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5328 srcElems.Append( elem );
5331 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5341 int* i = index[ FORWARD ];
5342 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5343 if ( elemType == SMDSAbs_Face )
5344 i = index[ REV_FACE ];
5346 i = index[ nbNodes - 4 ];
5348 if(elem->IsQuadratic()) {
5349 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5352 if(nbNodes==3) { // quadratic edge
5353 static int anIds[] = {1,0,2};
5356 else if(nbNodes==6) { // quadratic triangle
5357 static int anIds[] = {0,2,1,5,4,3};
5360 else if(nbNodes==8) { // quadratic quadrangle
5361 static int anIds[] = {0,3,2,1,7,6,5,4};
5364 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5365 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5368 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5369 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5372 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5373 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5376 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5377 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5383 // find transformed nodes
5384 vector<const SMDS_MeshNode*> nodes(nbNodes);
5386 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5387 while ( itN->more() ) {
5388 const SMDS_MeshNode* node =
5389 static_cast<const SMDS_MeshNode*>( itN->next() );
5390 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5391 if ( nodeMapIt == nodeMap.end() )
5392 break; // not all nodes transformed
5393 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5395 if ( iNode != nbNodes )
5396 continue; // not all nodes transformed
5398 if ( theTargetMesh ) {
5399 if ( SMDS_MeshElement* copy =
5400 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5401 myLastCreatedElems.Append( copy );
5402 srcElems.Append( elem );
5405 else if ( theCopy ) {
5406 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5407 myLastCreatedElems.Append( copy );
5408 srcElems.Append( elem );
5412 // reverse element as it was reversed by transformation
5414 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5418 PGroupIDs newGroupIDs;
5420 if ( theMakeGroups && theCopy ||
5421 theMakeGroups && theTargetMesh )
5422 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5428 //=======================================================================
5431 //=======================================================================
5433 SMESH_MeshEditor::PGroupIDs
5434 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5435 const gp_Pnt& thePoint,
5436 const std::list<double>& theScaleFact,
5438 const bool theMakeGroups,
5439 SMESH_Mesh* theTargetMesh)
5441 myLastCreatedElems.Clear();
5442 myLastCreatedNodes.Clear();
5444 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5445 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5446 SMESHDS_Mesh* aMesh = GetMeshDS();
5448 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5449 std::list<double>::const_iterator itS = theScaleFact.begin();
5451 if(theScaleFact.size()==1) {
5455 if(theScaleFact.size()==2) {
5460 if(theScaleFact.size()>2) {
5467 // map old node to new one
5468 TNodeNodeMap nodeMap;
5470 // elements sharing moved nodes; those of them which have all
5471 // nodes mirrored but are not in theElems are to be reversed
5472 TIDSortedElemSet inverseElemSet;
5474 // source elements for each generated one
5475 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5478 TIDSortedElemSet::iterator itElem;
5479 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5480 const SMDS_MeshElement* elem = *itElem;
5484 // loop on elem nodes
5485 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5486 while ( itN->more() ) {
5488 // check if a node has been already transformed
5489 const SMDS_MeshNode* node = cast2Node( itN->next() );
5490 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5491 nodeMap.insert( make_pair ( node, node ));
5492 if ( !n2n_isnew.second )
5496 //coord[0] = node->X();
5497 //coord[1] = node->Y();
5498 //coord[2] = node->Z();
5499 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5500 double dx = (node->X() - thePoint.X()) * scaleX;
5501 double dy = (node->Y() - thePoint.Y()) * scaleY;
5502 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5503 if ( theTargetMesh ) {
5504 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5505 const SMDS_MeshNode * newNode =
5506 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5507 n2n_isnew.first->second = newNode;
5508 myLastCreatedNodes.Append(newNode);
5509 srcNodes.Append( node );
5511 else if ( theCopy ) {
5512 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5513 const SMDS_MeshNode * newNode =
5514 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5515 n2n_isnew.first->second = newNode;
5516 myLastCreatedNodes.Append(newNode);
5517 srcNodes.Append( node );
5520 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5521 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5522 // node position on shape becomes invalid
5523 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5524 ( SMDS_SpacePosition::originSpacePosition() );
5527 // keep inverse elements
5528 //if ( !theCopy && !theTargetMesh && needReverse ) {
5529 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5530 // while ( invElemIt->more() ) {
5531 // const SMDS_MeshElement* iel = invElemIt->next();
5532 // inverseElemSet.insert( iel );
5538 // either create new elements or reverse mirrored ones
5539 //if ( !theCopy && !needReverse && !theTargetMesh )
5540 if ( !theCopy && !theTargetMesh )
5543 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5544 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5545 theElems.insert( *invElemIt );
5547 // replicate or reverse elements
5550 REV_TETRA = 0, // = nbNodes - 4
5551 REV_PYRAMID = 1, // = nbNodes - 4
5552 REV_PENTA = 2, // = nbNodes - 4
5554 REV_HEXA = 4, // = nbNodes - 4
5558 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5559 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5560 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5561 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5562 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5563 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5566 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5568 const SMDS_MeshElement* elem = *itElem;
5569 if ( !elem || elem->GetType() == SMDSAbs_Node )
5572 int nbNodes = elem->NbNodes();
5573 int elemType = elem->GetType();
5575 if (elem->IsPoly()) {
5576 // Polygon or Polyhedral Volume
5577 switch ( elemType ) {
5580 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5582 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5583 while (itN->more()) {
5584 const SMDS_MeshNode* node =
5585 static_cast<const SMDS_MeshNode*>(itN->next());
5586 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5587 if (nodeMapIt == nodeMap.end())
5588 break; // not all nodes transformed
5589 //if (needReverse) {
5590 // // reverse mirrored faces and volumes
5591 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5593 poly_nodes[iNode] = (*nodeMapIt).second;
5597 if ( iNode != nbNodes )
5598 continue; // not all nodes transformed
5600 if ( theTargetMesh ) {
5601 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5602 srcElems.Append( elem );
5604 else if ( theCopy ) {
5605 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5606 srcElems.Append( elem );
5609 aMesh->ChangePolygonNodes(elem, poly_nodes);
5613 case SMDSAbs_Volume:
5615 // ATTENTION: Reversing is not yet done!!!
5616 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5617 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5619 MESSAGE("Warning: bad volumic element");
5623 vector<const SMDS_MeshNode*> poly_nodes;
5624 vector<int> quantities;
5626 bool allTransformed = true;
5627 int nbFaces = aPolyedre->NbFaces();
5628 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5629 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5630 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5631 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5632 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5633 if (nodeMapIt == nodeMap.end()) {
5634 allTransformed = false; // not all nodes transformed
5636 poly_nodes.push_back((*nodeMapIt).second);
5639 quantities.push_back(nbFaceNodes);
5641 if ( !allTransformed )
5642 continue; // not all nodes transformed
5644 if ( theTargetMesh ) {
5645 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5646 srcElems.Append( elem );
5648 else if ( theCopy ) {
5649 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5650 srcElems.Append( elem );
5653 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5663 int* i = index[ FORWARD ];
5664 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5665 // if ( elemType == SMDSAbs_Face )
5666 // i = index[ REV_FACE ];
5668 // i = index[ nbNodes - 4 ];
5670 if(elem->IsQuadratic()) {
5671 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5674 // if(nbNodes==3) { // quadratic edge
5675 // static int anIds[] = {1,0,2};
5678 // else if(nbNodes==6) { // quadratic triangle
5679 // static int anIds[] = {0,2,1,5,4,3};
5682 // else if(nbNodes==8) { // quadratic quadrangle
5683 // static int anIds[] = {0,3,2,1,7,6,5,4};
5686 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5687 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5690 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5691 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5694 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5695 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5698 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5699 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5705 // find transformed nodes
5706 vector<const SMDS_MeshNode*> nodes(nbNodes);
5708 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5709 while ( itN->more() ) {
5710 const SMDS_MeshNode* node =
5711 static_cast<const SMDS_MeshNode*>( itN->next() );
5712 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5713 if ( nodeMapIt == nodeMap.end() )
5714 break; // not all nodes transformed
5715 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5717 if ( iNode != nbNodes )
5718 continue; // not all nodes transformed
5720 if ( theTargetMesh ) {
5721 if ( SMDS_MeshElement* copy =
5722 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5723 myLastCreatedElems.Append( copy );
5724 srcElems.Append( elem );
5727 else if ( theCopy ) {
5728 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5729 myLastCreatedElems.Append( copy );
5730 srcElems.Append( elem );
5734 // reverse element as it was reversed by transformation
5736 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5740 PGroupIDs newGroupIDs;
5742 if ( theMakeGroups && theCopy ||
5743 theMakeGroups && theTargetMesh ) {
5744 string groupPostfix = "scaled";
5745 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5752 //=======================================================================
5754 * \brief Create groups of elements made during transformation
5755 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5756 * \param elemGens - elements making corresponding myLastCreatedElems
5757 * \param postfix - to append to names of new groups
5759 //=======================================================================
5761 SMESH_MeshEditor::PGroupIDs
5762 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5763 const SMESH_SequenceOfElemPtr& elemGens,
5764 const std::string& postfix,
5765 SMESH_Mesh* targetMesh)
5767 PGroupIDs newGroupIDs( new list<int> );
5768 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5770 // Sort existing groups by types and collect their names
5772 // to store an old group and a generated new one
5773 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5774 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5776 set< string > groupNames;
5778 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5779 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5780 while ( groupIt->more() ) {
5781 SMESH_Group * group = groupIt->next();
5782 if ( !group ) continue;
5783 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5784 if ( !groupDS || groupDS->IsEmpty() ) continue;
5785 groupNames.insert( group->GetName() );
5786 groupDS->SetStoreName( group->GetName() );
5787 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5792 // loop on nodes and elements
5793 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5795 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5796 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5797 if ( gens.Length() != elems.Length() )
5798 throw SALOME_Exception(LOCALIZED("invalid args"));
5800 // loop on created elements
5801 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5803 const SMDS_MeshElement* sourceElem = gens( iElem );
5804 if ( !sourceElem ) {
5805 MESSAGE("generateGroups(): NULL source element");
5808 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5809 if ( groupsOldNew.empty() ) {
5810 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5811 ++iElem; // skip all elements made by sourceElem
5814 // collect all elements made by sourceElem
5815 list< const SMDS_MeshElement* > resultElems;
5816 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5817 if ( resElem != sourceElem )
5818 resultElems.push_back( resElem );
5819 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5820 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5821 if ( resElem != sourceElem )
5822 resultElems.push_back( resElem );
5823 // do not generate element groups from node ones
5824 if ( sourceElem->GetType() == SMDSAbs_Node &&
5825 elems( iElem )->GetType() != SMDSAbs_Node )
5828 // add resultElems to groups made by ones the sourceElem belongs to
5829 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5830 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5832 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5833 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5835 SMDS_MeshGroup* & newGroup = gOldNew->second;
5836 if ( !newGroup )// create a new group
5839 string name = oldGroup->GetStoreName();
5840 if ( !targetMesh ) {
5844 while ( !groupNames.insert( name ).second ) // name exists
5850 TCollection_AsciiString nbStr(nb+1);
5851 name.resize( name.rfind('_')+1 );
5852 name += nbStr.ToCString();
5859 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5861 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5862 newGroup = & groupDS->SMDSGroup();
5863 newGroupIDs->push_back( id );
5866 // fill in a new group
5867 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5868 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5869 newGroup->Add( *resElemIt );
5872 } // loop on created elements
5873 }// loop on nodes and elements
5878 //================================================================================
5880 * \brief Return list of group of nodes close to each other within theTolerance
5881 * Search among theNodes or in the whole mesh if theNodes is empty using
5882 * an Octree algorithm
5884 //================================================================================
5886 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
5887 const double theTolerance,
5888 TListOfListOfNodes & theGroupsOfNodes)
5890 myLastCreatedElems.Clear();
5891 myLastCreatedNodes.Clear();
5893 if ( theNodes.empty() )
5894 { // get all nodes in the mesh
5895 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5896 while ( nIt->more() )
5897 theNodes.insert( theNodes.end(),nIt->next());
5900 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &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 TIDSortedNodeSet nodes;
5922 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
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 bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5975 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5977 SMESH_OctreeNode* tree = *trIt;
5978 if ( !tree->isLeaf() ) // put children to the queue
5980 if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5981 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5982 while ( cIt->more() )
5983 treeList.push_back( cIt->next() );
5985 else if ( tree->NbNodes() ) // put a tree to the treeMap
5987 const Bnd_B3d& box = tree->getBox();
5988 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5989 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5990 if ( !it_in.second ) // not unique distance to box center
5991 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5994 // find distance after which there is no sense to check tree's
5995 double sqLimit = DBL_MAX;
5996 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5997 if ( treeMap.size() > 5 ) {
5998 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5999 const Bnd_B3d& box = closestTree->getBox();
6000 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6001 sqLimit = limit * limit;
6003 // get all nodes from trees
6004 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6005 if ( sqDist_tree->first > sqLimit )
6007 SMESH_OctreeNode* tree = sqDist_tree->second;
6008 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6011 // find closest among nodes
6012 minSqDist = DBL_MAX;
6013 const SMDS_MeshNode* closestNode = 0;
6014 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6015 for ( ; nIt != nodes.end(); ++nIt ) {
6016 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6017 if ( minSqDist > sqDist ) {
6025 //---------------------------------------------------------------------
6029 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6031 //---------------------------------------------------------------------
6033 * \brief Return the node tree
6035 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6038 SMESH_OctreeNode* myOctreeNode;
6039 SMESHDS_Mesh* myMesh;
6040 double myHalfLeafSize; // max size of a leaf box
6043 //=======================================================================
6045 * \brief Return SMESH_NodeSearcher
6047 //=======================================================================
6049 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6051 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6054 // ========================================================================
6055 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6057 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6058 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6059 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6061 //=======================================================================
6063 * \brief Octal tree of bounding boxes of elements
6065 //=======================================================================
6067 class ElementBndBoxTree : public SMESH_Octree
6071 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6072 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6073 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6074 ~ElementBndBoxTree();
6077 ElementBndBoxTree() {}
6078 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6079 void buildChildrenData();
6080 Bnd_B3d* buildRootBox();
6082 //!< Bounding box of element
6083 struct ElementBox : public Bnd_B3d
6085 const SMDS_MeshElement* _element;
6086 int _refCount; // an ElementBox can be included in several tree branches
6087 ElementBox(const SMDS_MeshElement* elem);
6089 vector< ElementBox* > _elements;
6092 //================================================================================
6094 * \brief ElementBndBoxTree creation
6096 //================================================================================
6098 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6099 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6101 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6102 _elements.reserve( nbElems );
6104 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6105 while ( elemIt->more() )
6106 _elements.push_back( new ElementBox( elemIt->next() ));
6108 if ( _elements.size() > MaxNbElemsInLeaf )
6114 //================================================================================
6118 //================================================================================
6120 ElementBndBoxTree::~ElementBndBoxTree()
6122 for ( int i = 0; i < _elements.size(); ++i )
6123 if ( --_elements[i]->_refCount <= 0 )
6124 delete _elements[i];
6127 //================================================================================
6129 * \brief Return the maximal box
6131 //================================================================================
6133 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6135 Bnd_B3d* box = new Bnd_B3d;
6136 for ( int i = 0; i < _elements.size(); ++i )
6137 box->Add( *_elements[i] );
6141 //================================================================================
6143 * \brief Redistrubute element boxes among children
6145 //================================================================================
6147 void ElementBndBoxTree::buildChildrenData()
6149 for ( int i = 0; i < _elements.size(); ++i )
6151 for (int j = 0; j < 8; j++)
6153 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6155 _elements[i]->_refCount++;
6156 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6159 _elements[i]->_refCount--;
6163 for (int j = 0; j < 8; j++)
6165 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6166 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6167 child->myIsLeaf = true;
6169 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6170 child->_elements.resize( child->_elements.size() ); // compact
6174 //================================================================================
6176 * \brief Return elements which can include the point
6178 //================================================================================
6180 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6181 TIDSortedElemSet& foundElems)
6183 if ( level() && getBox().IsOut( point.XYZ() ))
6188 for ( int i = 0; i < _elements.size(); ++i )
6189 if ( !_elements[i]->IsOut( point.XYZ() ))
6190 foundElems.insert( _elements[i]->_element );
6194 for (int i = 0; i < 8; i++)
6195 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6199 //================================================================================
6201 * \brief Return elements which can be intersected by the line
6203 //================================================================================
6205 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6206 TIDSortedElemSet& foundElems)
6208 if ( level() && getBox().IsOut( line ))
6213 for ( int i = 0; i < _elements.size(); ++i )
6214 if ( !_elements[i]->IsOut( line ))
6215 foundElems.insert( _elements[i]->_element );
6219 for (int i = 0; i < 8; i++)
6220 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6224 //================================================================================
6226 * \brief Construct the element box
6228 //================================================================================
6230 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6234 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6235 while ( nIt->more() )
6236 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6237 Enlarge( NodeRadius );
6242 //=======================================================================
6244 * \brief Implementation of search for the elements by point and
6245 * of classification of point in 2D mesh
6247 //=======================================================================
6249 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6251 SMESHDS_Mesh* _mesh;
6252 ElementBndBoxTree* _ebbTree;
6253 SMESH_NodeSearcherImpl* _nodeSearcher;
6254 SMDSAbs_ElementType _elementType;
6256 bool _outerFacesFound;
6257 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6259 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6260 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6261 ~SMESH_ElementSearcherImpl()
6263 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6264 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6266 virtual int FindElementsByPoint(const gp_Pnt& point,
6267 SMDSAbs_ElementType type,
6268 vector< const SMDS_MeshElement* >& foundElements);
6269 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6271 void GetElementsNearLine( const gp_Ax1& line,
6272 SMDSAbs_ElementType type,
6273 vector< const SMDS_MeshElement* >& foundElems);
6274 double getTolerance();
6275 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6276 const double tolerance, double & param);
6277 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6278 bool isOuterBoundary(const SMDS_MeshElement* face) const
6280 return _outerFaces.empty() || _outerFaces.count(face);
6282 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6284 const SMDS_MeshElement* _face;
6286 bool _coincides; //!< the line lays in face plane
6287 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6288 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6290 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6293 TIDSortedElemSet _faces;
6294 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6295 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6299 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6301 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6302 << ", _coincides="<<i._coincides << ")";
6305 //=======================================================================
6307 * \brief define tolerance for search
6309 //=======================================================================
6311 double SMESH_ElementSearcherImpl::getTolerance()
6313 if ( _tolerance < 0 )
6315 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6318 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6320 double boxSize = _nodeSearcher->getTree()->maxSize();
6321 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6323 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6325 double boxSize = _ebbTree->maxSize();
6326 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6328 if ( _tolerance == 0 )
6330 // define tolerance by size of a most complex element
6331 int complexType = SMDSAbs_Volume;
6332 while ( complexType > SMDSAbs_All &&
6333 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6335 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6338 if ( complexType == int( SMDSAbs_Node ))
6340 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6342 if ( meshInfo.NbNodes() > 2 )
6343 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6347 const SMDS_MeshElement* elem =
6348 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6349 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6350 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6351 while ( nodeIt->more() )
6353 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6354 elemSize = max( dist, elemSize );
6357 _tolerance = 1e-6 * elemSize;
6363 //================================================================================
6365 * \brief Find intersection of the line and an edge of face and return parameter on line
6367 //================================================================================
6369 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6370 const SMDS_MeshElement* face,
6377 GeomAPI_ExtremaCurveCurve anExtCC;
6378 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6380 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6381 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6383 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6384 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6385 anExtCC.Init( lineCurve, edge);
6386 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6388 Quantity_Parameter pl, pe;
6389 anExtCC.LowerDistanceParameters( pl, pe );
6391 if ( ++nbInts == 2 )
6395 if ( nbInts > 0 ) param /= nbInts;
6398 //================================================================================
6400 * \brief Find all faces belonging to the outer boundary of mesh
6402 //================================================================================
6404 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6406 if ( _outerFacesFound ) return;
6408 // Collect all outer faces by passing from one outer face to another via their links
6409 // and BTW find out if there are internal faces at all.
6411 // checked links and links where outer boundary meets internal one
6412 set< SMESH_TLink > visitedLinks, seamLinks;
6414 // links to treat with already visited faces sharing them
6415 list < TFaceLink > startLinks;
6417 // load startLinks with the first outerFace
6418 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6419 _outerFaces.insert( outerFace );
6421 TIDSortedElemSet emptySet;
6422 while ( !startLinks.empty() )
6424 const SMESH_TLink& link = startLinks.front()._link;
6425 TIDSortedElemSet& faces = startLinks.front()._faces;
6427 outerFace = *faces.begin();
6428 // find other faces sharing the link
6429 const SMDS_MeshElement* f;
6430 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6433 // select another outer face among the found
6434 const SMDS_MeshElement* outerFace2 = 0;
6435 if ( faces.size() == 2 )
6437 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6439 else if ( faces.size() > 2 )
6441 seamLinks.insert( link );
6443 // link direction within the outerFace
6444 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6445 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6446 int i1 = outerFace->GetNodeIndex( link.node1() );
6447 int i2 = outerFace->GetNodeIndex( link.node2() );
6448 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6449 if ( rev ) n1n2.Reverse();
6451 gp_XYZ ofNorm, fNorm;
6452 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6454 // direction from the link inside outerFace
6455 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6456 // sort all other faces by angle with the dirInOF
6457 map< double, const SMDS_MeshElement* > angle2Face;
6458 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6459 for ( ; face != faces.end(); ++face )
6461 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6463 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6464 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6465 if ( angle < 0 ) angle += 2*PI;
6466 angle2Face.insert( make_pair( angle, *face ));
6468 if ( !angle2Face.empty() )
6469 outerFace2 = angle2Face.begin()->second;
6472 // store the found outer face and add its links to continue seaching from
6475 _outerFaces.insert( outerFace );
6476 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6477 for ( int i = 0; i < nbNodes; ++i )
6479 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6480 if ( visitedLinks.insert( link2 ).second )
6481 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6484 startLinks.pop_front();
6486 _outerFacesFound = true;
6488 if ( !seamLinks.empty() )
6490 // There are internal boundaries touching the outher one,
6491 // find all faces of internal boundaries in order to find
6492 // faces of boundaries of holes, if any.
6497 _outerFaces.clear();
6501 //=======================================================================
6503 * \brief Find elements of given type where the given point is IN or ON.
6504 * Returns nb of found elements and elements them-selves.
6506 * 'ALL' type means elements of any type excluding nodes and 0D elements
6508 //=======================================================================
6510 int SMESH_ElementSearcherImpl::
6511 FindElementsByPoint(const gp_Pnt& point,
6512 SMDSAbs_ElementType type,
6513 vector< const SMDS_MeshElement* >& foundElements)
6515 foundElements.clear();
6517 double tolerance = getTolerance();
6519 // =================================================================================
6520 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6522 if ( !_nodeSearcher )
6523 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6525 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6526 if ( !closeNode ) return foundElements.size();
6528 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6529 return foundElements.size(); // to far from any node
6531 if ( type == SMDSAbs_Node )
6533 foundElements.push_back( closeNode );
6537 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6538 while ( elemIt->more() )
6539 foundElements.push_back( elemIt->next() );
6542 // =================================================================================
6543 else // elements more complex than 0D
6545 if ( !_ebbTree || _elementType != type )
6547 if ( _ebbTree ) delete _ebbTree;
6548 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6550 TIDSortedElemSet suspectElems;
6551 _ebbTree->getElementsNearPoint( point, suspectElems );
6552 TIDSortedElemSet::iterator elem = suspectElems.begin();
6553 for ( ; elem != suspectElems.end(); ++elem )
6554 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6555 foundElements.push_back( *elem );
6557 return foundElements.size();
6560 //================================================================================
6562 * \brief Classify the given point in the closed 2D mesh
6564 //================================================================================
6566 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6568 double tolerance = getTolerance();
6569 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6571 if ( _ebbTree ) delete _ebbTree;
6572 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6574 // Algo: analyse transition of a line starting at the point through mesh boundary;
6575 // try three lines parallel to axis of the coordinate system and perform rough
6576 // analysis. If solution is not clear perform thorough analysis.
6578 const int nbAxes = 3;
6579 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6580 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6581 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6582 multimap< int, int > nbInt2Axis; // to find the simplest case
6583 for ( int axis = 0; axis < nbAxes; ++axis )
6585 gp_Ax1 lineAxis( point, axisDir[axis]);
6586 gp_Lin line ( lineAxis );
6588 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6589 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6591 // Intersect faces with the line
6593 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6594 TIDSortedElemSet::iterator face = suspectFaces.begin();
6595 for ( ; face != suspectFaces.end(); ++face )
6599 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6600 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6602 // perform intersection
6603 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6604 if ( !intersection.IsDone() )
6606 if ( intersection.IsInQuadric() )
6608 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6610 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6612 gp_Pnt intersectionPoint = intersection.Point(1);
6613 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6614 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6617 // Analyse intersections roughly
6619 int nbInter = u2inters.size();
6623 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6624 if ( nbInter == 1 ) // not closed mesh
6625 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6627 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6630 if ( (f<0) == (l<0) )
6633 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6634 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6635 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6638 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6640 if ( _outerFacesFound ) break; // pass to thorough analysis
6642 } // three attempts - loop on CS axes
6644 // Analyse intersections thoroughly.
6645 // We make two loops maximum, on the first one we only exclude touching intersections,
6646 // on the second, if situation is still unclear, we gather and use information on
6647 // position of faces (internal or outer). If faces position is already gathered,
6648 // we make the second loop right away.
6650 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6652 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6653 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6655 int axis = nb_axis->second;
6656 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6658 gp_Ax1 lineAxis( point, axisDir[axis]);
6659 gp_Lin line ( lineAxis );
6661 // add tangent intersections to u2inters
6663 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6664 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6665 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6666 u2inters.insert(make_pair( param, *tgtInt ));
6667 tangentInters[ axis ].clear();
6669 // Count intersections before and after the point excluding touching ones.
6670 // If hasPositionInfo we count intersections of outer boundary only
6672 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6673 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6674 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6675 bool ok = ! u_int1->second._coincides;
6676 while ( ok && u_int1 != u2inters.end() )
6678 double u = u_int1->first;
6679 bool touchingInt = false;
6680 if ( ++u_int2 != u2inters.end() )
6682 // skip intersections at the same point (if the line passes through edge or node)
6684 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6690 // skip tangent intersections
6692 const SMDS_MeshElement* prevFace = u_int1->second._face;
6693 while ( ok && u_int2->second._coincides )
6695 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6701 ok = ( u_int2 != u2inters.end() );
6706 // skip intersections at the same point after tangent intersections
6709 double u2 = u_int2->first;
6711 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6717 // decide if we skipped a touching intersection
6718 if ( nbSamePnt + nbTgt > 0 )
6720 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6721 map< double, TInters >::iterator u_int = u_int1;
6722 for ( ; u_int != u_int2; ++u_int )
6724 if ( u_int->second._coincides ) continue;
6725 double dot = u_int->second._faceNorm * line.Direction();
6726 if ( dot > maxDot ) maxDot = dot;
6727 if ( dot < minDot ) minDot = dot;
6729 touchingInt = ( minDot*maxDot < 0 );
6734 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6745 u_int1 = u_int2; // to next intersection
6747 } // loop on intersections with one line
6751 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6754 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6757 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6758 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6760 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6763 if ( (f<0) == (l<0) )
6766 if ( hasPositionInfo )
6767 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6769 } // loop on intersections of the tree lines - thorough analysis
6771 if ( !hasPositionInfo )
6773 // gather info on faces position - is face in the outer boundary or not
6774 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6775 findOuterBoundary( u2inters.begin()->second._face );
6778 } // two attempts - with and w/o faces position info in the mesh
6780 return TopAbs_UNKNOWN;
6783 //=======================================================================
6785 * \brief Return elements possibly intersecting the line
6787 //=======================================================================
6789 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
6790 SMDSAbs_ElementType type,
6791 vector< const SMDS_MeshElement* >& foundElems)
6793 if ( !_ebbTree || _elementType != type )
6795 if ( _ebbTree ) delete _ebbTree;
6796 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6798 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6799 _ebbTree->getElementsNearLine( line, suspectFaces );
6800 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6803 //=======================================================================
6805 * \brief Return SMESH_ElementSearcher
6807 //=======================================================================
6809 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6811 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6814 //=======================================================================
6816 * \brief Return true if the point is IN or ON of the element
6818 //=======================================================================
6820 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6822 if ( element->GetType() == SMDSAbs_Volume)
6824 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6827 // get ordered nodes
6829 vector< gp_XYZ > xyz;
6831 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6832 if ( element->IsQuadratic() )
6833 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6834 nodeIt = f->interlacedNodesElemIterator();
6835 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6836 nodeIt = e->interlacedNodesElemIterator();
6838 while ( nodeIt->more() )
6839 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6841 int i, nbNodes = element->NbNodes();
6843 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6845 // compute face normal
6846 gp_Vec faceNorm(0,0,0);
6847 xyz.push_back( xyz.front() );
6848 for ( i = 0; i < nbNodes; ++i )
6850 gp_Vec edge1( xyz[i+1], xyz[i]);
6851 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6852 faceNorm += edge1 ^ edge2;
6854 double normSize = faceNorm.Magnitude();
6855 if ( normSize <= tol )
6857 // degenerated face: point is out if it is out of all face edges
6858 for ( i = 0; i < nbNodes; ++i )
6860 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6861 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6862 SMDS_MeshEdge edge( &n1, &n2 );
6863 if ( !isOut( &edge, point, tol ))
6868 faceNorm /= normSize;
6870 // check if the point lays on face plane
6871 gp_Vec n2p( xyz[0], point );
6872 if ( fabs( n2p * faceNorm ) > tol )
6873 return true; // not on face plane
6875 // check if point is out of face boundary:
6876 // define it by closest transition of a ray point->infinity through face boundary
6877 // on the face plane.
6878 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6879 // to find intersections of the ray with the boundary.
6881 gp_Vec plnNorm = ray ^ faceNorm;
6882 normSize = plnNorm.Magnitude();
6883 if ( normSize <= tol ) return false; // point coincides with the first node
6884 plnNorm /= normSize;
6885 // for each node of the face, compute its signed distance to the plane
6886 vector<double> dist( nbNodes + 1);
6887 for ( i = 0; i < nbNodes; ++i )
6889 gp_Vec n2p( xyz[i], point );
6890 dist[i] = n2p * plnNorm;
6892 dist.back() = dist.front();
6893 // find the closest intersection
6895 double rClosest, distClosest = 1e100;;
6897 for ( i = 0; i < nbNodes; ++i )
6900 if ( fabs( dist[i]) < tol )
6902 else if ( fabs( dist[i+1]) < tol )
6904 else if ( dist[i] * dist[i+1] < 0 )
6905 r = dist[i] / ( dist[i] - dist[i+1] );
6907 continue; // no intersection
6908 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6909 gp_Vec p2int ( point, pInt);
6910 if ( p2int * ray > -tol ) // right half-space
6912 double intDist = p2int.SquareMagnitude();
6913 if ( intDist < distClosest )
6918 distClosest = intDist;
6923 return true; // no intesections - out
6925 // analyse transition
6926 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6927 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6928 gp_Vec p2int ( point, pClosest );
6929 bool out = (edgeNorm * p2int) < -tol;
6930 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6933 // ray pass through a face node; analyze transition through an adjacent edge
6934 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6935 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6936 gp_Vec edgeAdjacent( p1, p2 );
6937 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6938 bool out2 = (edgeNorm2 * p2int) < -tol;
6940 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6941 return covexCorner ? (out || out2) : (out && out2);
6943 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6945 // point is out of edge if it is NOT ON any straight part of edge
6946 // (we consider quadratic edge as being composed of two straight parts)
6947 for ( i = 1; i < nbNodes; ++i )
6949 gp_Vec edge( xyz[i-1], xyz[i]);
6950 gp_Vec n1p ( xyz[i-1], point);
6951 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6954 gp_Vec n2p( xyz[i], point );
6955 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6957 return false; // point is ON this part
6961 // Node or 0D element -------------------------------------------------------------------------
6963 gp_Vec n2p ( xyz[0], point );
6964 return n2p.Magnitude() <= tol;
6969 //=======================================================================
6970 //function : SimplifyFace
6972 //=======================================================================
6973 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6974 vector<const SMDS_MeshNode *>& poly_nodes,
6975 vector<int>& quantities) const
6977 int nbNodes = faceNodes.size();
6982 set<const SMDS_MeshNode*> nodeSet;
6984 // get simple seq of nodes
6985 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6986 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6987 int iSimple = 0, nbUnique = 0;
6989 simpleNodes[iSimple++] = faceNodes[0];
6991 for (int iCur = 1; iCur < nbNodes; iCur++) {
6992 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6993 simpleNodes[iSimple++] = faceNodes[iCur];
6994 if (nodeSet.insert( faceNodes[iCur] ).second)
6998 int nbSimple = iSimple;
6999 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7009 bool foundLoop = (nbSimple > nbUnique);
7012 set<const SMDS_MeshNode*> loopSet;
7013 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7014 const SMDS_MeshNode* n = simpleNodes[iSimple];
7015 if (!loopSet.insert( n ).second) {
7019 int iC = 0, curLast = iSimple;
7020 for (; iC < curLast; iC++) {
7021 if (simpleNodes[iC] == n) break;
7023 int loopLen = curLast - iC;
7025 // create sub-element
7027 quantities.push_back(loopLen);
7028 for (; iC < curLast; iC++) {
7029 poly_nodes.push_back(simpleNodes[iC]);
7032 // shift the rest nodes (place from the first loop position)
7033 for (iC = curLast + 1; iC < nbSimple; iC++) {
7034 simpleNodes[iC - loopLen] = simpleNodes[iC];
7036 nbSimple -= loopLen;
7039 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7040 } // while (foundLoop)
7044 quantities.push_back(iSimple);
7045 for (int i = 0; i < iSimple; i++)
7046 poly_nodes.push_back(simpleNodes[i]);
7052 //=======================================================================
7053 //function : MergeNodes
7054 //purpose : In each group, the cdr of nodes are substituted by the first one
7056 //=======================================================================
7058 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7060 myLastCreatedElems.Clear();
7061 myLastCreatedNodes.Clear();
7063 SMESHDS_Mesh* aMesh = GetMeshDS();
7065 TNodeNodeMap nodeNodeMap; // node to replace - new node
7066 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7067 list< int > rmElemIds, rmNodeIds;
7069 // Fill nodeNodeMap and elems
7071 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7072 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7073 list<const SMDS_MeshNode*>& nodes = *grIt;
7074 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7075 const SMDS_MeshNode* nToKeep = *nIt;
7076 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7077 const SMDS_MeshNode* nToRemove = *nIt;
7078 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7079 if ( nToRemove != nToKeep ) {
7080 rmNodeIds.push_back( nToRemove->GetID() );
7081 AddToSameGroups( nToKeep, nToRemove, aMesh );
7084 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7085 while ( invElemIt->more() ) {
7086 const SMDS_MeshElement* elem = invElemIt->next();
7091 // Change element nodes or remove an element
7093 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7094 for ( ; eIt != elems.end(); eIt++ ) {
7095 const SMDS_MeshElement* elem = *eIt;
7096 int nbNodes = elem->NbNodes();
7097 int aShapeId = FindShape( elem );
7099 set<const SMDS_MeshNode*> nodeSet;
7100 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7101 int iUnique = 0, iCur = 0, nbRepl = 0;
7102 vector<int> iRepl( nbNodes );
7104 // get new seq of nodes
7105 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7106 while ( itN->more() ) {
7107 const SMDS_MeshNode* n =
7108 static_cast<const SMDS_MeshNode*>( itN->next() );
7110 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7111 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7113 // BUG 0020185: begin
7115 bool stopRecur = false;
7116 set<const SMDS_MeshNode*> nodesRecur;
7117 nodesRecur.insert(n);
7118 while (!stopRecur) {
7119 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7120 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7121 n = (*nnIt_i).second;
7122 if (!nodesRecur.insert(n).second) {
7123 // error: recursive dependancy
7132 iRepl[ nbRepl++ ] = iCur;
7134 curNodes[ iCur ] = n;
7135 bool isUnique = nodeSet.insert( n ).second;
7137 uniqueNodes[ iUnique++ ] = n;
7141 // Analyse element topology after replacement
7144 int nbUniqueNodes = nodeSet.size();
7145 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7146 // Polygons and Polyhedral volumes
7147 if (elem->IsPoly()) {
7149 if (elem->GetType() == SMDSAbs_Face) {
7151 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7153 for (; inode < nbNodes; inode++) {
7154 face_nodes[inode] = curNodes[inode];
7157 vector<const SMDS_MeshNode *> polygons_nodes;
7158 vector<int> quantities;
7159 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7163 for (int iface = 0; iface < nbNew - 1; iface++) {
7164 int nbNodes = quantities[iface];
7165 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7166 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7167 poly_nodes[ii] = polygons_nodes[inode];
7169 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7170 myLastCreatedElems.Append(newElem);
7172 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7174 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7177 rmElemIds.push_back(elem->GetID());
7181 else if (elem->GetType() == SMDSAbs_Volume) {
7182 // Polyhedral volume
7183 if (nbUniqueNodes < 4) {
7184 rmElemIds.push_back(elem->GetID());
7187 // each face has to be analized in order to check volume validity
7188 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7189 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7191 int nbFaces = aPolyedre->NbFaces();
7193 vector<const SMDS_MeshNode *> poly_nodes;
7194 vector<int> quantities;
7196 for (int iface = 1; iface <= nbFaces; iface++) {
7197 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7198 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7200 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7201 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7202 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7203 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7204 faceNode = (*nnIt).second;
7206 faceNodes[inode - 1] = faceNode;
7209 SimplifyFace(faceNodes, poly_nodes, quantities);
7212 if (quantities.size() > 3) {
7213 // to be done: remove coincident faces
7216 if (quantities.size() > 3)
7217 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7219 rmElemIds.push_back(elem->GetID());
7223 rmElemIds.push_back(elem->GetID());
7234 switch ( nbNodes ) {
7235 case 2: ///////////////////////////////////// EDGE
7236 isOk = false; break;
7237 case 3: ///////////////////////////////////// TRIANGLE
7238 isOk = false; break;
7240 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7242 else { //////////////////////////////////// QUADRANGLE
7243 if ( nbUniqueNodes < 3 )
7245 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7246 isOk = false; // opposite nodes stick
7249 case 6: ///////////////////////////////////// PENTAHEDRON
7250 if ( nbUniqueNodes == 4 ) {
7251 // ---------------------------------> tetrahedron
7253 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7254 // all top nodes stick: reverse a bottom
7255 uniqueNodes[ 0 ] = curNodes [ 1 ];
7256 uniqueNodes[ 1 ] = curNodes [ 0 ];
7258 else if (nbRepl == 3 &&
7259 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7260 // all bottom nodes stick: set a top before
7261 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7262 uniqueNodes[ 0 ] = curNodes [ 3 ];
7263 uniqueNodes[ 1 ] = curNodes [ 4 ];
7264 uniqueNodes[ 2 ] = curNodes [ 5 ];
7266 else if (nbRepl == 4 &&
7267 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7268 // a lateral face turns into a line: reverse a bottom
7269 uniqueNodes[ 0 ] = curNodes [ 1 ];
7270 uniqueNodes[ 1 ] = curNodes [ 0 ];
7275 else if ( nbUniqueNodes == 5 ) {
7276 // PENTAHEDRON --------------------> 2 tetrahedrons
7277 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7278 // a bottom node sticks with a linked top one
7280 SMDS_MeshElement* newElem =
7281 aMesh->AddVolume(curNodes[ 3 ],
7284 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7285 myLastCreatedElems.Append(newElem);
7287 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7288 // 2. : reverse a bottom
7289 uniqueNodes[ 0 ] = curNodes [ 1 ];
7290 uniqueNodes[ 1 ] = curNodes [ 0 ];
7300 if(elem->IsQuadratic()) { // Quadratic quadrangle
7313 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7314 uniqueNodes[0] = curNodes[0];
7315 uniqueNodes[1] = curNodes[2];
7316 uniqueNodes[2] = curNodes[3];
7317 uniqueNodes[3] = curNodes[5];
7318 uniqueNodes[4] = curNodes[6];
7319 uniqueNodes[5] = curNodes[7];
7322 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7323 uniqueNodes[0] = curNodes[0];
7324 uniqueNodes[1] = curNodes[1];
7325 uniqueNodes[2] = curNodes[2];
7326 uniqueNodes[3] = curNodes[4];
7327 uniqueNodes[4] = curNodes[5];
7328 uniqueNodes[5] = curNodes[6];
7331 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7332 uniqueNodes[0] = curNodes[1];
7333 uniqueNodes[1] = curNodes[2];
7334 uniqueNodes[2] = curNodes[3];
7335 uniqueNodes[3] = curNodes[5];
7336 uniqueNodes[4] = curNodes[6];
7337 uniqueNodes[5] = curNodes[0];
7340 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7341 uniqueNodes[0] = curNodes[0];
7342 uniqueNodes[1] = curNodes[1];
7343 uniqueNodes[2] = curNodes[3];
7344 uniqueNodes[3] = curNodes[4];
7345 uniqueNodes[4] = curNodes[6];
7346 uniqueNodes[5] = curNodes[7];
7349 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7350 uniqueNodes[0] = curNodes[0];
7351 uniqueNodes[1] = curNodes[2];
7352 uniqueNodes[2] = curNodes[3];
7353 uniqueNodes[3] = curNodes[1];
7354 uniqueNodes[4] = curNodes[6];
7355 uniqueNodes[5] = curNodes[7];
7358 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7359 uniqueNodes[0] = curNodes[0];
7360 uniqueNodes[1] = curNodes[1];
7361 uniqueNodes[2] = curNodes[2];
7362 uniqueNodes[3] = curNodes[4];
7363 uniqueNodes[4] = curNodes[5];
7364 uniqueNodes[5] = curNodes[7];
7367 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7368 uniqueNodes[0] = curNodes[0];
7369 uniqueNodes[1] = curNodes[1];
7370 uniqueNodes[2] = curNodes[3];
7371 uniqueNodes[3] = curNodes[4];
7372 uniqueNodes[4] = curNodes[2];
7373 uniqueNodes[5] = curNodes[7];
7376 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7377 uniqueNodes[0] = curNodes[0];
7378 uniqueNodes[1] = curNodes[1];
7379 uniqueNodes[2] = curNodes[2];
7380 uniqueNodes[3] = curNodes[4];
7381 uniqueNodes[4] = curNodes[5];
7382 uniqueNodes[5] = curNodes[3];
7388 //////////////////////////////////// HEXAHEDRON
7390 SMDS_VolumeTool hexa (elem);
7391 hexa.SetExternalNormal();
7392 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7393 //////////////////////// ---> tetrahedron
7394 for ( int iFace = 0; iFace < 6; iFace++ ) {
7395 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7396 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7397 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7398 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7399 // one face turns into a point ...
7400 int iOppFace = hexa.GetOppFaceIndex( iFace );
7401 ind = hexa.GetFaceNodesIndices( iOppFace );
7403 iUnique = 2; // reverse a tetrahedron bottom
7404 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7405 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7407 else if ( iUnique >= 0 )
7408 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7410 if ( nbStick == 1 ) {
7411 // ... and the opposite one - into a triangle.
7413 ind = hexa.GetFaceNodesIndices( iFace );
7414 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7421 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7422 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7423 for ( int iFace = 0; iFace < 6; iFace++ ) {
7424 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7425 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7426 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7427 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7428 // one face turns into a point ...
7429 int iOppFace = hexa.GetOppFaceIndex( iFace );
7430 ind = hexa.GetFaceNodesIndices( iOppFace );
7432 iUnique = 2; // reverse a tetrahedron 1 bottom
7433 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7434 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7436 else if ( iUnique >= 0 )
7437 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7439 if ( nbStick == 0 ) {
7440 // ... and the opposite one is a quadrangle
7442 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7443 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7446 SMDS_MeshElement* newElem =
7447 aMesh->AddVolume(curNodes[ind[ 0 ]],
7450 curNodes[indTop[ 0 ]]);
7451 myLastCreatedElems.Append(newElem);
7453 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7460 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7461 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7462 // find indices of quad and tri faces
7463 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7464 for ( iFace = 0; iFace < 6; iFace++ ) {
7465 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7467 for ( iCur = 0; iCur < 4; iCur++ )
7468 nodeSet.insert( curNodes[ind[ iCur ]] );
7469 nbUniqueNodes = nodeSet.size();
7470 if ( nbUniqueNodes == 3 )
7471 iTriFace[ nbTri++ ] = iFace;
7472 else if ( nbUniqueNodes == 4 )
7473 iQuadFace[ nbQuad++ ] = iFace;
7475 if (nbQuad == 2 && nbTri == 4 &&
7476 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7477 // 2 opposite quadrangles stuck with a diagonal;
7478 // sample groups of merged indices: (0-4)(2-6)
7479 // --------------------------------------------> 2 tetrahedrons
7480 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7481 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7482 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7483 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7484 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7485 // stuck with 0-2 diagonal
7493 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7494 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7495 // stuck with 1-3 diagonal
7507 uniqueNodes[ 0 ] = curNodes [ i0 ];
7508 uniqueNodes[ 1 ] = curNodes [ i1d ];
7509 uniqueNodes[ 2 ] = curNodes [ i3d ];
7510 uniqueNodes[ 3 ] = curNodes [ i0t ];
7513 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7517 myLastCreatedElems.Append(newElem);
7519 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7522 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7523 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7524 // --------------------------------------------> prism
7525 // find 2 opposite triangles
7527 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7528 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7529 // find indices of kept and replaced nodes
7530 // and fill unique nodes of 2 opposite triangles
7531 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7532 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7533 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7534 // fill unique nodes
7537 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7538 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7539 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7541 // iCur of a linked node of the opposite face (make normals co-directed):
7542 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7543 // check that correspondent corners of triangles are linked
7544 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7547 uniqueNodes[ iUnique ] = n;
7548 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7557 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7563 } // switch ( nbNodes )
7565 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7568 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7569 // Change nodes of polyedre
7570 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7571 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7573 int nbFaces = aPolyedre->NbFaces();
7575 vector<const SMDS_MeshNode *> poly_nodes;
7576 vector<int> quantities (nbFaces);
7578 for (int iface = 1; iface <= nbFaces; iface++) {
7579 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7580 quantities[iface - 1] = nbFaceNodes;
7582 for (inode = 1; inode <= nbFaceNodes; inode++) {
7583 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7585 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7586 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7587 curNode = (*nnIt).second;
7589 poly_nodes.push_back(curNode);
7592 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7596 // Change regular element or polygon
7597 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7601 // Remove invalid regular element or invalid polygon
7602 rmElemIds.push_back( elem->GetID() );
7605 } // loop on elements
7607 // Remove equal nodes and bad elements
7609 Remove( rmNodeIds, true );
7610 Remove( rmElemIds, false );
7615 // ========================================================
7616 // class : SortableElement
7617 // purpose : allow sorting elements basing on their nodes
7618 // ========================================================
7619 class SortableElement : public set <const SMDS_MeshElement*>
7623 SortableElement( const SMDS_MeshElement* theElem )
7626 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7627 while ( nodeIt->more() )
7628 this->insert( nodeIt->next() );
7631 const SMDS_MeshElement* Get() const
7634 void Set(const SMDS_MeshElement* e) const
7639 mutable const SMDS_MeshElement* myElem;
7642 //=======================================================================
7643 //function : FindEqualElements
7644 //purpose : Return list of group of elements built on the same nodes.
7645 // Search among theElements or in the whole mesh if theElements is empty
7646 //=======================================================================
7647 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7648 TListOfListOfElementsID & theGroupsOfElementsID)
7650 myLastCreatedElems.Clear();
7651 myLastCreatedNodes.Clear();
7653 typedef set<const SMDS_MeshElement*> TElemsSet;
7654 typedef map< SortableElement, int > TMapOfNodeSet;
7655 typedef list<int> TGroupOfElems;
7658 if ( theElements.empty() )
7659 { // get all elements in the mesh
7660 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7661 while ( eIt->more() )
7662 elems.insert( elems.end(), eIt->next());
7665 elems = theElements;
7667 vector< TGroupOfElems > arrayOfGroups;
7668 TGroupOfElems groupOfElems;
7669 TMapOfNodeSet mapOfNodeSet;
7671 TElemsSet::iterator elemIt = elems.begin();
7672 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7673 const SMDS_MeshElement* curElem = *elemIt;
7674 SortableElement SE(curElem);
7677 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7678 if( !(pp.second) ) {
7679 TMapOfNodeSet::iterator& itSE = pp.first;
7680 ind = (*itSE).second;
7681 arrayOfGroups[ind].push_back(curElem->GetID());
7684 groupOfElems.clear();
7685 groupOfElems.push_back(curElem->GetID());
7686 arrayOfGroups.push_back(groupOfElems);
7691 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7692 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7693 groupOfElems = *groupIt;
7694 if ( groupOfElems.size() > 1 ) {
7695 groupOfElems.sort();
7696 theGroupsOfElementsID.push_back(groupOfElems);
7701 //=======================================================================
7702 //function : MergeElements
7703 //purpose : In each given group, substitute all elements by the first one.
7704 //=======================================================================
7706 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7708 myLastCreatedElems.Clear();
7709 myLastCreatedNodes.Clear();
7711 typedef list<int> TListOfIDs;
7712 TListOfIDs rmElemIds; // IDs of elems to remove
7714 SMESHDS_Mesh* aMesh = GetMeshDS();
7716 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7717 while ( groupsIt != theGroupsOfElementsID.end() ) {
7718 TListOfIDs& aGroupOfElemID = *groupsIt;
7719 aGroupOfElemID.sort();
7720 int elemIDToKeep = aGroupOfElemID.front();
7721 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7722 aGroupOfElemID.pop_front();
7723 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7724 while ( idIt != aGroupOfElemID.end() ) {
7725 int elemIDToRemove = *idIt;
7726 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7727 // add the kept element in groups of removed one (PAL15188)
7728 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7729 rmElemIds.push_back( elemIDToRemove );
7735 Remove( rmElemIds, false );
7738 //=======================================================================
7739 //function : MergeEqualElements
7740 //purpose : Remove all but one of elements built on the same nodes.
7741 //=======================================================================
7743 void SMESH_MeshEditor::MergeEqualElements()
7745 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7746 to merge equal elements in the whole mesh */
7747 TListOfListOfElementsID aGroupsOfElementsID;
7748 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7749 MergeElements(aGroupsOfElementsID);
7752 //=======================================================================
7753 //function : FindFaceInSet
7754 //purpose : Return a face having linked nodes n1 and n2 and which is
7755 // - not in avoidSet,
7756 // - in elemSet provided that !elemSet.empty()
7757 // i1 and i2 optionally returns indices of n1 and n2
7758 //=======================================================================
7760 const SMDS_MeshElement*
7761 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7762 const SMDS_MeshNode* n2,
7763 const TIDSortedElemSet& elemSet,
7764 const TIDSortedElemSet& avoidSet,
7770 const SMDS_MeshElement* face = 0;
7772 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7773 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7775 const SMDS_MeshElement* elem = invElemIt->next();
7776 if (avoidSet.count( elem ))
7778 if ( !elemSet.empty() && !elemSet.count( elem ))
7781 i1 = elem->GetNodeIndex( n1 );
7782 // find a n2 linked to n1
7783 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7784 for ( int di = -1; di < 2 && !face; di += 2 )
7786 i2 = (i1+di+nbN) % nbN;
7787 if ( elem->GetNode( i2 ) == n2 )
7790 if ( !face && elem->IsQuadratic())
7792 // analysis for quadratic elements using all nodes
7793 const SMDS_QuadraticFaceOfNodes* F =
7794 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7795 // use special nodes iterator
7796 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7797 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7798 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7800 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7801 if ( n1 == prevN && n2 == n )
7805 else if ( n2 == prevN && n1 == n )
7807 face = elem; swap( i1, i2 );
7813 if ( n1ind ) *n1ind = i1;
7814 if ( n2ind ) *n2ind = i2;
7818 //=======================================================================
7819 //function : findAdjacentFace
7821 //=======================================================================
7823 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7824 const SMDS_MeshNode* n2,
7825 const SMDS_MeshElement* elem)
7827 TIDSortedElemSet elemSet, avoidSet;
7829 avoidSet.insert ( elem );
7830 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7833 //=======================================================================
7834 //function : FindFreeBorder
7836 //=======================================================================
7838 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7840 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7841 const SMDS_MeshNode* theSecondNode,
7842 const SMDS_MeshNode* theLastNode,
7843 list< const SMDS_MeshNode* > & theNodes,
7844 list< const SMDS_MeshElement* >& theFaces)
7846 if ( !theFirstNode || !theSecondNode )
7848 // find border face between theFirstNode and theSecondNode
7849 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7853 theFaces.push_back( curElem );
7854 theNodes.push_back( theFirstNode );
7855 theNodes.push_back( theSecondNode );
7857 //vector<const SMDS_MeshNode*> nodes;
7858 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7859 TIDSortedElemSet foundElems;
7860 bool needTheLast = ( theLastNode != 0 );
7862 while ( nStart != theLastNode ) {
7863 if ( nStart == theFirstNode )
7864 return !needTheLast;
7866 // find all free border faces sharing form nStart
7868 list< const SMDS_MeshElement* > curElemList;
7869 list< const SMDS_MeshNode* > nStartList;
7870 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7871 while ( invElemIt->more() ) {
7872 const SMDS_MeshElement* e = invElemIt->next();
7873 if ( e == curElem || foundElems.insert( e ).second ) {
7875 int iNode = 0, nbNodes = e->NbNodes();
7876 //const SMDS_MeshNode* nodes[nbNodes+1];
7877 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7879 if(e->IsQuadratic()) {
7880 const SMDS_QuadraticFaceOfNodes* F =
7881 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7882 // use special nodes iterator
7883 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7884 while( anIter->more() ) {
7885 nodes[ iNode++ ] = anIter->next();
7889 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7890 while ( nIt->more() )
7891 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7893 nodes[ iNode ] = nodes[ 0 ];
7895 for ( iNode = 0; iNode < nbNodes; iNode++ )
7896 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7897 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7898 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7900 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7901 curElemList.push_back( e );
7905 // analyse the found
7907 int nbNewBorders = curElemList.size();
7908 if ( nbNewBorders == 0 ) {
7909 // no free border furthermore
7910 return !needTheLast;
7912 else if ( nbNewBorders == 1 ) {
7913 // one more element found
7915 nStart = nStartList.front();
7916 curElem = curElemList.front();
7917 theFaces.push_back( curElem );
7918 theNodes.push_back( nStart );
7921 // several continuations found
7922 list< const SMDS_MeshElement* >::iterator curElemIt;
7923 list< const SMDS_MeshNode* >::iterator nStartIt;
7924 // check if one of them reached the last node
7925 if ( needTheLast ) {
7926 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7927 curElemIt!= curElemList.end();
7928 curElemIt++, nStartIt++ )
7929 if ( *nStartIt == theLastNode ) {
7930 theFaces.push_back( *curElemIt );
7931 theNodes.push_back( *nStartIt );
7935 // find the best free border by the continuations
7936 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7937 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7938 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7939 curElemIt!= curElemList.end();
7940 curElemIt++, nStartIt++ )
7942 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7943 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7944 // find one more free border
7945 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7949 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7950 // choice: clear a worse one
7951 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7952 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7953 contNodes[ iWorse ].clear();
7954 contFaces[ iWorse ].clear();
7957 if ( contNodes[0].empty() && contNodes[1].empty() )
7960 // append the best free border
7961 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7962 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7963 theNodes.pop_back(); // remove nIgnore
7964 theNodes.pop_back(); // remove nStart
7965 theFaces.pop_back(); // remove curElem
7966 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7967 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7968 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7969 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7972 } // several continuations found
7973 } // while ( nStart != theLastNode )
7978 //=======================================================================
7979 //function : CheckFreeBorderNodes
7980 //purpose : Return true if the tree nodes are on a free border
7981 //=======================================================================
7983 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7984 const SMDS_MeshNode* theNode2,
7985 const SMDS_MeshNode* theNode3)
7987 list< const SMDS_MeshNode* > nodes;
7988 list< const SMDS_MeshElement* > faces;
7989 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7992 //=======================================================================
7993 //function : SewFreeBorder
7995 //=======================================================================
7997 SMESH_MeshEditor::Sew_Error
7998 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7999 const SMDS_MeshNode* theBordSecondNode,
8000 const SMDS_MeshNode* theBordLastNode,
8001 const SMDS_MeshNode* theSideFirstNode,
8002 const SMDS_MeshNode* theSideSecondNode,
8003 const SMDS_MeshNode* theSideThirdNode,
8004 const bool theSideIsFreeBorder,
8005 const bool toCreatePolygons,
8006 const bool toCreatePolyedrs)
8008 myLastCreatedElems.Clear();
8009 myLastCreatedNodes.Clear();
8011 MESSAGE("::SewFreeBorder()");
8012 Sew_Error aResult = SEW_OK;
8014 // ====================================
8015 // find side nodes and elements
8016 // ====================================
8018 list< const SMDS_MeshNode* > nSide[ 2 ];
8019 list< const SMDS_MeshElement* > eSide[ 2 ];
8020 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8021 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8025 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8026 nSide[0], eSide[0])) {
8027 MESSAGE(" Free Border 1 not found " );
8028 aResult = SEW_BORDER1_NOT_FOUND;
8030 if (theSideIsFreeBorder) {
8033 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8034 nSide[1], eSide[1])) {
8035 MESSAGE(" Free Border 2 not found " );
8036 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8039 if ( aResult != SEW_OK )
8042 if (!theSideIsFreeBorder) {
8046 // -------------------------------------------------------------------------
8048 // 1. If nodes to merge are not coincident, move nodes of the free border
8049 // from the coord sys defined by the direction from the first to last
8050 // nodes of the border to the correspondent sys of the side 2
8051 // 2. On the side 2, find the links most co-directed with the correspondent
8052 // links of the free border
8053 // -------------------------------------------------------------------------
8055 // 1. Since sewing may brake if there are volumes to split on the side 2,
8056 // we wont move nodes but just compute new coordinates for them
8057 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8058 TNodeXYZMap nBordXYZ;
8059 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8060 list< const SMDS_MeshNode* >::iterator nBordIt;
8062 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8063 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8064 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8065 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8066 double tol2 = 1.e-8;
8067 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8068 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8069 // Need node movement.
8071 // find X and Z axes to create trsf
8072 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8074 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8076 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8079 gp_Ax3 toBordAx( Pb1, Zb, X );
8080 gp_Ax3 fromSideAx( Ps1, Zs, X );
8081 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8083 gp_Trsf toBordSys, fromSide2Sys;
8084 toBordSys.SetTransformation( toBordAx );
8085 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8086 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8089 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8090 const SMDS_MeshNode* n = *nBordIt;
8091 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8092 toBordSys.Transforms( xyz );
8093 fromSide2Sys.Transforms( xyz );
8094 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8098 // just insert nodes XYZ in the nBordXYZ map
8099 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8100 const SMDS_MeshNode* n = *nBordIt;
8101 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8105 // 2. On the side 2, find the links most co-directed with the correspondent
8106 // links of the free border
8108 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8109 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8110 sideNodes.push_back( theSideFirstNode );
8112 bool hasVolumes = false;
8113 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8114 set<long> foundSideLinkIDs, checkedLinkIDs;
8115 SMDS_VolumeTool volume;
8116 //const SMDS_MeshNode* faceNodes[ 4 ];
8118 const SMDS_MeshNode* sideNode;
8119 const SMDS_MeshElement* sideElem;
8120 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8121 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8122 nBordIt = bordNodes.begin();
8124 // border node position and border link direction to compare with
8125 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8126 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8127 // choose next side node by link direction or by closeness to
8128 // the current border node:
8129 bool searchByDir = ( *nBordIt != theBordLastNode );
8131 // find the next node on the Side 2
8133 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8135 checkedLinkIDs.clear();
8136 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8138 // loop on inverse elements of current node (prevSideNode) on the Side 2
8139 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8140 while ( invElemIt->more() )
8142 const SMDS_MeshElement* elem = invElemIt->next();
8143 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8144 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8145 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8146 bool isVolume = volume.Set( elem );
8147 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8148 if ( isVolume ) // --volume
8150 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8151 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8152 if(elem->IsQuadratic()) {
8153 const SMDS_QuadraticFaceOfNodes* F =
8154 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8155 // use special nodes iterator
8156 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8157 while( anIter->more() ) {
8158 nodes[ iNode ] = anIter->next();
8159 if ( nodes[ iNode++ ] == prevSideNode )
8160 iPrevNode = iNode - 1;
8164 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8165 while ( nIt->more() ) {
8166 nodes[ iNode ] = cast2Node( nIt->next() );
8167 if ( nodes[ iNode++ ] == prevSideNode )
8168 iPrevNode = iNode - 1;
8171 // there are 2 links to check
8176 // loop on links, to be precise, on the second node of links
8177 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8178 const SMDS_MeshNode* n = nodes[ iNode ];
8180 if ( !volume.IsLinked( n, prevSideNode ))
8184 if ( iNode ) // a node before prevSideNode
8185 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8186 else // a node after prevSideNode
8187 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8189 // check if this link was already used
8190 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8191 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8192 if (!isJustChecked &&
8193 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8195 // test a link geometrically
8196 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8197 bool linkIsBetter = false;
8198 double dot = 0.0, dist = 0.0;
8199 if ( searchByDir ) { // choose most co-directed link
8200 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8201 linkIsBetter = ( dot > maxDot );
8203 else { // choose link with the node closest to bordPos
8204 dist = ( nextXYZ - bordPos ).SquareModulus();
8205 linkIsBetter = ( dist < minDist );
8207 if ( linkIsBetter ) {
8216 } // loop on inverse elements of prevSideNode
8219 MESSAGE(" Cant find path by links of the Side 2 ");
8220 return SEW_BAD_SIDE_NODES;
8222 sideNodes.push_back( sideNode );
8223 sideElems.push_back( sideElem );
8224 foundSideLinkIDs.insert ( linkID );
8225 prevSideNode = sideNode;
8227 if ( *nBordIt == theBordLastNode )
8228 searchByDir = false;
8230 // find the next border link to compare with
8231 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8232 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8233 // move to next border node if sideNode is before forward border node (bordPos)
8234 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8235 prevBordNode = *nBordIt;
8237 bordPos = nBordXYZ[ *nBordIt ];
8238 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8239 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8243 while ( sideNode != theSideSecondNode );
8245 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8246 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8247 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8249 } // end nodes search on the side 2
8251 // ============================
8252 // sew the border to the side 2
8253 // ============================
8255 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8256 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8258 TListOfListOfNodes nodeGroupsToMerge;
8259 if ( nbNodes[0] == nbNodes[1] ||
8260 ( theSideIsFreeBorder && !theSideThirdNode)) {
8262 // all nodes are to be merged
8264 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8265 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8266 nIt[0]++, nIt[1]++ )
8268 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8269 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8270 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8275 // insert new nodes into the border and the side to get equal nb of segments
8277 // get normalized parameters of nodes on the borders
8278 //double param[ 2 ][ maxNbNodes ];
8280 param[0] = new double [ maxNbNodes ];
8281 param[1] = new double [ maxNbNodes ];
8283 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8284 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8285 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8286 const SMDS_MeshNode* nPrev = *nIt;
8287 double bordLength = 0;
8288 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8289 const SMDS_MeshNode* nCur = *nIt;
8290 gp_XYZ segment (nCur->X() - nPrev->X(),
8291 nCur->Y() - nPrev->Y(),
8292 nCur->Z() - nPrev->Z());
8293 double segmentLen = segment.Modulus();
8294 bordLength += segmentLen;
8295 param[ iBord ][ iNode ] = bordLength;
8298 // normalize within [0,1]
8299 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8300 param[ iBord ][ iNode ] /= bordLength;
8304 // loop on border segments
8305 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8306 int i[ 2 ] = { 0, 0 };
8307 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8308 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8310 TElemOfNodeListMap insertMap;
8311 TElemOfNodeListMap::iterator insertMapIt;
8313 // key: elem to insert nodes into
8314 // value: 2 nodes to insert between + nodes to be inserted
8316 bool next[ 2 ] = { false, false };
8318 // find min adjacent segment length after sewing
8319 double nextParam = 10., prevParam = 0;
8320 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8321 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8322 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8323 if ( i[ iBord ] > 0 )
8324 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8326 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8327 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8328 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8330 // choose to insert or to merge nodes
8331 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8332 if ( Abs( du ) <= minSegLen * 0.2 ) {
8335 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8336 const SMDS_MeshNode* n0 = *nIt[0];
8337 const SMDS_MeshNode* n1 = *nIt[1];
8338 nodeGroupsToMerge.back().push_back( n1 );
8339 nodeGroupsToMerge.back().push_back( n0 );
8340 // position of node of the border changes due to merge
8341 param[ 0 ][ i[0] ] += du;
8342 // move n1 for the sake of elem shape evaluation during insertion.
8343 // n1 will be removed by MergeNodes() anyway
8344 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8345 next[0] = next[1] = true;
8350 int intoBord = ( du < 0 ) ? 0 : 1;
8351 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8352 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8353 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8354 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8355 if ( intoBord == 1 ) {
8356 // move node of the border to be on a link of elem of the side
8357 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8358 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8359 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8360 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8361 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8363 insertMapIt = insertMap.find( elem );
8364 bool notFound = ( insertMapIt == insertMap.end() );
8365 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8367 // insert into another link of the same element:
8368 // 1. perform insertion into the other link of the elem
8369 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8370 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8371 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8372 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8373 // 2. perform insertion into the link of adjacent faces
8375 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8377 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8381 if (toCreatePolyedrs) {
8382 // perform insertion into the links of adjacent volumes
8383 UpdateVolumes(n12, n22, nodeList);
8385 // 3. find an element appeared on n1 and n2 after the insertion
8386 insertMap.erase( elem );
8387 elem = findAdjacentFace( n1, n2, 0 );
8389 if ( notFound || otherLink ) {
8390 // add element and nodes of the side into the insertMap
8391 insertMapIt = insertMap.insert
8392 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8393 (*insertMapIt).second.push_back( n1 );
8394 (*insertMapIt).second.push_back( n2 );
8396 // add node to be inserted into elem
8397 (*insertMapIt).second.push_back( nIns );
8398 next[ 1 - intoBord ] = true;
8401 // go to the next segment
8402 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8403 if ( next[ iBord ] ) {
8404 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8406 nPrev[ iBord ] = *nIt[ iBord ];
8407 nIt[ iBord ]++; i[ iBord ]++;
8411 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8413 // perform insertion of nodes into elements
8415 for (insertMapIt = insertMap.begin();
8416 insertMapIt != insertMap.end();
8419 const SMDS_MeshElement* elem = (*insertMapIt).first;
8420 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8421 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8422 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8424 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8426 if ( !theSideIsFreeBorder ) {
8427 // look for and insert nodes into the faces adjacent to elem
8429 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8431 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8436 if (toCreatePolyedrs) {
8437 // perform insertion into the links of adjacent volumes
8438 UpdateVolumes(n1, n2, nodeList);
8444 } // end: insert new nodes
8446 MergeNodes ( nodeGroupsToMerge );
8451 //=======================================================================
8452 //function : InsertNodesIntoLink
8453 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8454 // and theBetweenNode2 and split theElement
8455 //=======================================================================
8457 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8458 const SMDS_MeshNode* theBetweenNode1,
8459 const SMDS_MeshNode* theBetweenNode2,
8460 list<const SMDS_MeshNode*>& theNodesToInsert,
8461 const bool toCreatePoly)
8463 if ( theFace->GetType() != SMDSAbs_Face ) return;
8465 // find indices of 2 link nodes and of the rest nodes
8466 int iNode = 0, il1, il2, i3, i4;
8467 il1 = il2 = i3 = i4 = -1;
8468 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8469 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8471 if(theFace->IsQuadratic()) {
8472 const SMDS_QuadraticFaceOfNodes* F =
8473 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8474 // use special nodes iterator
8475 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8476 while( anIter->more() ) {
8477 const SMDS_MeshNode* n = anIter->next();
8478 if ( n == theBetweenNode1 )
8480 else if ( n == theBetweenNode2 )
8486 nodes[ iNode++ ] = n;
8490 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8491 while ( nodeIt->more() ) {
8492 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8493 if ( n == theBetweenNode1 )
8495 else if ( n == theBetweenNode2 )
8501 nodes[ iNode++ ] = n;
8504 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8507 // arrange link nodes to go one after another regarding the face orientation
8508 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8509 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8514 aNodesToInsert.reverse();
8516 // check that not link nodes of a quadrangles are in good order
8517 int nbFaceNodes = theFace->NbNodes();
8518 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8524 if (toCreatePoly || theFace->IsPoly()) {
8527 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8529 // add nodes of face up to first node of link
8532 if(theFace->IsQuadratic()) {
8533 const SMDS_QuadraticFaceOfNodes* F =
8534 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8535 // use special nodes iterator
8536 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8537 while( anIter->more() && !isFLN ) {
8538 const SMDS_MeshNode* n = anIter->next();
8539 poly_nodes[iNode++] = n;
8540 if (n == nodes[il1]) {
8544 // add nodes to insert
8545 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8546 for (; nIt != aNodesToInsert.end(); nIt++) {
8547 poly_nodes[iNode++] = *nIt;
8549 // add nodes of face starting from last node of link
8550 while ( anIter->more() ) {
8551 poly_nodes[iNode++] = anIter->next();
8555 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8556 while ( nodeIt->more() && !isFLN ) {
8557 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8558 poly_nodes[iNode++] = n;
8559 if (n == nodes[il1]) {
8563 // add nodes to insert
8564 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8565 for (; nIt != aNodesToInsert.end(); nIt++) {
8566 poly_nodes[iNode++] = *nIt;
8568 // add nodes of face starting from last node of link
8569 while ( nodeIt->more() ) {
8570 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8571 poly_nodes[iNode++] = n;
8575 // edit or replace the face
8576 SMESHDS_Mesh *aMesh = GetMeshDS();
8578 if (theFace->IsPoly()) {
8579 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8582 int aShapeId = FindShape( theFace );
8584 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8585 myLastCreatedElems.Append(newElem);
8586 if ( aShapeId && newElem )
8587 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8589 aMesh->RemoveElement(theFace);
8594 if( !theFace->IsQuadratic() ) {
8596 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8597 int nbLinkNodes = 2 + aNodesToInsert.size();
8598 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8599 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8600 linkNodes[ 0 ] = nodes[ il1 ];
8601 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8602 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8603 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8604 linkNodes[ iNode++ ] = *nIt;
8606 // decide how to split a quadrangle: compare possible variants
8607 // and choose which of splits to be a quadrangle
8608 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8609 if ( nbFaceNodes == 3 ) {
8610 iBestQuad = nbSplits;
8613 else if ( nbFaceNodes == 4 ) {
8614 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8615 double aBestRate = DBL_MAX;
8616 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8618 double aBadRate = 0;
8619 // evaluate elements quality
8620 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8621 if ( iSplit == iQuad ) {
8622 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8626 aBadRate += getBadRate( &quad, aCrit );
8629 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8631 nodes[ iSplit < iQuad ? i4 : i3 ]);
8632 aBadRate += getBadRate( &tria, aCrit );
8636 if ( aBadRate < aBestRate ) {
8638 aBestRate = aBadRate;
8643 // create new elements
8644 SMESHDS_Mesh *aMesh = GetMeshDS();
8645 int aShapeId = FindShape( theFace );
8648 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8649 SMDS_MeshElement* newElem = 0;
8650 if ( iSplit == iBestQuad )
8651 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8656 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8658 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8659 myLastCreatedElems.Append(newElem);
8660 if ( aShapeId && newElem )
8661 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8664 // change nodes of theFace
8665 const SMDS_MeshNode* newNodes[ 4 ];
8666 newNodes[ 0 ] = linkNodes[ i1 ];
8667 newNodes[ 1 ] = linkNodes[ i2 ];
8668 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8669 newNodes[ 3 ] = nodes[ i4 ];
8670 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8671 } // end if(!theFace->IsQuadratic())
8672 else { // theFace is quadratic
8673 // we have to split theFace on simple triangles and one simple quadrangle
8675 int nbshift = tmp*2;
8676 // shift nodes in nodes[] by nbshift
8678 for(i=0; i<nbshift; i++) {
8679 const SMDS_MeshNode* n = nodes[0];
8680 for(j=0; j<nbFaceNodes-1; j++) {
8681 nodes[j] = nodes[j+1];
8683 nodes[nbFaceNodes-1] = n;
8685 il1 = il1 - nbshift;
8686 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8687 // n0 n1 n2 n0 n1 n2
8688 // +-----+-----+ +-----+-----+
8697 // create new elements
8698 SMESHDS_Mesh *aMesh = GetMeshDS();
8699 int aShapeId = FindShape( theFace );
8702 if(nbFaceNodes==6) { // quadratic triangle
8703 SMDS_MeshElement* newElem =
8704 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8705 myLastCreatedElems.Append(newElem);
8706 if ( aShapeId && newElem )
8707 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8708 if(theFace->IsMediumNode(nodes[il1])) {
8709 // create quadrangle
8710 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8711 myLastCreatedElems.Append(newElem);
8712 if ( aShapeId && newElem )
8713 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8719 // create quadrangle
8720 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8721 myLastCreatedElems.Append(newElem);
8722 if ( aShapeId && newElem )
8723 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8729 else { // nbFaceNodes==8 - quadratic quadrangle
8730 SMDS_MeshElement* newElem =
8731 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8732 myLastCreatedElems.Append(newElem);
8733 if ( aShapeId && newElem )
8734 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8735 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8736 myLastCreatedElems.Append(newElem);
8737 if ( aShapeId && newElem )
8738 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8739 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8740 myLastCreatedElems.Append(newElem);
8741 if ( aShapeId && newElem )
8742 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8743 if(theFace->IsMediumNode(nodes[il1])) {
8744 // create quadrangle
8745 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8746 myLastCreatedElems.Append(newElem);
8747 if ( aShapeId && newElem )
8748 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8754 // create quadrangle
8755 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8756 myLastCreatedElems.Append(newElem);
8757 if ( aShapeId && newElem )
8758 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8764 // create needed triangles using n1,n2,n3 and inserted nodes
8765 int nbn = 2 + aNodesToInsert.size();
8766 //const SMDS_MeshNode* aNodes[nbn];
8767 vector<const SMDS_MeshNode*> aNodes(nbn);
8768 aNodes[0] = nodes[n1];
8769 aNodes[nbn-1] = nodes[n2];
8770 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8771 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8772 aNodes[iNode++] = *nIt;
8774 for(i=1; i<nbn; i++) {
8775 SMDS_MeshElement* newElem =
8776 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8777 myLastCreatedElems.Append(newElem);
8778 if ( aShapeId && newElem )
8779 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8781 // remove old quadratic face
8782 aMesh->RemoveElement(theFace);
8786 //=======================================================================
8787 //function : UpdateVolumes
8789 //=======================================================================
8790 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8791 const SMDS_MeshNode* theBetweenNode2,
8792 list<const SMDS_MeshNode*>& theNodesToInsert)
8794 myLastCreatedElems.Clear();
8795 myLastCreatedNodes.Clear();
8797 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8798 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8799 const SMDS_MeshElement* elem = invElemIt->next();
8801 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8802 SMDS_VolumeTool aVolume (elem);
8803 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8806 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8807 int iface, nbFaces = aVolume.NbFaces();
8808 vector<const SMDS_MeshNode *> poly_nodes;
8809 vector<int> quantities (nbFaces);
8811 for (iface = 0; iface < nbFaces; iface++) {
8812 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8813 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8814 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8816 for (int inode = 0; inode < nbFaceNodes; inode++) {
8817 poly_nodes.push_back(faceNodes[inode]);
8819 if (nbInserted == 0) {
8820 if (faceNodes[inode] == theBetweenNode1) {
8821 if (faceNodes[inode + 1] == theBetweenNode2) {
8822 nbInserted = theNodesToInsert.size();
8824 // add nodes to insert
8825 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8826 for (; nIt != theNodesToInsert.end(); nIt++) {
8827 poly_nodes.push_back(*nIt);
8831 else if (faceNodes[inode] == theBetweenNode2) {
8832 if (faceNodes[inode + 1] == theBetweenNode1) {
8833 nbInserted = theNodesToInsert.size();
8835 // add nodes to insert in reversed order
8836 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8838 for (; nIt != theNodesToInsert.begin(); nIt--) {
8839 poly_nodes.push_back(*nIt);
8841 poly_nodes.push_back(*nIt);
8848 quantities[iface] = nbFaceNodes + nbInserted;
8851 // Replace or update the volume
8852 SMESHDS_Mesh *aMesh = GetMeshDS();
8854 if (elem->IsPoly()) {
8855 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8859 int aShapeId = FindShape( elem );
8861 SMDS_MeshElement* newElem =
8862 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8863 myLastCreatedElems.Append(newElem);
8864 if (aShapeId && newElem)
8865 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8867 aMesh->RemoveElement(elem);
8872 //=======================================================================
8874 * \brief Convert elements contained in a submesh to quadratic
8875 * \retval int - nb of checked elements
8877 //=======================================================================
8879 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8880 SMESH_MesherHelper& theHelper,
8881 const bool theForce3d)
8884 if( !theSm ) return nbElem;
8886 const bool notFromGroups = false;
8887 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8888 while(ElemItr->more())
8891 const SMDS_MeshElement* elem = ElemItr->next();
8892 if( !elem || elem->IsQuadratic() ) continue;
8894 int id = elem->GetID();
8895 int nbNodes = elem->NbNodes();
8896 vector<const SMDS_MeshNode *> aNds (nbNodes);
8898 for(int i = 0; i < nbNodes; i++)
8900 aNds[i] = elem->GetNode(i);
8902 SMDSAbs_ElementType aType = elem->GetType();
8904 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8906 const SMDS_MeshElement* NewElem = 0;
8912 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8920 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8923 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8930 case SMDSAbs_Volume :
8935 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8938 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8941 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8944 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8945 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8955 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8957 theSm->AddElement( NewElem );
8962 //=======================================================================
8963 //function : ConvertToQuadratic
8965 //=======================================================================
8966 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8968 SMESHDS_Mesh* meshDS = GetMeshDS();
8970 SMESH_MesherHelper aHelper(*myMesh);
8971 aHelper.SetIsQuadratic( true );
8972 const bool notFromGroups = false;
8974 int nbCheckedElems = 0;
8975 if ( myMesh->HasShapeToMesh() )
8977 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8979 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8980 while ( smIt->more() ) {
8981 SMESH_subMesh* sm = smIt->next();
8982 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8983 aHelper.SetSubShape( sm->GetSubShape() );
8984 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8989 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8990 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8992 SMESHDS_SubMesh *smDS = 0;
8993 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8994 while(aEdgeItr->more())
8996 const SMDS_MeshEdge* edge = aEdgeItr->next();
8997 if(edge && !edge->IsQuadratic())
8999 int id = edge->GetID();
9000 const SMDS_MeshNode* n1 = edge->GetNode(0);
9001 const SMDS_MeshNode* n2 = edge->GetNode(1);
9003 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
9005 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9006 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9009 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9010 while(aFaceItr->more())
9012 const SMDS_MeshFace* face = aFaceItr->next();
9013 if(!face || face->IsQuadratic() ) continue;
9015 int id = face->GetID();
9016 int nbNodes = face->NbNodes();
9017 vector<const SMDS_MeshNode *> aNds (nbNodes);
9019 for(int i = 0; i < nbNodes; i++)
9021 aNds[i] = face->GetNode(i);
9024 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9026 SMDS_MeshFace * NewFace = 0;
9030 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9033 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9038 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9040 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9041 while(aVolumeItr->more())
9043 const SMDS_MeshVolume* volume = aVolumeItr->next();
9044 if(!volume || volume->IsQuadratic() ) continue;
9046 int id = volume->GetID();
9047 int nbNodes = volume->NbNodes();
9048 vector<const SMDS_MeshNode *> aNds (nbNodes);
9050 for(int i = 0; i < nbNodes; i++)
9052 aNds[i] = volume->GetNode(i);
9055 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9057 SMDS_MeshVolume * NewVolume = 0;
9061 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9062 aNds[3], id, theForce3d );
9065 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9066 aNds[3], aNds[4], id, theForce3d);
9069 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9070 aNds[3], aNds[4], aNds[5], id, theForce3d);
9073 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9074 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9079 ReplaceElemInGroups(volume, NewVolume, meshDS);
9082 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9083 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9084 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9085 aHelper.FixQuadraticElements();
9089 //=======================================================================
9091 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9092 * \retval int - nb of checked elements
9094 //=======================================================================
9096 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9097 SMDS_ElemIteratorPtr theItr,
9098 const int theShapeID)
9101 SMESHDS_Mesh* meshDS = GetMeshDS();
9102 const bool notFromGroups = false;
9104 while( theItr->more() )
9106 const SMDS_MeshElement* elem = theItr->next();
9108 if( elem && elem->IsQuadratic())
9110 int id = elem->GetID();
9111 int nbNodes = elem->NbNodes();
9112 vector<const SMDS_MeshNode *> aNds, mediumNodes;
9113 aNds.reserve( nbNodes );
9114 mediumNodes.reserve( nbNodes );
9116 for(int i = 0; i < nbNodes; i++)
9118 const SMDS_MeshNode* n = elem->GetNode(i);
9120 if( elem->IsMediumNode( n ) )
9121 mediumNodes.push_back( n );
9123 aNds.push_back( n );
9125 if( aNds.empty() ) continue;
9126 SMDSAbs_ElementType aType = elem->GetType();
9128 //remove old quadratic element
9129 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9131 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9132 ReplaceElemInGroups(elem, NewElem, meshDS);
9133 if( theSm && NewElem )
9134 theSm->AddElement( NewElem );
9136 // remove medium nodes
9137 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9138 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9139 const SMDS_MeshNode* n = *nIt;
9140 if ( n->NbInverseElements() == 0 ) {
9141 if ( n->GetPosition()->GetShapeId() != theShapeID )
9142 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9143 ( n->GetPosition()->GetShapeId() ));
9145 meshDS->RemoveFreeNode( n, theSm );
9153 //=======================================================================
9154 //function : ConvertFromQuadratic
9156 //=======================================================================
9157 bool SMESH_MeshEditor::ConvertFromQuadratic()
9159 int nbCheckedElems = 0;
9160 if ( myMesh->HasShapeToMesh() )
9162 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9164 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9165 while ( smIt->more() ) {
9166 SMESH_subMesh* sm = smIt->next();
9167 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9168 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9174 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9175 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9177 SMESHDS_SubMesh *aSM = 0;
9178 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9184 //=======================================================================
9185 //function : SewSideElements
9187 //=======================================================================
9189 SMESH_MeshEditor::Sew_Error
9190 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9191 TIDSortedElemSet& theSide2,
9192 const SMDS_MeshNode* theFirstNode1,
9193 const SMDS_MeshNode* theFirstNode2,
9194 const SMDS_MeshNode* theSecondNode1,
9195 const SMDS_MeshNode* theSecondNode2)
9197 myLastCreatedElems.Clear();
9198 myLastCreatedNodes.Clear();
9200 MESSAGE ("::::SewSideElements()");
9201 if ( theSide1.size() != theSide2.size() )
9202 return SEW_DIFF_NB_OF_ELEMENTS;
9204 Sew_Error aResult = SEW_OK;
9206 // 1. Build set of faces representing each side
9207 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9208 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9210 // =======================================================================
9211 // 1. Build set of faces representing each side:
9212 // =======================================================================
9213 // a. build set of nodes belonging to faces
9214 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9215 // c. create temporary faces representing side of volumes if correspondent
9216 // face does not exist
9218 SMESHDS_Mesh* aMesh = GetMeshDS();
9219 SMDS_Mesh aTmpFacesMesh;
9220 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9221 set<const SMDS_MeshElement*> volSet1, volSet2;
9222 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9223 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9224 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9225 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9226 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9227 int iSide, iFace, iNode;
9229 for ( iSide = 0; iSide < 2; iSide++ ) {
9230 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9231 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9232 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9233 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9234 set<const SMDS_MeshElement*>::iterator vIt;
9235 TIDSortedElemSet::iterator eIt;
9236 set<const SMDS_MeshNode*>::iterator nIt;
9238 // check that given nodes belong to given elements
9239 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9240 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9241 int firstIndex = -1, secondIndex = -1;
9242 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9243 const SMDS_MeshElement* elem = *eIt;
9244 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9245 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9246 if ( firstIndex > -1 && secondIndex > -1 ) break;
9248 if ( firstIndex < 0 || secondIndex < 0 ) {
9249 // we can simply return until temporary faces created
9250 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9253 // -----------------------------------------------------------
9254 // 1a. Collect nodes of existing faces
9255 // and build set of face nodes in order to detect missing
9256 // faces corresponing to sides of volumes
9257 // -----------------------------------------------------------
9259 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9261 // loop on the given element of a side
9262 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9263 //const SMDS_MeshElement* elem = *eIt;
9264 const SMDS_MeshElement* elem = *eIt;
9265 if ( elem->GetType() == SMDSAbs_Face ) {
9266 faceSet->insert( elem );
9267 set <const SMDS_MeshNode*> faceNodeSet;
9268 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9269 while ( nodeIt->more() ) {
9270 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9271 nodeSet->insert( n );
9272 faceNodeSet.insert( n );
9274 setOfFaceNodeSet.insert( faceNodeSet );
9276 else if ( elem->GetType() == SMDSAbs_Volume )
9277 volSet->insert( elem );
9279 // ------------------------------------------------------------------------------
9280 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9281 // ------------------------------------------------------------------------------
9283 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9284 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9285 while ( fIt->more() ) { // loop on faces sharing a node
9286 const SMDS_MeshElement* f = fIt->next();
9287 if ( faceSet->find( f ) == faceSet->end() ) {
9288 // check if all nodes are in nodeSet and
9289 // complete setOfFaceNodeSet if they are
9290 set <const SMDS_MeshNode*> faceNodeSet;
9291 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9292 bool allInSet = true;
9293 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9294 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9295 if ( nodeSet->find( n ) == nodeSet->end() )
9298 faceNodeSet.insert( n );
9301 faceSet->insert( f );
9302 setOfFaceNodeSet.insert( faceNodeSet );
9308 // -------------------------------------------------------------------------
9309 // 1c. Create temporary faces representing sides of volumes if correspondent
9310 // face does not exist
9311 // -------------------------------------------------------------------------
9313 if ( !volSet->empty() ) {
9314 //int nodeSetSize = nodeSet->size();
9316 // loop on given volumes
9317 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9318 SMDS_VolumeTool vol (*vIt);
9319 // loop on volume faces: find free faces
9320 // --------------------------------------
9321 list<const SMDS_MeshElement* > freeFaceList;
9322 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9323 if ( !vol.IsFreeFace( iFace ))
9325 // check if there is already a face with same nodes in a face set
9326 const SMDS_MeshElement* aFreeFace = 0;
9327 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9328 int nbNodes = vol.NbFaceNodes( iFace );
9329 set <const SMDS_MeshNode*> faceNodeSet;
9330 vol.GetFaceNodes( iFace, faceNodeSet );
9331 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9333 // no such a face is given but it still can exist, check it
9334 if ( nbNodes == 3 ) {
9335 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9337 else if ( nbNodes == 4 ) {
9338 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9341 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9342 aFreeFace = aMesh->FindFace(poly_nodes);
9346 // create a temporary face
9347 if ( nbNodes == 3 ) {
9348 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9350 else if ( nbNodes == 4 ) {
9351 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9354 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9355 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9359 freeFaceList.push_back( aFreeFace );
9361 } // loop on faces of a volume
9363 // choose one of several free faces
9364 // --------------------------------------
9365 if ( freeFaceList.size() > 1 ) {
9366 // choose a face having max nb of nodes shared by other elems of a side
9367 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9368 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9369 while ( fIt != freeFaceList.end() ) { // loop on free faces
9370 int nbSharedNodes = 0;
9371 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9372 while ( nodeIt->more() ) { // loop on free face nodes
9373 const SMDS_MeshNode* n =
9374 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9375 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9376 while ( invElemIt->more() ) {
9377 const SMDS_MeshElement* e = invElemIt->next();
9378 if ( faceSet->find( e ) != faceSet->end() )
9380 if ( elemSet->find( e ) != elemSet->end() )
9384 if ( nbSharedNodes >= maxNbNodes ) {
9385 maxNbNodes = nbSharedNodes;
9389 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9391 if ( freeFaceList.size() > 1 )
9393 // could not choose one face, use another way
9394 // choose a face most close to the bary center of the opposite side
9395 gp_XYZ aBC( 0., 0., 0. );
9396 set <const SMDS_MeshNode*> addedNodes;
9397 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9398 eIt = elemSet2->begin();
9399 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9400 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9401 while ( nodeIt->more() ) { // loop on free face nodes
9402 const SMDS_MeshNode* n =
9403 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9404 if ( addedNodes.insert( n ).second )
9405 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9408 aBC /= addedNodes.size();
9409 double minDist = DBL_MAX;
9410 fIt = freeFaceList.begin();
9411 while ( fIt != freeFaceList.end() ) { // loop on free faces
9413 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9414 while ( nodeIt->more() ) { // loop on free face nodes
9415 const SMDS_MeshNode* n =
9416 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9417 gp_XYZ p( n->X(),n->Y(),n->Z() );
9418 dist += ( aBC - p ).SquareModulus();
9420 if ( dist < minDist ) {
9422 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9425 fIt = freeFaceList.erase( fIt++ );
9428 } // choose one of several free faces of a volume
9430 if ( freeFaceList.size() == 1 ) {
9431 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9432 faceSet->insert( aFreeFace );
9433 // complete a node set with nodes of a found free face
9434 // for ( iNode = 0; iNode < ; iNode++ )
9435 // nodeSet->insert( fNodes[ iNode ] );
9438 } // loop on volumes of a side
9440 // // complete a set of faces if new nodes in a nodeSet appeared
9441 // // ----------------------------------------------------------
9442 // if ( nodeSetSize != nodeSet->size() ) {
9443 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9444 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9445 // while ( fIt->more() ) { // loop on faces sharing a node
9446 // const SMDS_MeshElement* f = fIt->next();
9447 // if ( faceSet->find( f ) == faceSet->end() ) {
9448 // // check if all nodes are in nodeSet and
9449 // // complete setOfFaceNodeSet if they are
9450 // set <const SMDS_MeshNode*> faceNodeSet;
9451 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9452 // bool allInSet = true;
9453 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9454 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9455 // if ( nodeSet->find( n ) == nodeSet->end() )
9456 // allInSet = false;
9458 // faceNodeSet.insert( n );
9460 // if ( allInSet ) {
9461 // faceSet->insert( f );
9462 // setOfFaceNodeSet.insert( faceNodeSet );
9468 } // Create temporary faces, if there are volumes given
9471 if ( faceSet1.size() != faceSet2.size() ) {
9472 // delete temporary faces: they are in reverseElements of actual nodes
9473 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9474 while ( tmpFaceIt->more() )
9475 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9476 MESSAGE("Diff nb of faces");
9477 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9480 // ============================================================
9481 // 2. Find nodes to merge:
9482 // bind a node to remove to a node to put instead
9483 // ============================================================
9485 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9486 if ( theFirstNode1 != theFirstNode2 )
9487 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9488 if ( theSecondNode1 != theSecondNode2 )
9489 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9491 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9492 set< long > linkIdSet; // links to process
9493 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9495 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9496 list< NLink > linkList[2];
9497 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9498 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9499 // loop on links in linkList; find faces by links and append links
9500 // of the found faces to linkList
9501 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9502 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9503 NLink link[] = { *linkIt[0], *linkIt[1] };
9504 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9505 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9508 // by links, find faces in the face sets,
9509 // and find indices of link nodes in the found faces;
9510 // in a face set, there is only one or no face sharing a link
9511 // ---------------------------------------------------------------
9513 const SMDS_MeshElement* face[] = { 0, 0 };
9514 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9515 vector<const SMDS_MeshNode*> fnodes1(9);
9516 vector<const SMDS_MeshNode*> fnodes2(9);
9517 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9518 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9519 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9520 int iLinkNode[2][2];
9521 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9522 const SMDS_MeshNode* n1 = link[iSide].first;
9523 const SMDS_MeshNode* n2 = link[iSide].second;
9524 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9525 set< const SMDS_MeshElement* > fMap;
9526 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9527 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9528 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9529 while ( fIt->more() ) { // loop on faces sharing a node
9530 const SMDS_MeshElement* f = fIt->next();
9531 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9532 ! fMap.insert( f ).second ) // f encounters twice
9534 if ( face[ iSide ] ) {
9535 MESSAGE( "2 faces per link " );
9536 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9540 faceSet->erase( f );
9541 // get face nodes and find ones of a link
9546 fnodes1.resize(f->NbNodes()+1);
9547 notLinkNodes1.resize(f->NbNodes()-2);
9550 fnodes2.resize(f->NbNodes()+1);
9551 notLinkNodes2.resize(f->NbNodes()-2);
9554 if(!f->IsQuadratic()) {
9555 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9556 while ( nIt->more() ) {
9557 const SMDS_MeshNode* n =
9558 static_cast<const SMDS_MeshNode*>( nIt->next() );
9560 iLinkNode[ iSide ][ 0 ] = iNode;
9562 else if ( n == n2 ) {
9563 iLinkNode[ iSide ][ 1 ] = iNode;
9565 //else if ( notLinkNodes[ iSide ][ 0 ] )
9566 // notLinkNodes[ iSide ][ 1 ] = n;
9568 // notLinkNodes[ iSide ][ 0 ] = n;
9572 notLinkNodes1[nbl] = n;
9573 //notLinkNodes1.push_back(n);
9575 notLinkNodes2[nbl] = n;
9576 //notLinkNodes2.push_back(n);
9578 //faceNodes[ iSide ][ iNode++ ] = n;
9580 fnodes1[iNode++] = n;
9583 fnodes2[iNode++] = n;
9587 else { // f->IsQuadratic()
9588 const SMDS_QuadraticFaceOfNodes* F =
9589 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9590 // use special nodes iterator
9591 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9592 while ( anIter->more() ) {
9593 const SMDS_MeshNode* n =
9594 static_cast<const SMDS_MeshNode*>( anIter->next() );
9596 iLinkNode[ iSide ][ 0 ] = iNode;
9598 else if ( n == n2 ) {
9599 iLinkNode[ iSide ][ 1 ] = iNode;
9604 notLinkNodes1[nbl] = n;
9607 notLinkNodes2[nbl] = n;
9611 fnodes1[iNode++] = n;
9614 fnodes2[iNode++] = n;
9618 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9620 fnodes1[iNode] = fnodes1[0];
9623 fnodes2[iNode] = fnodes1[0];
9630 // check similarity of elements of the sides
9631 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9632 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9633 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9634 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9637 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9639 break; // do not return because it s necessary to remove tmp faces
9642 // set nodes to merge
9643 // -------------------
9645 if ( face[0] && face[1] ) {
9646 int nbNodes = face[0]->NbNodes();
9647 if ( nbNodes != face[1]->NbNodes() ) {
9648 MESSAGE("Diff nb of face nodes");
9649 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9650 break; // do not return because it s necessary to remove tmp faces
9652 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9653 if ( nbNodes == 3 ) {
9654 //nReplaceMap.insert( TNodeNodeMap::value_type
9655 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9656 nReplaceMap.insert( TNodeNodeMap::value_type
9657 ( notLinkNodes1[0], notLinkNodes2[0] ));
9660 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9661 // analyse link orientation in faces
9662 int i1 = iLinkNode[ iSide ][ 0 ];
9663 int i2 = iLinkNode[ iSide ][ 1 ];
9664 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9665 // if notLinkNodes are the first and the last ones, then
9666 // their order does not correspond to the link orientation
9667 if (( i1 == 1 && i2 == 2 ) ||
9668 ( i1 == 2 && i2 == 1 ))
9669 reverse[ iSide ] = !reverse[ iSide ];
9671 if ( reverse[0] == reverse[1] ) {
9672 //nReplaceMap.insert( TNodeNodeMap::value_type
9673 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9674 //nReplaceMap.insert( TNodeNodeMap::value_type
9675 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9676 for(int nn=0; nn<nbNodes-2; nn++) {
9677 nReplaceMap.insert( TNodeNodeMap::value_type
9678 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9682 //nReplaceMap.insert( TNodeNodeMap::value_type
9683 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9684 //nReplaceMap.insert( TNodeNodeMap::value_type
9685 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9686 for(int nn=0; nn<nbNodes-2; nn++) {
9687 nReplaceMap.insert( TNodeNodeMap::value_type
9688 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9693 // add other links of the faces to linkList
9694 // -----------------------------------------
9696 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9697 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9698 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9699 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9700 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9701 if ( !iter_isnew.second ) { // already in a set: no need to process
9702 linkIdSet.erase( iter_isnew.first );
9704 else // new in set == encountered for the first time: add
9706 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9707 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9708 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9709 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9710 linkList[0].push_back ( NLink( n1, n2 ));
9711 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9715 } // loop on link lists
9717 if ( aResult == SEW_OK &&
9718 ( linkIt[0] != linkList[0].end() ||
9719 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9720 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9721 " " << (faceSetPtr[1]->empty()));
9722 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9725 // ====================================================================
9726 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9727 // ====================================================================
9729 // delete temporary faces: they are in reverseElements of actual nodes
9730 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9731 while ( tmpFaceIt->more() )
9732 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9734 if ( aResult != SEW_OK)
9737 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9738 // loop on nodes replacement map
9739 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9740 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9741 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9742 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9743 nodeIDsToRemove.push_back( nToRemove->GetID() );
9744 // loop on elements sharing nToRemove
9745 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9746 while ( invElemIt->more() ) {
9747 const SMDS_MeshElement* e = invElemIt->next();
9748 // get a new suite of nodes: make replacement
9749 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9750 vector< const SMDS_MeshNode*> nodes( nbNodes );
9751 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9752 while ( nIt->more() ) {
9753 const SMDS_MeshNode* n =
9754 static_cast<const SMDS_MeshNode*>( nIt->next() );
9755 nnIt = nReplaceMap.find( n );
9756 if ( nnIt != nReplaceMap.end() ) {
9762 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9763 // elemIDsToRemove.push_back( e->GetID() );
9766 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9770 Remove( nodeIDsToRemove, true );
9775 //================================================================================
9777 * \brief Find corresponding nodes in two sets of faces
9778 * \param theSide1 - first face set
9779 * \param theSide2 - second first face
9780 * \param theFirstNode1 - a boundary node of set 1
9781 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9782 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9783 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9784 * \param nReplaceMap - output map of corresponding nodes
9785 * \retval bool - is a success or not
9787 //================================================================================
9790 //#define DEBUG_MATCHING_NODES
9793 SMESH_MeshEditor::Sew_Error
9794 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9795 set<const SMDS_MeshElement*>& theSide2,
9796 const SMDS_MeshNode* theFirstNode1,
9797 const SMDS_MeshNode* theFirstNode2,
9798 const SMDS_MeshNode* theSecondNode1,
9799 const SMDS_MeshNode* theSecondNode2,
9800 TNodeNodeMap & nReplaceMap)
9802 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9804 nReplaceMap.clear();
9805 if ( theFirstNode1 != theFirstNode2 )
9806 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9807 if ( theSecondNode1 != theSecondNode2 )
9808 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9810 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9811 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9813 list< NLink > linkList[2];
9814 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9815 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9817 // loop on links in linkList; find faces by links and append links
9818 // of the found faces to linkList
9819 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9820 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9821 NLink link[] = { *linkIt[0], *linkIt[1] };
9822 if ( linkSet.find( link[0] ) == linkSet.end() )
9825 // by links, find faces in the face sets,
9826 // and find indices of link nodes in the found faces;
9827 // in a face set, there is only one or no face sharing a link
9828 // ---------------------------------------------------------------
9830 const SMDS_MeshElement* face[] = { 0, 0 };
9831 list<const SMDS_MeshNode*> notLinkNodes[2];
9832 //bool reverse[] = { false, false }; // order of notLinkNodes
9834 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9836 const SMDS_MeshNode* n1 = link[iSide].first;
9837 const SMDS_MeshNode* n2 = link[iSide].second;
9838 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9839 set< const SMDS_MeshElement* > facesOfNode1;
9840 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9842 // during a loop of the first node, we find all faces around n1,
9843 // during a loop of the second node, we find one face sharing both n1 and n2
9844 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9845 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9846 while ( fIt->more() ) { // loop on faces sharing a node
9847 const SMDS_MeshElement* f = fIt->next();
9848 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9849 ! facesOfNode1.insert( f ).second ) // f encounters twice
9851 if ( face[ iSide ] ) {
9852 MESSAGE( "2 faces per link " );
9853 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9856 faceSet->erase( f );
9858 // get not link nodes
9859 int nbN = f->NbNodes();
9860 if ( f->IsQuadratic() )
9862 nbNodes[ iSide ] = nbN;
9863 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9864 int i1 = f->GetNodeIndex( n1 );
9865 int i2 = f->GetNodeIndex( n2 );
9866 int iEnd = nbN, iBeg = -1, iDelta = 1;
9867 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9869 std::swap( iEnd, iBeg ); iDelta = -1;
9874 if ( i == iEnd ) i = iBeg + iDelta;
9875 if ( i == i1 ) break;
9876 nodes.push_back ( f->GetNode( i ) );
9882 // check similarity of elements of the sides
9883 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9884 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9885 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9886 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9889 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9893 // set nodes to merge
9894 // -------------------
9896 if ( face[0] && face[1] ) {
9897 if ( nbNodes[0] != nbNodes[1] ) {
9898 MESSAGE("Diff nb of face nodes");
9899 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9901 #ifdef DEBUG_MATCHING_NODES
9902 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9903 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9904 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9906 int nbN = nbNodes[0];
9908 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9909 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9910 for ( int i = 0 ; i < nbN - 2; ++i ) {
9911 #ifdef DEBUG_MATCHING_NODES
9912 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9914 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9918 // add other links of the face 1 to linkList
9919 // -----------------------------------------
9921 const SMDS_MeshElement* f0 = face[0];
9922 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9923 for ( int i = 0; i < nbN; i++ )
9925 const SMDS_MeshNode* n2 = f0->GetNode( i );
9926 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9927 linkSet.insert( SMESH_TLink( n1, n2 ));
9928 if ( !iter_isnew.second ) { // already in a set: no need to process
9929 linkSet.erase( iter_isnew.first );
9931 else // new in set == encountered for the first time: add
9933 #ifdef DEBUG_MATCHING_NODES
9934 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9935 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9937 linkList[0].push_back ( NLink( n1, n2 ));
9938 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9943 } // loop on link lists
9948 //================================================================================
9950 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9951 \param theElems - the list of elements (edges or faces) to be replicated
9952 The nodes for duplication could be found from these elements
9953 \param theNodesNot - list of nodes to NOT replicate
9954 \param theAffectedElems - the list of elements (cells and edges) to which the
9955 replicated nodes should be associated to.
9956 \return TRUE if operation has been completed successfully, FALSE otherwise
9958 //================================================================================
9960 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9961 const TIDSortedElemSet& theNodesNot,
9962 const TIDSortedElemSet& theAffectedElems )
9964 myLastCreatedElems.Clear();
9965 myLastCreatedNodes.Clear();
9967 if ( theElems.size() == 0 )
9970 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9975 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9976 // duplicate elements and nodes
9977 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9978 // replce nodes by duplications
9979 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9983 //================================================================================
9985 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9986 \param theMeshDS - mesh instance
9987 \param theElems - the elements replicated or modified (nodes should be changed)
9988 \param theNodesNot - nodes to NOT replicate
9989 \param theNodeNodeMap - relation of old node to new created node
9990 \param theIsDoubleElem - flag os to replicate element or modify
9991 \return TRUE if operation has been completed successfully, FALSE otherwise
9993 //================================================================================
9995 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9996 const TIDSortedElemSet& theElems,
9997 const TIDSortedElemSet& theNodesNot,
9998 std::map< const SMDS_MeshNode*,
9999 const SMDS_MeshNode* >& theNodeNodeMap,
10000 const bool theIsDoubleElem )
10002 // iterate on through element and duplicate them (by nodes duplication)
10004 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10005 for ( ; elemItr != theElems.end(); ++elemItr )
10007 const SMDS_MeshElement* anElem = *elemItr;
10011 bool isDuplicate = false;
10012 // duplicate nodes to duplicate element
10013 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10014 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10016 while ( anIter->more() )
10019 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10020 SMDS_MeshNode* aNewNode = aCurrNode;
10021 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10022 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10023 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10026 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10027 theNodeNodeMap[ aCurrNode ] = aNewNode;
10028 myLastCreatedNodes.Append( aNewNode );
10030 isDuplicate |= (aCurrNode != aNewNode);
10031 newNodes[ ind++ ] = aNewNode;
10033 if ( !isDuplicate )
10036 if ( theIsDoubleElem )
10037 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10039 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10046 //================================================================================
10048 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10049 \param theNodes - identifiers of nodes to be doubled
10050 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10051 nodes. If list of element identifiers is empty then nodes are doubled but
10052 they not assigned to elements
10053 \return TRUE if operation has been completed successfully, FALSE otherwise
10055 //================================================================================
10057 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10058 const std::list< int >& theListOfModifiedElems )
10060 myLastCreatedElems.Clear();
10061 myLastCreatedNodes.Clear();
10063 if ( theListOfNodes.size() == 0 )
10066 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10070 // iterate through nodes and duplicate them
10072 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10074 std::list< int >::const_iterator aNodeIter;
10075 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10077 int aCurr = *aNodeIter;
10078 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10084 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10087 anOldNodeToNewNode[ aNode ] = aNewNode;
10088 myLastCreatedNodes.Append( aNewNode );
10092 // Create map of new nodes for modified elements
10094 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10096 std::list< int >::const_iterator anElemIter;
10097 for ( anElemIter = theListOfModifiedElems.begin();
10098 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10100 int aCurr = *anElemIter;
10101 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10105 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10107 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10109 while ( anIter->more() )
10111 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10112 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10114 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10115 aNodeArr[ ind++ ] = aNewNode;
10118 aNodeArr[ ind++ ] = aCurrNode;
10120 anElemToNodes[ anElem ] = aNodeArr;
10123 // Change nodes of elements
10125 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10126 anElemToNodesIter = anElemToNodes.begin();
10127 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10129 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10130 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10132 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10140 //================================================================================
10142 \brief Check if element located inside shape
10143 \return TRUE if IN or ON shape, FALSE otherwise
10145 //================================================================================
10147 template<class Classifier>
10148 bool isInside(const SMDS_MeshElement* theElem,
10149 Classifier& theClassifier,
10150 const double theTol)
10152 gp_XYZ centerXYZ (0, 0, 0);
10153 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10154 while (aNodeItr->more())
10155 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10157 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10158 theClassifier.Perform(aPnt, theTol);
10159 TopAbs_State aState = theClassifier.State();
10160 return (aState == TopAbs_IN || aState == TopAbs_ON );
10163 //================================================================================
10165 * \brief Classifier of the 3D point on the TopoDS_Face
10166 * with interaface suitable for isInside()
10168 //================================================================================
10170 struct _FaceClassifier
10172 Extrema_ExtPS _extremum;
10173 BRepAdaptor_Surface _surface;
10174 TopAbs_State _state;
10176 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10178 _extremum.Initialize( _surface,
10179 _surface.FirstUParameter(), _surface.LastUParameter(),
10180 _surface.FirstVParameter(), _surface.LastVParameter(),
10181 _surface.Tolerance(), _surface.Tolerance() );
10183 void Perform(const gp_Pnt& aPnt, double theTol)
10185 _state = TopAbs_OUT;
10186 _extremum.Perform(aPnt);
10187 if ( _extremum.IsDone() )
10188 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10189 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10191 TopAbs_State State() const
10198 //================================================================================
10200 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10201 \param theElems - group of of elements (edges or faces) to be replicated
10202 \param theNodesNot - group of nodes not to replicate
10203 \param theShape - shape to detect affected elements (element which geometric center
10204 located on or inside shape).
10205 The replicated nodes should be associated to affected elements.
10206 \return TRUE if operation has been completed successfully, FALSE otherwise
10208 //================================================================================
10210 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10211 const TIDSortedElemSet& theNodesNot,
10212 const TopoDS_Shape& theShape )
10214 if ( theShape.IsNull() )
10217 const double aTol = Precision::Confusion();
10218 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10219 auto_ptr<_FaceClassifier> aFaceClassifier;
10220 if ( theShape.ShapeType() == TopAbs_SOLID )
10222 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10223 bsc3d->PerformInfinitePoint(aTol);
10225 else if (theShape.ShapeType() == TopAbs_FACE )
10227 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10230 // iterates on indicated elements and get elements by back references from their nodes
10231 TIDSortedElemSet anAffected;
10232 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10233 for ( ; elemItr != theElems.end(); ++elemItr )
10235 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10239 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10240 while ( nodeItr->more() )
10242 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10243 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10245 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10246 while ( backElemItr->more() )
10248 const SMDS_MeshElement* curElem = backElemItr->next();
10249 if ( curElem && theElems.find(curElem) == theElems.end() &&
10251 isInside( curElem, *bsc3d, aTol ) :
10252 isInside( curElem, *aFaceClassifier, aTol )))
10253 anAffected.insert( curElem );
10257 return DoubleNodes( theElems, theNodesNot, anAffected );
10260 //================================================================================
10262 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10263 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10264 * \return TRUE if operation has been completed successfully, FALSE otherwise
10266 //================================================================================
10268 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10270 // iterates on volume elements and detect all free faces on them
10271 SMESHDS_Mesh* aMesh = GetMeshDS();
10274 //bool res = false;
10275 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10276 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10279 const SMDS_MeshVolume* volume = vIt->next();
10280 SMDS_VolumeTool vTool( volume );
10281 vTool.SetExternalNormal();
10282 const bool isPoly = volume->IsPoly();
10283 const bool isQuad = volume->IsQuadratic();
10284 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10286 if (!vTool.IsFreeFace(iface))
10289 vector<const SMDS_MeshNode *> nodes;
10290 int nbFaceNodes = vTool.NbFaceNodes(iface);
10291 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10293 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10294 nodes.push_back(faceNodes[inode]);
10296 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10297 nodes.push_back(faceNodes[inode]);
10299 // add new face based on volume nodes
10300 if (aMesh->FindFace( nodes ) ) {
10302 continue; // face already exsist
10304 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10308 return ( nbFree==(nbExisted+nbCreated) );