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 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
257 myLastCreatedElems.Clear();
258 myLastCreatedNodes.Clear();
260 SMESHDS_Mesh* aMesh = GetMeshDS();
261 set< SMESH_subMesh *> smmap;
263 list<int>::const_iterator it = theIDs.begin();
264 for ( ; it != theIDs.end(); it++ ) {
265 const SMDS_MeshElement * elem;
267 elem = aMesh->FindNode( *it );
269 elem = aMesh->FindElement( *it );
273 // Notify VERTEX sub-meshes about modification
275 const SMDS_MeshNode* node = cast2Node( elem );
276 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
277 if ( int aShapeID = node->GetPosition()->GetShapeId() )
278 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
281 // Find sub-meshes to notify about modification
282 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
283 // while ( nodeIt->more() ) {
284 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
285 // const SMDS_PositionPtr& aPosition = node->GetPosition();
286 // if ( aPosition.get() ) {
287 // if ( int aShapeID = aPosition->GetShapeId() ) {
288 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
289 // smmap.insert( sm );
296 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
298 aMesh->RemoveElement( elem );
301 // Notify sub-meshes about modification
302 if ( !smmap.empty() ) {
303 set< SMESH_subMesh *>::iterator smIt;
304 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
305 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
308 // // Check if the whole mesh becomes empty
309 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
310 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
315 //=======================================================================
316 //function : FindShape
317 //purpose : Return an index of the shape theElem is on
318 // or zero if a shape not found
319 //=======================================================================
321 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
323 myLastCreatedElems.Clear();
324 myLastCreatedNodes.Clear();
326 SMESHDS_Mesh * aMesh = GetMeshDS();
327 if ( aMesh->ShapeToMesh().IsNull() )
330 if ( theElem->GetType() == SMDSAbs_Node ) {
331 const SMDS_PositionPtr& aPosition =
332 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
333 if ( aPosition.get() )
334 return aPosition->GetShapeId();
339 TopoDS_Shape aShape; // the shape a node is on
340 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
341 while ( nodeIt->more() ) {
342 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
343 const SMDS_PositionPtr& aPosition = node->GetPosition();
344 if ( aPosition.get() ) {
345 int aShapeID = aPosition->GetShapeId();
346 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
348 if ( sm->Contains( theElem ))
350 if ( aShape.IsNull() )
351 aShape = aMesh->IndexToShape( aShapeID );
354 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
359 // None of nodes is on a proper shape,
360 // find the shape among ancestors of aShape on which a node is
361 if ( aShape.IsNull() ) {
362 //MESSAGE ("::FindShape() - NONE node is on shape")
365 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
366 for ( ; ancIt.More(); ancIt.Next() ) {
367 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
368 if ( sm && sm->Contains( theElem ))
369 return aMesh->ShapeToIndex( ancIt.Value() );
372 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
376 //=======================================================================
377 //function : IsMedium
379 //=======================================================================
381 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
382 const SMDSAbs_ElementType typeToCheck)
384 bool isMedium = false;
385 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
386 while (it->more() && !isMedium ) {
387 const SMDS_MeshElement* elem = it->next();
388 isMedium = elem->IsMediumNode(node);
393 //=======================================================================
394 //function : ShiftNodesQuadTria
396 // Shift nodes in the array corresponded to quadratic triangle
397 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
398 //=======================================================================
399 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
401 const SMDS_MeshNode* nd1 = aNodes[0];
402 aNodes[0] = aNodes[1];
403 aNodes[1] = aNodes[2];
405 const SMDS_MeshNode* nd2 = aNodes[3];
406 aNodes[3] = aNodes[4];
407 aNodes[4] = aNodes[5];
411 //=======================================================================
412 //function : GetNodesFromTwoTria
414 // Shift nodes in the array corresponded to quadratic triangle
415 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
416 //=======================================================================
417 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
418 const SMDS_MeshElement * theTria2,
419 const SMDS_MeshNode* N1[],
420 const SMDS_MeshNode* N2[])
422 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
425 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
428 if(it->more()) return false;
429 it = theTria2->nodesIterator();
432 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435 if(it->more()) return false;
437 int sames[3] = {-1,-1,-1};
449 if(nbsames!=2) return false;
451 ShiftNodesQuadTria(N1);
453 ShiftNodesQuadTria(N1);
456 i = sames[0] + sames[1] + sames[2];
458 ShiftNodesQuadTria(N2);
460 // now we receive following N1 and N2 (using numeration as above image)
461 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
462 // i.e. first nodes from both arrays determ new diagonal
466 //=======================================================================
467 //function : InverseDiag
468 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
469 // but having other common link.
470 // Return False if args are improper
471 //=======================================================================
473 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
474 const SMDS_MeshElement * theTria2 )
476 myLastCreatedElems.Clear();
477 myLastCreatedNodes.Clear();
479 if (!theTria1 || !theTria2)
482 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
483 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
486 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
487 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
491 // put nodes in array and find out indices of the same ones
492 const SMDS_MeshNode* aNodes [6];
493 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
495 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
496 while ( it->more() ) {
497 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
499 if ( i > 2 ) // theTria2
500 // find same node of theTria1
501 for ( int j = 0; j < 3; j++ )
502 if ( aNodes[ i ] == aNodes[ j ]) {
511 return false; // theTria1 is not a triangle
512 it = theTria2->nodesIterator();
514 if ( i == 6 && it->more() )
515 return false; // theTria2 is not a triangle
518 // find indices of 1,2 and of A,B in theTria1
519 int iA = 0, iB = 0, i1 = 0, i2 = 0;
520 for ( i = 0; i < 6; i++ ) {
521 if ( sameInd [ i ] == 0 )
528 // nodes 1 and 2 should not be the same
529 if ( aNodes[ i1 ] == aNodes[ i2 ] )
533 aNodes[ iA ] = aNodes[ i2 ];
535 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
537 //MESSAGE( theTria1 << theTria2 );
539 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
540 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
542 //MESSAGE( theTria1 << theTria2 );
546 } // end if(F1 && F2)
548 // check case of quadratic faces
549 const SMDS_QuadraticFaceOfNodes* QF1 =
550 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
551 if(!QF1) return false;
552 const SMDS_QuadraticFaceOfNodes* QF2 =
553 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
554 if(!QF2) return false;
557 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
558 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
566 const SMDS_MeshNode* N1 [6];
567 const SMDS_MeshNode* N2 [6];
568 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
570 // now we receive following N1 and N2 (using numeration as above image)
571 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
572 // i.e. first nodes from both arrays determ new diagonal
574 const SMDS_MeshNode* N1new [6];
575 const SMDS_MeshNode* N2new [6];
588 // replaces nodes in faces
589 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
590 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
595 //=======================================================================
596 //function : findTriangles
597 //purpose : find triangles sharing theNode1-theNode2 link
598 //=======================================================================
600 static bool findTriangles(const SMDS_MeshNode * theNode1,
601 const SMDS_MeshNode * theNode2,
602 const SMDS_MeshElement*& theTria1,
603 const SMDS_MeshElement*& theTria2)
605 if ( !theNode1 || !theNode2 ) return false;
607 theTria1 = theTria2 = 0;
609 set< const SMDS_MeshElement* > emap;
610 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
612 const SMDS_MeshElement* elem = it->next();
613 if ( elem->NbNodes() == 3 )
616 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
618 const SMDS_MeshElement* elem = it->next();
619 if ( emap.find( elem ) != emap.end() )
621 // theTria1 must be element with minimum ID
622 if( theTria1->GetID() < elem->GetID() ) {
635 return ( theTria1 && theTria2 );
638 //=======================================================================
639 //function : InverseDiag
640 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
641 // with ones built on the same 4 nodes but having other common link.
642 // Return false if proper faces not found
643 //=======================================================================
645 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
646 const SMDS_MeshNode * theNode2)
648 myLastCreatedElems.Clear();
649 myLastCreatedNodes.Clear();
651 MESSAGE( "::InverseDiag()" );
653 const SMDS_MeshElement *tr1, *tr2;
654 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
657 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
658 //if (!F1) return false;
659 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
660 //if (!F2) return false;
663 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
664 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
668 // put nodes in array
669 // and find indices of 1,2 and of A in tr1 and of B in tr2
670 int i, iA1 = 0, i1 = 0;
671 const SMDS_MeshNode* aNodes1 [3];
672 SMDS_ElemIteratorPtr it;
673 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
674 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
675 if ( aNodes1[ i ] == theNode1 )
676 iA1 = i; // node A in tr1
677 else if ( aNodes1[ i ] != theNode2 )
681 const SMDS_MeshNode* aNodes2 [3];
682 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
683 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
684 if ( aNodes2[ i ] == theNode2 )
685 iB2 = i; // node B in tr2
686 else if ( aNodes2[ i ] != theNode1 )
690 // nodes 1 and 2 should not be the same
691 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
695 aNodes1[ iA1 ] = aNodes2[ i2 ];
697 aNodes2[ iB2 ] = aNodes1[ i1 ];
699 //MESSAGE( tr1 << tr2 );
701 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
702 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
704 //MESSAGE( tr1 << tr2 );
709 // check case of quadratic faces
710 const SMDS_QuadraticFaceOfNodes* QF1 =
711 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
712 if(!QF1) return false;
713 const SMDS_QuadraticFaceOfNodes* QF2 =
714 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
715 if(!QF2) return false;
716 return InverseDiag(tr1,tr2);
719 //=======================================================================
720 //function : getQuadrangleNodes
721 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
722 // fusion of triangles tr1 and tr2 having shared link on
723 // theNode1 and theNode2
724 //=======================================================================
726 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
727 const SMDS_MeshNode * theNode1,
728 const SMDS_MeshNode * theNode2,
729 const SMDS_MeshElement * tr1,
730 const SMDS_MeshElement * tr2 )
732 if( tr1->NbNodes() != tr2->NbNodes() )
734 // find the 4-th node to insert into tr1
735 const SMDS_MeshNode* n4 = 0;
736 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
738 while ( !n4 && i<3 ) {
739 const SMDS_MeshNode * n = cast2Node( it->next() );
741 bool isDiag = ( n == theNode1 || n == theNode2 );
745 // Make an array of nodes to be in a quadrangle
746 int iNode = 0, iFirstDiag = -1;
747 it = tr1->nodesIterator();
750 const SMDS_MeshNode * n = cast2Node( it->next() );
752 bool isDiag = ( n == theNode1 || n == theNode2 );
754 if ( iFirstDiag < 0 )
756 else if ( iNode - iFirstDiag == 1 )
757 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
759 else if ( n == n4 ) {
760 return false; // tr1 and tr2 should not have all the same nodes
762 theQuadNodes[ iNode++ ] = n;
764 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
765 theQuadNodes[ iNode ] = n4;
770 //=======================================================================
771 //function : DeleteDiag
772 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
773 // with a quadrangle built on the same 4 nodes.
774 // Return false if proper faces not found
775 //=======================================================================
777 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
778 const SMDS_MeshNode * theNode2)
780 myLastCreatedElems.Clear();
781 myLastCreatedNodes.Clear();
783 MESSAGE( "::DeleteDiag()" );
785 const SMDS_MeshElement *tr1, *tr2;
786 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
789 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
790 //if (!F1) return false;
791 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
792 //if (!F2) return false;
795 const SMDS_MeshNode* aNodes [ 4 ];
796 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
799 //MESSAGE( endl << tr1 << tr2 );
801 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
802 myLastCreatedElems.Append(tr1);
803 GetMeshDS()->RemoveElement( tr2 );
805 //MESSAGE( endl << tr1 );
810 // check case of quadratic faces
811 const SMDS_QuadraticFaceOfNodes* QF1 =
812 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
813 if(!QF1) return false;
814 const SMDS_QuadraticFaceOfNodes* QF2 =
815 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
816 if(!QF2) return false;
819 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
820 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
828 const SMDS_MeshNode* N1 [6];
829 const SMDS_MeshNode* N2 [6];
830 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
832 // now we receive following N1 and N2 (using numeration as above image)
833 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
834 // i.e. first nodes from both arrays determ new diagonal
836 const SMDS_MeshNode* aNodes[8];
846 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
847 myLastCreatedElems.Append(tr1);
848 GetMeshDS()->RemoveElement( tr2 );
850 // remove middle node (9)
851 GetMeshDS()->RemoveNode( N1[4] );
856 //=======================================================================
857 //function : Reorient
858 //purpose : Reverse theElement orientation
859 //=======================================================================
861 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
863 myLastCreatedElems.Clear();
864 myLastCreatedNodes.Clear();
868 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
869 if ( !it || !it->more() )
872 switch ( theElem->GetType() ) {
876 if(!theElem->IsQuadratic()) {
877 int i = theElem->NbNodes();
878 vector<const SMDS_MeshNode*> aNodes( i );
880 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
881 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
884 // quadratic elements
885 if(theElem->GetType()==SMDSAbs_Edge) {
886 vector<const SMDS_MeshNode*> aNodes(3);
887 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
888 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
889 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
890 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
893 int nbn = theElem->NbNodes();
894 vector<const SMDS_MeshNode*> aNodes(nbn);
895 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
897 for(; i<nbn/2; i++) {
898 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
900 for(i=0; i<nbn/2; i++) {
901 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
903 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
907 case SMDSAbs_Volume: {
908 if (theElem->IsPoly()) {
909 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
910 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
912 MESSAGE("Warning: bad volumic element");
916 int nbFaces = aPolyedre->NbFaces();
917 vector<const SMDS_MeshNode *> poly_nodes;
918 vector<int> quantities (nbFaces);
920 // reverse each face of the polyedre
921 for (int iface = 1; iface <= nbFaces; iface++) {
922 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
923 quantities[iface - 1] = nbFaceNodes;
925 for (inode = nbFaceNodes; inode >= 1; inode--) {
926 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
927 poly_nodes.push_back(curNode);
931 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
935 SMDS_VolumeTool vTool;
936 if ( !vTool.Set( theElem ))
939 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
948 //=======================================================================
949 //function : getBadRate
951 //=======================================================================
953 static double getBadRate (const SMDS_MeshElement* theElem,
954 SMESH::Controls::NumericalFunctorPtr& theCrit)
956 SMESH::Controls::TSequenceOfXYZ P;
957 if ( !theElem || !theCrit->GetPoints( theElem, P ))
959 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
960 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
963 //=======================================================================
964 //function : QuadToTri
965 //purpose : Cut quadrangles into triangles.
966 // theCrit is used to select a diagonal to cut
967 //=======================================================================
969 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
970 SMESH::Controls::NumericalFunctorPtr theCrit)
972 myLastCreatedElems.Clear();
973 myLastCreatedNodes.Clear();
975 MESSAGE( "::QuadToTri()" );
977 if ( !theCrit.get() )
980 SMESHDS_Mesh * aMesh = GetMeshDS();
982 Handle(Geom_Surface) surface;
983 SMESH_MesherHelper helper( *GetMesh() );
985 TIDSortedElemSet::iterator itElem;
986 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
987 const SMDS_MeshElement* elem = *itElem;
988 if ( !elem || elem->GetType() != SMDSAbs_Face )
990 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
993 // retrieve element nodes
994 const SMDS_MeshNode* aNodes [8];
995 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
997 while ( itN->more() )
998 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1000 // compare two sets of possible triangles
1001 double aBadRate1, aBadRate2; // to what extent a set is bad
1002 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1003 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1004 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1006 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1007 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1008 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1010 int aShapeId = FindShape( elem );
1011 const SMDS_MeshElement* newElem = 0;
1013 if( !elem->IsQuadratic() ) {
1015 // split liner quadrangle
1017 if ( aBadRate1 <= aBadRate2 ) {
1018 // tr1 + tr2 is better
1019 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1020 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1023 // tr3 + tr4 is better
1024 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1025 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1030 // split quadratic quadrangle
1032 // get surface elem is on
1033 if ( aShapeId != helper.GetSubShapeID() ) {
1037 shape = aMesh->IndexToShape( aShapeId );
1038 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1039 TopoDS_Face face = TopoDS::Face( shape );
1040 surface = BRep_Tool::Surface( face );
1041 if ( !surface.IsNull() )
1042 helper.SetSubShape( shape );
1046 const SMDS_MeshNode* aNodes [8];
1047 const SMDS_MeshNode* inFaceNode = 0;
1048 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1050 while ( itN->more() ) {
1051 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1052 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1053 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1055 inFaceNode = aNodes[ i-1 ];
1058 // find middle point for (0,1,2,3)
1059 // and create a node in this point;
1061 if ( surface.IsNull() ) {
1063 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1067 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1070 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1072 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1074 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1075 myLastCreatedNodes.Append(newN);
1077 // create a new element
1078 const SMDS_MeshNode* N[6];
1079 if ( aBadRate1 <= aBadRate2 ) {
1086 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1087 aNodes[6], aNodes[7], newN );
1096 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1097 aNodes[7], aNodes[4], newN );
1099 aMesh->ChangeElementNodes( elem, N, 6 );
1103 // care of a new element
1105 myLastCreatedElems.Append(newElem);
1106 AddToSameGroups( newElem, elem, aMesh );
1108 // put a new triangle on the same shape
1110 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1115 //=======================================================================
1116 //function : BestSplit
1117 //purpose : Find better diagonal for cutting.
1118 //=======================================================================
1120 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1121 SMESH::Controls::NumericalFunctorPtr theCrit)
1123 myLastCreatedElems.Clear();
1124 myLastCreatedNodes.Clear();
1129 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1132 if( theQuad->NbNodes()==4 ||
1133 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1135 // retrieve element nodes
1136 const SMDS_MeshNode* aNodes [4];
1137 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1139 //while (itN->more())
1141 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1143 // compare two sets of possible triangles
1144 double aBadRate1, aBadRate2; // to what extent a set is bad
1145 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1146 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1147 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1149 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1150 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1151 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1153 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1154 return 1; // diagonal 1-3
1156 return 2; // diagonal 2-4
1163 // Methods of splitting volumes into tetra
1165 const int theHexTo5_1[5*4+1] =
1167 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1169 const int theHexTo5_2[5*4+1] =
1171 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1173 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1175 const int theHexTo6_1[6*4+1] =
1177 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
1179 const int theHexTo6_2[6*4+1] =
1181 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
1183 const int theHexTo6_3[6*4+1] =
1185 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
1187 const int theHexTo6_4[6*4+1] =
1189 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
1191 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1193 const int thePyraTo2_1[2*4+1] =
1195 0, 1, 2, 4, 0, 2, 3, 4, -1
1197 const int thePyraTo2_2[2*4+1] =
1199 1, 2, 3, 4, 1, 3, 0, 4, -1
1201 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1203 const int thePentaTo3_1[3*4+1] =
1205 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1207 const int thePentaTo3_2[3*4+1] =
1209 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1211 const int thePentaTo3_3[3*4+1] =
1213 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1215 const int thePentaTo3_4[3*4+1] =
1217 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1219 const int thePentaTo3_5[3*4+1] =
1221 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1223 const int thePentaTo3_6[3*4+1] =
1225 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1227 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1228 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1230 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1233 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1234 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1235 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1240 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1241 bool _baryNode; //!< additional node is to be created at cell barycenter
1242 bool _ownConn; //!< to delete _connectivity in destructor
1244 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1245 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1246 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1247 bool hasFacet( const TTriangleFacet& facet ) const
1249 const int* tetConn = _connectivity;
1250 for ( ; tetConn[0] >= 0; tetConn += 4 )
1251 if (( facet.contains( tetConn[0] ) +
1252 facet.contains( tetConn[1] ) +
1253 facet.contains( tetConn[2] ) +
1254 facet.contains( tetConn[3] )) == 3 )
1260 //=======================================================================
1262 * \brief return TSplitMethod for the given element
1264 //=======================================================================
1266 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1268 int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1270 // Find out how adjacent volumes are split
1272 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1273 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1274 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1276 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1277 maxTetConnSize += 4 * ( nbNodes - 2 );
1278 if ( nbNodes < 4 ) continue;
1280 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1281 const int* nInd = vol.GetFaceNodesIndices( iF );
1284 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1285 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1286 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1287 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1291 int iCom = 0; // common node of triangle faces to split into
1292 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1294 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1295 nInd[ iQ * ( (iCom+1)%nbNodes )],
1296 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1297 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1298 nInd[ iQ * ( (iCom+2)%nbNodes )],
1299 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1300 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1302 triaSplits.push_back( t012 );
1303 triaSplits.push_back( t023 );
1308 if ( !triaSplits.empty() )
1309 hasAdjacentSplits = true;
1312 // Among variants of split method select one compliant with adjacent volumes
1314 TSplitMethod method;
1315 if ( !vol.Element()->IsPoly() )
1317 int nbVariants = 2, nbTet = 0;
1318 const int** connVariants = 0;
1319 switch ( vol.Element()->GetEntityType() )
1321 case SMDSEntity_Hexa:
1322 case SMDSEntity_Quad_Hexa:
1323 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1324 connVariants = theHexTo5, nbTet = 5;
1326 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1328 case SMDSEntity_Pyramid:
1329 case SMDSEntity_Quad_Pyramid:
1330 connVariants = thePyraTo2; nbTet = 2;
1332 case SMDSEntity_Penta:
1333 case SMDSEntity_Quad_Penta:
1334 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1339 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1341 // check method compliancy with adjacent tetras,
1342 // all found splits must be among facets of tetras described by this method
1343 method = TSplitMethod( nbTet, connVariants[variant] );
1344 if ( hasAdjacentSplits && method._nbTetra > 0 )
1346 bool facetCreated = true;
1347 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1349 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1350 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1351 facetCreated = method.hasFacet( *facet );
1353 if ( !facetCreated )
1354 method = TSplitMethod(0); // incompatible method
1358 if ( method._nbTetra < 1 )
1360 // No standard method is applicable, use a generic solution:
1361 // each facet of a volume is split into triangles and
1362 // each of triangles and a volume barycenter form a tetrahedron.
1364 int* connectivity = new int[ maxTetConnSize + 1 ];
1365 method._connectivity = connectivity;
1366 method._ownConn = true;
1367 method._baryNode = true;
1370 int baryCenInd = vol.NbNodes();
1371 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1373 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1374 const int* nInd = vol.GetFaceNodesIndices( iF );
1375 // find common node of triangle facets of tetra to create
1376 int iCommon = 0; // index in linear numeration
1377 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1378 if ( !triaSplits.empty() )
1381 const TTriangleFacet* facet = &triaSplits.front();
1382 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1383 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1384 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1387 else if ( nbNodes > 3 )
1389 // find the best method of splitting into triangles by aspect ratio
1390 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1391 map< double, int > badness2iCommon;
1392 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1393 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1394 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1395 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1397 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1398 nodes[ iQ*((iLast-1)%nbNodes)],
1399 nodes[ iQ*((iLast )%nbNodes)]);
1400 double badness = getBadRate( &tria, aspectRatio );
1401 badness2iCommon.insert( make_pair( badness, iCommon ));
1403 // use iCommon with lowest badness
1404 iCommon = badness2iCommon.begin()->second;
1406 if ( iCommon >= nbNodes )
1407 iCommon = 0; // something wrong
1408 // fill connectivity of tetra
1409 int nbTet = nbNodes - 2;
1410 for ( int i = 0; i < nbTet; ++i )
1412 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1413 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1414 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1415 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1416 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1417 connectivity[ connSize++ ] = baryCenInd;
1421 connectivity[ connSize++ ] = -1;
1425 //================================================================================
1427 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1429 //================================================================================
1431 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1433 // find the tetrahedron including the three nodes of facet
1434 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1435 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1436 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1437 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1438 while ( volIt1->more() )
1440 const SMDS_MeshElement* v = volIt1->next();
1441 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1443 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1444 while ( volIt2->more() )
1445 if ( v != volIt2->next() )
1447 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1448 while ( volIt3->more() )
1449 if ( v == volIt3->next() )
1456 //=======================================================================
1457 //function : SplitVolumesIntoTetra
1458 //purpose : Split volumic elements into tetrahedra.
1459 //=======================================================================
1461 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1462 const int theMethodFlags)
1464 // std-like iterator on coordinates of nodes of mesh element
1465 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1466 NXyzIterator xyzEnd;
1468 SMDS_VolumeTool volTool;
1469 SMESH_MesherHelper helper( *GetMesh());
1471 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1472 SMESHDS_SubMesh* fSubMesh = subMesh;
1474 SMESH_SequenceOfElemPtr newNodes, newElems;
1476 TIDSortedElemSet::const_iterator elem = theElems.begin();
1477 for ( ; elem != theElems.end(); ++elem )
1479 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1480 if ( geomType <= SMDSEntity_Quad_Tetra )
1481 continue; // tetra or face or ...
1483 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1485 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1486 if ( splitMethod._nbTetra < 1 ) continue;
1488 // find submesh to add new tetras in
1489 if ( !subMesh || !subMesh->Contains( *elem ))
1491 int shapeID = FindShape( *elem );
1492 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1493 subMesh = GetMeshDS()->MeshElements( shapeID );
1496 if ( (*elem)->IsQuadratic() )
1499 // add quadratic links to the helper
1500 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1502 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1503 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1504 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1506 helper.SetIsQuadratic( true );
1511 helper.SetIsQuadratic( false );
1513 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1514 if ( splitMethod._baryNode )
1516 // make a node at barycenter
1518 gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1519 SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1520 nodes.push_back( gcNode );
1521 newNodes.Append( gcNode );
1525 helper.SetElementsOnShape( true );
1526 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1527 const int* tetConn = splitMethod._connectivity;
1528 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1529 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1530 nodes[ tetConn[1] ],
1531 nodes[ tetConn[2] ],
1532 nodes[ tetConn[3] ]));
1534 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1536 // Split faces on sides of the split volume
1538 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1539 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1541 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1542 if ( nbNodes < 4 ) continue;
1544 // find an existing face
1545 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1546 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1547 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1549 // among possible triangles create ones discribed by split method
1550 const int* nInd = volTool.GetFaceNodesIndices( iF );
1551 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1552 int iCom = 0; // common node of triangle faces to split into
1553 list< TTriangleFacet > facets;
1554 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1556 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1557 nInd[ iQ * ( (iCom+1)%nbNodes )],
1558 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1559 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1560 nInd[ iQ * ( (iCom+2)%nbNodes )],
1561 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1562 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1564 facets.push_back( t012 );
1565 facets.push_back( t023 );
1566 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1567 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1568 nInd[ iQ * ((iLast-1)%nbNodes )],
1569 nInd[ iQ * ((iLast )%nbNodes )]));
1573 // find submesh to add new faces in
1574 if ( !fSubMesh || !fSubMesh->Contains( face ))
1576 int shapeID = FindShape( face );
1577 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1580 helper.SetElementsOnShape( false );
1581 vector< const SMDS_MeshElement* > triangles;
1582 list< TTriangleFacet >::iterator facet = facets.begin();
1583 for ( ; facet != facets.end(); ++facet )
1585 if ( !volTool.IsFaceExternal( iF ))
1586 swap( facet->_n2, facet->_n3 );
1587 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1588 volNodes[ facet->_n2 ],
1589 volNodes[ facet->_n3 ]));
1590 if ( triangles.back() && fSubMesh )
1591 fSubMesh->AddElement( triangles.back());
1592 newElems.Append( triangles.back() );
1594 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1595 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1598 } // loop on volume faces to split them into triangles
1600 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1602 } // loop on volumes to split
1604 myLastCreatedNodes = newNodes;
1605 myLastCreatedElems = newElems;
1608 //=======================================================================
1609 //function : AddToSameGroups
1610 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1611 //=======================================================================
1613 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1614 const SMDS_MeshElement* elemInGroups,
1615 SMESHDS_Mesh * aMesh)
1617 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1618 if (!groups.empty()) {
1619 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1620 for ( ; grIt != groups.end(); grIt++ ) {
1621 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1622 if ( group && group->Contains( elemInGroups ))
1623 group->SMDSGroup().Add( elemToAdd );
1629 //=======================================================================
1630 //function : RemoveElemFromGroups
1631 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1632 //=======================================================================
1633 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1634 SMESHDS_Mesh * aMesh)
1636 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1637 if (!groups.empty())
1639 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1640 for (; GrIt != groups.end(); GrIt++)
1642 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1643 if (!grp || grp->IsEmpty()) continue;
1644 grp->SMDSGroup().Remove(removeelem);
1649 //================================================================================
1651 * \brief Replace elemToRm by elemToAdd in the all groups
1653 //================================================================================
1655 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1656 const SMDS_MeshElement* elemToAdd,
1657 SMESHDS_Mesh * aMesh)
1659 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1660 if (!groups.empty()) {
1661 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1662 for ( ; grIt != groups.end(); grIt++ ) {
1663 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1664 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1665 group->SMDSGroup().Add( elemToAdd );
1670 //================================================================================
1672 * \brief Replace elemToRm by elemToAdd in the all groups
1674 //================================================================================
1676 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1677 const vector<const SMDS_MeshElement*>& elemToAdd,
1678 SMESHDS_Mesh * aMesh)
1680 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1681 if (!groups.empty())
1683 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1684 for ( ; grIt != groups.end(); grIt++ ) {
1685 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1686 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1687 for ( int i = 0; i < elemToAdd.size(); ++i )
1688 group->SMDSGroup().Add( elemToAdd[ i ] );
1693 //=======================================================================
1694 //function : QuadToTri
1695 //purpose : Cut quadrangles into triangles.
1696 // theCrit is used to select a diagonal to cut
1697 //=======================================================================
1699 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1700 const bool the13Diag)
1702 myLastCreatedElems.Clear();
1703 myLastCreatedNodes.Clear();
1705 MESSAGE( "::QuadToTri()" );
1707 SMESHDS_Mesh * aMesh = GetMeshDS();
1709 Handle(Geom_Surface) surface;
1710 SMESH_MesherHelper helper( *GetMesh() );
1712 TIDSortedElemSet::iterator itElem;
1713 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1714 const SMDS_MeshElement* elem = *itElem;
1715 if ( !elem || elem->GetType() != SMDSAbs_Face )
1717 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1718 if(!isquad) continue;
1720 if(elem->NbNodes()==4) {
1721 // retrieve element nodes
1722 const SMDS_MeshNode* aNodes [4];
1723 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1725 while ( itN->more() )
1726 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1728 int aShapeId = FindShape( elem );
1729 const SMDS_MeshElement* newElem = 0;
1731 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1732 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1735 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1736 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1738 myLastCreatedElems.Append(newElem);
1739 // put a new triangle on the same shape and add to the same groups
1741 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1742 AddToSameGroups( newElem, elem, aMesh );
1745 // Quadratic quadrangle
1747 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1749 // get surface elem is on
1750 int aShapeId = FindShape( elem );
1751 if ( aShapeId != helper.GetSubShapeID() ) {
1755 shape = aMesh->IndexToShape( aShapeId );
1756 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1757 TopoDS_Face face = TopoDS::Face( shape );
1758 surface = BRep_Tool::Surface( face );
1759 if ( !surface.IsNull() )
1760 helper.SetSubShape( shape );
1764 const SMDS_MeshNode* aNodes [8];
1765 const SMDS_MeshNode* inFaceNode = 0;
1766 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1768 while ( itN->more() ) {
1769 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1770 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1771 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1773 inFaceNode = aNodes[ i-1 ];
1777 // find middle point for (0,1,2,3)
1778 // and create a node in this point;
1780 if ( surface.IsNull() ) {
1782 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1786 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1789 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1791 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1793 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1794 myLastCreatedNodes.Append(newN);
1796 // create a new element
1797 const SMDS_MeshElement* newElem = 0;
1798 const SMDS_MeshNode* N[6];
1806 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1807 aNodes[6], aNodes[7], newN );
1816 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1817 aNodes[7], aNodes[4], newN );
1819 myLastCreatedElems.Append(newElem);
1820 aMesh->ChangeElementNodes( elem, N, 6 );
1821 // put a new triangle on the same shape and add to the same groups
1823 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1824 AddToSameGroups( newElem, elem, aMesh );
1831 //=======================================================================
1832 //function : getAngle
1834 //=======================================================================
1836 double getAngle(const SMDS_MeshElement * tr1,
1837 const SMDS_MeshElement * tr2,
1838 const SMDS_MeshNode * n1,
1839 const SMDS_MeshNode * n2)
1841 double angle = 2*PI; // bad angle
1844 SMESH::Controls::TSequenceOfXYZ P1, P2;
1845 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1846 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1849 if(!tr1->IsQuadratic())
1850 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1852 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1853 if ( N1.SquareMagnitude() <= gp::Resolution() )
1855 if(!tr2->IsQuadratic())
1856 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1858 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1859 if ( N2.SquareMagnitude() <= gp::Resolution() )
1862 // find the first diagonal node n1 in the triangles:
1863 // take in account a diagonal link orientation
1864 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1865 for ( int t = 0; t < 2; t++ ) {
1866 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1867 int i = 0, iDiag = -1;
1868 while ( it->more()) {
1869 const SMDS_MeshElement *n = it->next();
1870 if ( n == n1 || n == n2 )
1874 if ( i - iDiag == 1 )
1875 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1883 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1886 angle = N1.Angle( N2 );
1891 // =================================================
1892 // class generating a unique ID for a pair of nodes
1893 // and able to return nodes by that ID
1894 // =================================================
1898 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1899 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1902 long GetLinkID (const SMDS_MeshNode * n1,
1903 const SMDS_MeshNode * n2) const
1905 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1908 bool GetNodes (const long theLinkID,
1909 const SMDS_MeshNode* & theNode1,
1910 const SMDS_MeshNode* & theNode2) const
1912 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1913 if ( !theNode1 ) return false;
1914 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1915 if ( !theNode2 ) return false;
1921 const SMESHDS_Mesh* myMesh;
1926 //=======================================================================
1927 //function : TriToQuad
1928 //purpose : Fuse neighbour triangles into quadrangles.
1929 // theCrit is used to select a neighbour to fuse with.
1930 // theMaxAngle is a max angle between element normals at which
1931 // fusion is still performed.
1932 //=======================================================================
1934 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1935 SMESH::Controls::NumericalFunctorPtr theCrit,
1936 const double theMaxAngle)
1938 myLastCreatedElems.Clear();
1939 myLastCreatedNodes.Clear();
1941 MESSAGE( "::TriToQuad()" );
1943 if ( !theCrit.get() )
1946 SMESHDS_Mesh * aMesh = GetMeshDS();
1948 // Prepare data for algo: build
1949 // 1. map of elements with their linkIDs
1950 // 2. map of linkIDs with their elements
1952 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1953 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1954 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1955 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1957 TIDSortedElemSet::iterator itElem;
1958 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1959 const SMDS_MeshElement* elem = *itElem;
1960 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1961 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1962 if(!IsTria) continue;
1964 // retrieve element nodes
1965 const SMDS_MeshNode* aNodes [4];
1966 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1969 aNodes[ i++ ] = cast2Node( itN->next() );
1970 aNodes[ 3 ] = aNodes[ 0 ];
1973 for ( i = 0; i < 3; i++ ) {
1974 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1975 // check if elements sharing a link can be fused
1976 itLE = mapLi_listEl.find( link );
1977 if ( itLE != mapLi_listEl.end() ) {
1978 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1980 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1981 //if ( FindShape( elem ) != FindShape( elem2 ))
1982 // continue; // do not fuse triangles laying on different shapes
1983 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1984 continue; // avoid making badly shaped quads
1985 (*itLE).second.push_back( elem );
1988 mapLi_listEl[ link ].push_back( elem );
1990 mapEl_setLi [ elem ].insert( link );
1993 // Clean the maps from the links shared by a sole element, ie
1994 // links to which only one element is bound in mapLi_listEl
1996 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1997 int nbElems = (*itLE).second.size();
1998 if ( nbElems < 2 ) {
1999 const SMDS_MeshElement* elem = (*itLE).second.front();
2000 SMESH_TLink link = (*itLE).first;
2001 mapEl_setLi[ elem ].erase( link );
2002 if ( mapEl_setLi[ elem ].empty() )
2003 mapEl_setLi.erase( elem );
2007 // Algo: fuse triangles into quadrangles
2009 while ( ! mapEl_setLi.empty() ) {
2010 // Look for the start element:
2011 // the element having the least nb of shared links
2012 const SMDS_MeshElement* startElem = 0;
2014 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2015 int nbLinks = (*itEL).second.size();
2016 if ( nbLinks < minNbLinks ) {
2017 startElem = (*itEL).first;
2018 minNbLinks = nbLinks;
2019 if ( minNbLinks == 1 )
2024 // search elements to fuse starting from startElem or links of elements
2025 // fused earlyer - startLinks
2026 list< SMESH_TLink > startLinks;
2027 while ( startElem || !startLinks.empty() ) {
2028 while ( !startElem && !startLinks.empty() ) {
2029 // Get an element to start, by a link
2030 SMESH_TLink linkId = startLinks.front();
2031 startLinks.pop_front();
2032 itLE = mapLi_listEl.find( linkId );
2033 if ( itLE != mapLi_listEl.end() ) {
2034 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2035 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2036 for ( ; itE != listElem.end() ; itE++ )
2037 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2039 mapLi_listEl.erase( itLE );
2044 // Get candidates to be fused
2045 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2046 const SMESH_TLink *link12, *link13;
2048 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2049 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2050 ASSERT( !setLi.empty() );
2051 set< SMESH_TLink >::iterator itLi;
2052 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2054 const SMESH_TLink & link = (*itLi);
2055 itLE = mapLi_listEl.find( link );
2056 if ( itLE == mapLi_listEl.end() )
2059 const SMDS_MeshElement* elem = (*itLE).second.front();
2061 elem = (*itLE).second.back();
2062 mapLi_listEl.erase( itLE );
2063 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2074 // add other links of elem to list of links to re-start from
2075 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2076 set< SMESH_TLink >::iterator it;
2077 for ( it = links.begin(); it != links.end(); it++ ) {
2078 const SMESH_TLink& link2 = (*it);
2079 if ( link2 != link )
2080 startLinks.push_back( link2 );
2084 // Get nodes of possible quadrangles
2085 const SMDS_MeshNode *n12 [4], *n13 [4];
2086 bool Ok12 = false, Ok13 = false;
2087 const SMDS_MeshNode *linkNode1, *linkNode2;
2089 linkNode1 = link12->first;
2090 linkNode2 = link12->second;
2091 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2095 linkNode1 = link13->first;
2096 linkNode2 = link13->second;
2097 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2101 // Choose a pair to fuse
2102 if ( Ok12 && Ok13 ) {
2103 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2104 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2105 double aBadRate12 = getBadRate( &quad12, theCrit );
2106 double aBadRate13 = getBadRate( &quad13, theCrit );
2107 if ( aBadRate13 < aBadRate12 )
2114 // and remove fused elems and removed links from the maps
2115 mapEl_setLi.erase( tr1 );
2117 mapEl_setLi.erase( tr2 );
2118 mapLi_listEl.erase( *link12 );
2119 if(tr1->NbNodes()==3) {
2120 if( tr1->GetID() < tr2->GetID() ) {
2121 aMesh->ChangeElementNodes( tr1, n12, 4 );
2122 myLastCreatedElems.Append(tr1);
2123 aMesh->RemoveElement( tr2 );
2126 aMesh->ChangeElementNodes( tr2, n12, 4 );
2127 myLastCreatedElems.Append(tr2);
2128 aMesh->RemoveElement( tr1);
2132 const SMDS_MeshNode* N1 [6];
2133 const SMDS_MeshNode* N2 [6];
2134 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2135 // now we receive following N1 and N2 (using numeration as above image)
2136 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2137 // i.e. first nodes from both arrays determ new diagonal
2138 const SMDS_MeshNode* aNodes[8];
2147 if( tr1->GetID() < tr2->GetID() ) {
2148 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2149 myLastCreatedElems.Append(tr1);
2150 GetMeshDS()->RemoveElement( tr2 );
2153 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2154 myLastCreatedElems.Append(tr2);
2155 GetMeshDS()->RemoveElement( tr1 );
2157 // remove middle node (9)
2158 GetMeshDS()->RemoveNode( N1[4] );
2162 mapEl_setLi.erase( tr3 );
2163 mapLi_listEl.erase( *link13 );
2164 if(tr1->NbNodes()==3) {
2165 if( tr1->GetID() < tr2->GetID() ) {
2166 aMesh->ChangeElementNodes( tr1, n13, 4 );
2167 myLastCreatedElems.Append(tr1);
2168 aMesh->RemoveElement( tr3 );
2171 aMesh->ChangeElementNodes( tr3, n13, 4 );
2172 myLastCreatedElems.Append(tr3);
2173 aMesh->RemoveElement( tr1 );
2177 const SMDS_MeshNode* N1 [6];
2178 const SMDS_MeshNode* N2 [6];
2179 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2180 // now we receive following N1 and N2 (using numeration as above image)
2181 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2182 // i.e. first nodes from both arrays determ new diagonal
2183 const SMDS_MeshNode* aNodes[8];
2192 if( tr1->GetID() < tr2->GetID() ) {
2193 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2194 myLastCreatedElems.Append(tr1);
2195 GetMeshDS()->RemoveElement( tr3 );
2198 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2199 myLastCreatedElems.Append(tr3);
2200 GetMeshDS()->RemoveElement( tr1 );
2202 // remove middle node (9)
2203 GetMeshDS()->RemoveNode( N1[4] );
2207 // Next element to fuse: the rejected one
2209 startElem = Ok12 ? tr3 : tr2;
2211 } // if ( startElem )
2212 } // while ( startElem || !startLinks.empty() )
2213 } // while ( ! mapEl_setLi.empty() )
2219 /*#define DUMPSO(txt) \
2220 // cout << txt << endl;
2221 //=============================================================================
2225 //=============================================================================
2226 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2230 int tmp = idNodes[ i1 ];
2231 idNodes[ i1 ] = idNodes[ i2 ];
2232 idNodes[ i2 ] = tmp;
2233 gp_Pnt Ptmp = P[ i1 ];
2236 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2239 //=======================================================================
2240 //function : SortQuadNodes
2241 //purpose : Set 4 nodes of a quadrangle face in a good order.
2242 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2244 //=======================================================================
2246 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2251 for ( i = 0; i < 4; i++ ) {
2252 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2254 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2257 gp_Vec V1(P[0], P[1]);
2258 gp_Vec V2(P[0], P[2]);
2259 gp_Vec V3(P[0], P[3]);
2261 gp_Vec Cross1 = V1 ^ V2;
2262 gp_Vec Cross2 = V2 ^ V3;
2265 if (Cross1.Dot(Cross2) < 0)
2270 if (Cross1.Dot(Cross2) < 0)
2274 swap ( i, i + 1, idNodes, P );
2276 // for ( int ii = 0; ii < 4; ii++ ) {
2277 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2278 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2284 //=======================================================================
2285 //function : SortHexaNodes
2286 //purpose : Set 8 nodes of a hexahedron in a good order.
2287 // Return success status
2288 //=======================================================================
2290 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2295 DUMPSO( "INPUT: ========================================");
2296 for ( i = 0; i < 8; i++ ) {
2297 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2298 if ( !n ) return false;
2299 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2300 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2302 DUMPSO( "========================================");
2305 set<int> faceNodes; // ids of bottom face nodes, to be found
2306 set<int> checkedId1; // ids of tried 2-nd nodes
2307 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2308 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2309 int iMin, iLoop1 = 0;
2311 // Loop to try the 2-nd nodes
2313 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2315 // Find not checked 2-nd node
2316 for ( i = 1; i < 8; i++ )
2317 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2318 int id1 = idNodes[i];
2319 swap ( 1, i, idNodes, P );
2320 checkedId1.insert ( id1 );
2324 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2325 // ie that all but meybe one (id3 which is on the same face) nodes
2326 // lay on the same side from the triangle plane.
2328 bool manyInPlane = false; // more than 4 nodes lay in plane
2330 while ( ++iLoop2 < 6 ) {
2332 // get 1-2-3 plane coeffs
2333 Standard_Real A, B, C, D;
2334 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2335 if ( N.SquareMagnitude() > gp::Resolution() )
2337 gp_Pln pln ( P[0], N );
2338 pln.Coefficients( A, B, C, D );
2340 // find the node (iMin) closest to pln
2341 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2343 for ( i = 3; i < 8; i++ ) {
2344 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2345 if ( fabs( dist[i] ) < minDist ) {
2346 minDist = fabs( dist[i] );
2349 if ( fabs( dist[i] ) <= tol )
2350 idInPln.insert( idNodes[i] );
2353 // there should not be more than 4 nodes in bottom plane
2354 if ( idInPln.size() > 1 )
2356 DUMPSO( "### idInPln.size() = " << idInPln.size());
2357 // idInPlane does not contain the first 3 nodes
2358 if ( manyInPlane || idInPln.size() == 5)
2359 return false; // all nodes in one plane
2362 // set the 1-st node to be not in plane
2363 for ( i = 3; i < 8; i++ ) {
2364 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2365 DUMPSO( "### Reset 0-th node");
2366 swap( 0, i, idNodes, P );
2371 // reset to re-check second nodes
2372 leastDist = DBL_MAX;
2376 break; // from iLoop2;
2379 // check that the other 4 nodes are on the same side
2380 bool sameSide = true;
2381 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2382 for ( i = 3; sameSide && i < 8; i++ ) {
2384 sameSide = ( isNeg == dist[i] <= 0.);
2387 // keep best solution
2388 if ( sameSide && minDist < leastDist ) {
2389 leastDist = minDist;
2391 faceNodes.insert( idNodes[ 1 ] );
2392 faceNodes.insert( idNodes[ 2 ] );
2393 faceNodes.insert( idNodes[ iMin ] );
2394 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2395 << " leastDist = " << leastDist);
2396 if ( leastDist <= DBL_MIN )
2401 // set next 3-d node to check
2402 int iNext = 2 + iLoop2;
2404 DUMPSO( "Try 2-nd");
2405 swap ( 2, iNext, idNodes, P );
2407 } // while ( iLoop2 < 6 )
2410 if ( faceNodes.empty() ) return false;
2412 // Put the faceNodes in proper places
2413 for ( i = 4; i < 8; i++ ) {
2414 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2415 // find a place to put
2417 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2419 DUMPSO( "Set faceNodes");
2420 swap ( iTo, i, idNodes, P );
2425 // Set nodes of the found bottom face in good order
2426 DUMPSO( " Found bottom face: ");
2427 i = SortQuadNodes( theMesh, idNodes );
2429 gp_Pnt Ptmp = P[ i ];
2434 // for ( int ii = 0; ii < 4; ii++ ) {
2435 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2436 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2439 // Gravity center of the top and bottom faces
2440 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2441 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2443 // Get direction from the bottom to the top face
2444 gp_Vec upDir ( aGCb, aGCt );
2445 Standard_Real upDirSize = upDir.Magnitude();
2446 if ( upDirSize <= gp::Resolution() ) return false;
2449 // Assure that the bottom face normal points up
2450 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2451 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2452 if ( Nb.Dot( upDir ) < 0 ) {
2453 DUMPSO( "Reverse bottom face");
2454 swap( 1, 3, idNodes, P );
2457 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2458 Standard_Real minDist = DBL_MAX;
2459 for ( i = 4; i < 8; i++ ) {
2460 // projection of P[i] to the plane defined by P[0] and upDir
2461 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2462 Standard_Real sqDist = P[0].SquareDistance( Pp );
2463 if ( sqDist < minDist ) {
2468 DUMPSO( "Set 4-th");
2469 swap ( 4, iMin, idNodes, P );
2471 // Set nodes of the top face in good order
2472 DUMPSO( "Sort top face");
2473 i = SortQuadNodes( theMesh, &idNodes[4] );
2476 gp_Pnt Ptmp = P[ i ];
2481 // Assure that direction of the top face normal is from the bottom face
2482 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2483 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2484 if ( Nt.Dot( upDir ) < 0 ) {
2485 DUMPSO( "Reverse top face");
2486 swap( 5, 7, idNodes, P );
2489 // DUMPSO( "OUTPUT: ========================================");
2490 // for ( i = 0; i < 8; i++ ) {
2491 // float *p = ugrid->GetPoint(idNodes[i]);
2492 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2498 //================================================================================
2500 * \brief Return nodes linked to the given one
2501 * \param theNode - the node
2502 * \param linkedNodes - the found nodes
2503 * \param type - the type of elements to check
2505 * Medium nodes are ignored
2507 //================================================================================
2509 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2510 TIDSortedElemSet & linkedNodes,
2511 SMDSAbs_ElementType type )
2513 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2514 while ( elemIt->more() )
2516 const SMDS_MeshElement* elem = elemIt->next();
2517 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2518 if ( elem->GetType() == SMDSAbs_Volume )
2520 SMDS_VolumeTool vol( elem );
2521 while ( nodeIt->more() ) {
2522 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2523 if ( theNode != n && vol.IsLinked( theNode, n ))
2524 linkedNodes.insert( n );
2529 for ( int i = 0; nodeIt->more(); ++i ) {
2530 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2531 if ( n == theNode ) {
2532 int iBefore = i - 1;
2534 if ( elem->IsQuadratic() ) {
2535 int nb = elem->NbNodes() / 2;
2536 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2537 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2539 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2540 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2547 //=======================================================================
2548 //function : laplacianSmooth
2549 //purpose : pulls theNode toward the center of surrounding nodes directly
2550 // connected to that node along an element edge
2551 //=======================================================================
2553 void laplacianSmooth(const SMDS_MeshNode* theNode,
2554 const Handle(Geom_Surface)& theSurface,
2555 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2557 // find surrounding nodes
2559 TIDSortedElemSet nodeSet;
2560 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2562 // compute new coodrs
2564 double coord[] = { 0., 0., 0. };
2565 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2566 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2567 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2568 if ( theSurface.IsNull() ) { // smooth in 3D
2569 coord[0] += node->X();
2570 coord[1] += node->Y();
2571 coord[2] += node->Z();
2573 else { // smooth in 2D
2574 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2575 gp_XY* uv = theUVMap[ node ];
2576 coord[0] += uv->X();
2577 coord[1] += uv->Y();
2580 int nbNodes = nodeSet.size();
2583 coord[0] /= nbNodes;
2584 coord[1] /= nbNodes;
2586 if ( !theSurface.IsNull() ) {
2587 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2588 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2589 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2595 coord[2] /= nbNodes;
2599 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2602 //=======================================================================
2603 //function : centroidalSmooth
2604 //purpose : pulls theNode toward the element-area-weighted centroid of the
2605 // surrounding elements
2606 //=======================================================================
2608 void centroidalSmooth(const SMDS_MeshNode* theNode,
2609 const Handle(Geom_Surface)& theSurface,
2610 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2612 gp_XYZ aNewXYZ(0.,0.,0.);
2613 SMESH::Controls::Area anAreaFunc;
2614 double totalArea = 0.;
2619 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2620 while ( elemIt->more() )
2622 const SMDS_MeshElement* elem = elemIt->next();
2625 gp_XYZ elemCenter(0.,0.,0.);
2626 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2627 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2628 int nn = elem->NbNodes();
2629 if(elem->IsQuadratic()) nn = nn/2;
2631 //while ( itN->more() ) {
2633 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2635 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2636 aNodePoints.push_back( aP );
2637 if ( !theSurface.IsNull() ) { // smooth in 2D
2638 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2639 gp_XY* uv = theUVMap[ aNode ];
2640 aP.SetCoord( uv->X(), uv->Y(), 0. );
2644 double elemArea = anAreaFunc.GetValue( aNodePoints );
2645 totalArea += elemArea;
2647 aNewXYZ += elemCenter * elemArea;
2649 aNewXYZ /= totalArea;
2650 if ( !theSurface.IsNull() ) {
2651 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2652 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2657 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2660 //=======================================================================
2661 //function : getClosestUV
2662 //purpose : return UV of closest projection
2663 //=======================================================================
2665 static bool getClosestUV (Extrema_GenExtPS& projector,
2666 const gp_Pnt& point,
2669 projector.Perform( point );
2670 if ( projector.IsDone() ) {
2671 double u, v, minVal = DBL_MAX;
2672 for ( int i = projector.NbExt(); i > 0; i-- )
2673 if ( projector.Value( i ) < minVal ) {
2674 minVal = projector.Value( i );
2675 projector.Point( i ).Parameter( u, v );
2677 result.SetCoord( u, v );
2683 //=======================================================================
2685 //purpose : Smooth theElements during theNbIterations or until a worst
2686 // element has aspect ratio <= theTgtAspectRatio.
2687 // Aspect Ratio varies in range [1.0, inf].
2688 // If theElements is empty, the whole mesh is smoothed.
2689 // theFixedNodes contains additionally fixed nodes. Nodes built
2690 // on edges and boundary nodes are always fixed.
2691 //=======================================================================
2693 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2694 set<const SMDS_MeshNode*> & theFixedNodes,
2695 const SmoothMethod theSmoothMethod,
2696 const int theNbIterations,
2697 double theTgtAspectRatio,
2700 myLastCreatedElems.Clear();
2701 myLastCreatedNodes.Clear();
2703 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2705 if ( theTgtAspectRatio < 1.0 )
2706 theTgtAspectRatio = 1.0;
2708 const double disttol = 1.e-16;
2710 SMESH::Controls::AspectRatio aQualityFunc;
2712 SMESHDS_Mesh* aMesh = GetMeshDS();
2714 if ( theElems.empty() ) {
2715 // add all faces to theElems
2716 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2717 while ( fIt->more() ) {
2718 const SMDS_MeshElement* face = fIt->next();
2719 theElems.insert( face );
2722 // get all face ids theElems are on
2723 set< int > faceIdSet;
2724 TIDSortedElemSet::iterator itElem;
2726 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2727 int fId = FindShape( *itElem );
2728 // check that corresponding submesh exists and a shape is face
2730 faceIdSet.find( fId ) == faceIdSet.end() &&
2731 aMesh->MeshElements( fId )) {
2732 TopoDS_Shape F = aMesh->IndexToShape( fId );
2733 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2734 faceIdSet.insert( fId );
2737 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2739 // ===============================================
2740 // smooth elements on each TopoDS_Face separately
2741 // ===============================================
2743 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2744 for ( ; fId != faceIdSet.rend(); ++fId ) {
2745 // get face surface and submesh
2746 Handle(Geom_Surface) surface;
2747 SMESHDS_SubMesh* faceSubMesh = 0;
2749 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2750 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2751 bool isUPeriodic = false, isVPeriodic = false;
2753 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2754 surface = BRep_Tool::Surface( face );
2755 faceSubMesh = aMesh->MeshElements( *fId );
2756 fToler2 = BRep_Tool::Tolerance( face );
2757 fToler2 *= fToler2 * 10.;
2758 isUPeriodic = surface->IsUPeriodic();
2760 vPeriod = surface->UPeriod();
2761 isVPeriodic = surface->IsVPeriodic();
2763 uPeriod = surface->VPeriod();
2764 surface->Bounds( u1, u2, v1, v2 );
2766 // ---------------------------------------------------------
2767 // for elements on a face, find movable and fixed nodes and
2768 // compute UV for them
2769 // ---------------------------------------------------------
2770 bool checkBoundaryNodes = false;
2771 bool isQuadratic = false;
2772 set<const SMDS_MeshNode*> setMovableNodes;
2773 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2774 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2775 list< const SMDS_MeshElement* > elemsOnFace;
2777 Extrema_GenExtPS projector;
2778 GeomAdaptor_Surface surfAdaptor;
2779 if ( !surface.IsNull() ) {
2780 surfAdaptor.Load( surface );
2781 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2783 int nbElemOnFace = 0;
2784 itElem = theElems.begin();
2785 // loop on not yet smoothed elements: look for elems on a face
2786 while ( itElem != theElems.end() ) {
2787 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2788 break; // all elements found
2790 const SMDS_MeshElement* elem = *itElem;
2791 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2792 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2796 elemsOnFace.push_back( elem );
2797 theElems.erase( itElem++ );
2801 isQuadratic = elem->IsQuadratic();
2803 // get movable nodes of elem
2804 const SMDS_MeshNode* node;
2805 SMDS_TypeOfPosition posType;
2806 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2807 int nn = 0, nbn = elem->NbNodes();
2808 if(elem->IsQuadratic())
2810 while ( nn++ < nbn ) {
2811 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2812 const SMDS_PositionPtr& pos = node->GetPosition();
2813 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2814 if (posType != SMDS_TOP_EDGE &&
2815 posType != SMDS_TOP_VERTEX &&
2816 theFixedNodes.find( node ) == theFixedNodes.end())
2818 // check if all faces around the node are on faceSubMesh
2819 // because a node on edge may be bound to face
2820 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2822 if ( faceSubMesh ) {
2823 while ( eIt->more() && all ) {
2824 const SMDS_MeshElement* e = eIt->next();
2825 all = faceSubMesh->Contains( e );
2829 setMovableNodes.insert( node );
2831 checkBoundaryNodes = true;
2833 if ( posType == SMDS_TOP_3DSPACE )
2834 checkBoundaryNodes = true;
2837 if ( surface.IsNull() )
2840 // get nodes to check UV
2841 list< const SMDS_MeshNode* > uvCheckNodes;
2842 itN = elem->nodesIterator();
2843 nn = 0; nbn = elem->NbNodes();
2844 if(elem->IsQuadratic())
2846 while ( nn++ < nbn ) {
2847 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2848 if ( uvMap.find( node ) == uvMap.end() )
2849 uvCheckNodes.push_back( node );
2850 // add nodes of elems sharing node
2851 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2852 // while ( eIt->more() ) {
2853 // const SMDS_MeshElement* e = eIt->next();
2854 // if ( e != elem ) {
2855 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2856 // while ( nIt->more() ) {
2857 // const SMDS_MeshNode* n =
2858 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2859 // if ( uvMap.find( n ) == uvMap.end() )
2860 // uvCheckNodes.push_back( n );
2866 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2867 for ( ; n != uvCheckNodes.end(); ++n ) {
2870 const SMDS_PositionPtr& pos = node->GetPosition();
2871 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2873 switch ( posType ) {
2874 case SMDS_TOP_FACE: {
2875 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2876 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2879 case SMDS_TOP_EDGE: {
2880 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2881 Handle(Geom2d_Curve) pcurve;
2882 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2883 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2884 if ( !pcurve.IsNull() ) {
2885 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2886 uv = pcurve->Value( u ).XY();
2890 case SMDS_TOP_VERTEX: {
2891 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2892 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2893 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2898 // check existing UV
2899 bool project = true;
2900 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2901 double dist1 = DBL_MAX, dist2 = 0;
2902 if ( posType != SMDS_TOP_3DSPACE ) {
2903 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2904 project = dist1 > fToler2;
2906 if ( project ) { // compute new UV
2908 if ( !getClosestUV( projector, pNode, newUV )) {
2909 MESSAGE("Node Projection Failed " << node);
2913 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2915 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2917 if ( posType != SMDS_TOP_3DSPACE )
2918 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2919 if ( dist2 < dist1 )
2923 // store UV in the map
2924 listUV.push_back( uv );
2925 uvMap.insert( make_pair( node, &listUV.back() ));
2927 } // loop on not yet smoothed elements
2929 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2930 checkBoundaryNodes = true;
2932 // fix nodes on mesh boundary
2934 if ( checkBoundaryNodes ) {
2935 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2936 map< NLink, int >::iterator link_nb;
2937 // put all elements links to linkNbMap
2938 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2939 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2940 const SMDS_MeshElement* elem = (*elemIt);
2941 int nbn = elem->NbNodes();
2942 if(elem->IsQuadratic())
2944 // loop on elem links: insert them in linkNbMap
2945 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2946 for ( int iN = 0; iN < nbn; ++iN ) {
2947 curNode = elem->GetNode( iN );
2949 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2950 else link = make_pair( prevNode , curNode );
2952 link_nb = linkNbMap.find( link );
2953 if ( link_nb == linkNbMap.end() )
2954 linkNbMap.insert( make_pair ( link, 1 ));
2959 // remove nodes that are in links encountered only once from setMovableNodes
2960 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2961 if ( link_nb->second == 1 ) {
2962 setMovableNodes.erase( link_nb->first.first );
2963 setMovableNodes.erase( link_nb->first.second );
2968 // -----------------------------------------------------
2969 // for nodes on seam edge, compute one more UV ( uvMap2 );
2970 // find movable nodes linked to nodes on seam and which
2971 // are to be smoothed using the second UV ( uvMap2 )
2972 // -----------------------------------------------------
2974 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2975 if ( !surface.IsNull() ) {
2976 TopExp_Explorer eExp( face, TopAbs_EDGE );
2977 for ( ; eExp.More(); eExp.Next() ) {
2978 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2979 if ( !BRep_Tool::IsClosed( edge, face ))
2981 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2982 if ( !sm ) continue;
2983 // find out which parameter varies for a node on seam
2986 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2987 if ( pcurve.IsNull() ) continue;
2988 uv1 = pcurve->Value( f );
2990 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2991 if ( pcurve.IsNull() ) continue;
2992 uv2 = pcurve->Value( f );
2993 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2995 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2996 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2998 // get nodes on seam and its vertices
2999 list< const SMDS_MeshNode* > seamNodes;
3000 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3001 while ( nSeamIt->more() ) {
3002 const SMDS_MeshNode* node = nSeamIt->next();
3003 if ( !isQuadratic || !IsMedium( node ))
3004 seamNodes.push_back( node );
3006 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3007 for ( ; vExp.More(); vExp.Next() ) {
3008 sm = aMesh->MeshElements( vExp.Current() );
3010 nSeamIt = sm->GetNodes();
3011 while ( nSeamIt->more() )
3012 seamNodes.push_back( nSeamIt->next() );
3015 // loop on nodes on seam
3016 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3017 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3018 const SMDS_MeshNode* nSeam = *noSeIt;
3019 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3020 if ( n_uv == uvMap.end() )
3023 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3024 // set the second UV
3025 listUV.push_back( *n_uv->second );
3026 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3027 if ( uvMap2.empty() )
3028 uvMap2 = uvMap; // copy the uvMap contents
3029 uvMap2[ nSeam ] = &listUV.back();
3031 // collect movable nodes linked to ones on seam in nodesNearSeam
3032 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3033 while ( eIt->more() ) {
3034 const SMDS_MeshElement* e = eIt->next();
3035 int nbUseMap1 = 0, nbUseMap2 = 0;
3036 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3037 int nn = 0, nbn = e->NbNodes();
3038 if(e->IsQuadratic()) nbn = nbn/2;
3039 while ( nn++ < nbn )
3041 const SMDS_MeshNode* n =
3042 static_cast<const SMDS_MeshNode*>( nIt->next() );
3044 setMovableNodes.find( n ) == setMovableNodes.end() )
3046 // add only nodes being closer to uv2 than to uv1
3047 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3048 0.5 * ( n->Y() + nSeam->Y() ),
3049 0.5 * ( n->Z() + nSeam->Z() ));
3051 getClosestUV( projector, pMid, uv );
3052 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3053 nodesNearSeam.insert( n );
3059 // for centroidalSmooth all element nodes must
3060 // be on one side of a seam
3061 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3062 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3064 while ( nn++ < nbn ) {
3065 const SMDS_MeshNode* n =
3066 static_cast<const SMDS_MeshNode*>( nIt->next() );
3067 setMovableNodes.erase( n );
3071 } // loop on nodes on seam
3072 } // loop on edge of a face
3073 } // if ( !face.IsNull() )
3075 if ( setMovableNodes.empty() ) {
3076 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3077 continue; // goto next face
3085 double maxRatio = -1., maxDisplacement = -1.;
3086 set<const SMDS_MeshNode*>::iterator nodeToMove;
3087 for ( it = 0; it < theNbIterations; it++ ) {
3088 maxDisplacement = 0.;
3089 nodeToMove = setMovableNodes.begin();
3090 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3091 const SMDS_MeshNode* node = (*nodeToMove);
3092 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3095 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3096 if ( theSmoothMethod == LAPLACIAN )
3097 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3099 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3101 // node displacement
3102 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3103 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3104 if ( aDispl > maxDisplacement )
3105 maxDisplacement = aDispl;
3107 // no node movement => exit
3108 //if ( maxDisplacement < 1.e-16 ) {
3109 if ( maxDisplacement < disttol ) {
3110 MESSAGE("-- no node movement --");
3114 // check elements quality
3116 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3117 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3118 const SMDS_MeshElement* elem = (*elemIt);
3119 if ( !elem || elem->GetType() != SMDSAbs_Face )
3121 SMESH::Controls::TSequenceOfXYZ aPoints;
3122 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3123 double aValue = aQualityFunc.GetValue( aPoints );
3124 if ( aValue > maxRatio )
3128 if ( maxRatio <= theTgtAspectRatio ) {
3129 MESSAGE("-- quality achived --");
3132 if (it+1 == theNbIterations) {
3133 MESSAGE("-- Iteration limit exceeded --");
3135 } // smoothing iterations
3137 MESSAGE(" Face id: " << *fId <<
3138 " Nb iterstions: " << it <<
3139 " Displacement: " << maxDisplacement <<
3140 " Aspect Ratio " << maxRatio);
3142 // ---------------------------------------
3143 // new nodes positions are computed,
3144 // record movement in DS and set new UV
3145 // ---------------------------------------
3146 nodeToMove = setMovableNodes.begin();
3147 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3148 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3149 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3150 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3151 if ( node_uv != uvMap.end() ) {
3152 gp_XY* uv = node_uv->second;
3154 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3158 // move medium nodes of quadratic elements
3161 SMESH_MesherHelper helper( *GetMesh() );
3162 if ( !face.IsNull() )
3163 helper.SetSubShape( face );
3164 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3165 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3166 const SMDS_QuadraticFaceOfNodes* QF =
3167 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3169 vector<const SMDS_MeshNode*> Ns;
3170 Ns.reserve(QF->NbNodes()+1);
3171 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3172 while ( anIter->more() )
3173 Ns.push_back( anIter->next() );
3174 Ns.push_back( Ns[0] );
3176 for(int i=0; i<QF->NbNodes(); i=i+2) {
3177 if ( !surface.IsNull() ) {
3178 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3179 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3180 gp_XY uv = ( uv1 + uv2 ) / 2.;
3181 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3182 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3185 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3186 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3187 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3189 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3190 fabs( Ns[i+1]->Y() - y ) > disttol ||
3191 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3192 // we have to move i+1 node
3193 aMesh->MoveNode( Ns[i+1], x, y, z );
3200 } // loop on face ids
3204 //=======================================================================
3205 //function : isReverse
3206 //purpose : Return true if normal of prevNodes is not co-directied with
3207 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3208 // iNotSame is where prevNodes and nextNodes are different
3209 //=======================================================================
3211 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3212 vector<const SMDS_MeshNode*> nextNodes,
3216 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3217 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3219 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3220 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3221 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3222 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3224 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3225 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3226 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3227 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3229 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3231 return (vA ^ vB) * vN < 0.0;
3234 //=======================================================================
3236 * \brief Create elements by sweeping an element
3237 * \param elem - element to sweep
3238 * \param newNodesItVec - nodes generated from each node of the element
3239 * \param newElems - generated elements
3240 * \param nbSteps - number of sweeping steps
3241 * \param srcElements - to append elem for each generated element
3243 //=======================================================================
3245 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3246 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3247 list<const SMDS_MeshElement*>& newElems,
3249 SMESH_SequenceOfElemPtr& srcElements)
3251 SMESHDS_Mesh* aMesh = GetMeshDS();
3253 // Loop on elem nodes:
3254 // find new nodes and detect same nodes indices
3255 int nbNodes = elem->NbNodes();
3256 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3257 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3258 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3259 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3261 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3262 vector<int> sames(nbNodes);
3263 vector<bool> issimple(nbNodes);
3265 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3266 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3267 const SMDS_MeshNode* node = nnIt->first;
3268 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3269 if ( listNewNodes.empty() ) {
3273 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3275 itNN[ iNode ] = listNewNodes.begin();
3276 prevNod[ iNode ] = node;
3277 nextNod[ iNode ] = listNewNodes.front();
3278 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3279 if ( prevNod[ iNode ] != nextNod [ iNode ])
3280 iNotSameNode = iNode;
3284 sames[nbSame++] = iNode;
3289 //cout<<" nbSame = "<<nbSame<<endl;
3290 if ( nbSame == nbNodes || nbSame > 2) {
3291 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3292 //INFOS( " Too many same nodes of element " << elem->GetID() );
3296 // if( elem->IsQuadratic() && nbSame>0 ) {
3297 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3301 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3302 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3304 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3305 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3306 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3310 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3311 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3312 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3313 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3315 // check element orientation
3317 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3318 //MESSAGE("Reversed elem " << elem );
3322 std::swap( iBeforeSame, iAfterSame );
3325 // make new elements
3326 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3328 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3329 if(issimple[iNode]) {
3330 nextNod[ iNode ] = *itNN[ iNode ];
3334 if( elem->GetType()==SMDSAbs_Node ) {
3335 // we have to use two nodes
3336 midlNod[ iNode ] = *itNN[ iNode ];
3338 nextNod[ iNode ] = *itNN[ iNode ];
3341 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3342 // we have to use each second node
3344 nextNod[ iNode ] = *itNN[ iNode ];
3348 // we have to use two nodes
3349 midlNod[ iNode ] = *itNN[ iNode ];
3351 nextNod[ iNode ] = *itNN[ iNode ];
3356 SMDS_MeshElement* aNewElem = 0;
3357 if(!elem->IsPoly()) {
3358 switch ( nbNodes ) {
3362 if ( nbSame == 0 ) {
3364 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3366 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3372 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3373 nextNod[ 1 ], nextNod[ 0 ] );
3375 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3376 nextNod[ iNotSameNode ] );
3380 case 3: { // TRIANGLE or quadratic edge
3381 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3383 if ( nbSame == 0 ) // --- pentahedron
3384 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3385 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3387 else if ( nbSame == 1 ) // --- pyramid
3388 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3389 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3390 nextNod[ iSameNode ]);
3392 else // 2 same nodes: --- tetrahedron
3393 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3394 nextNod[ iNotSameNode ]);
3396 else { // quadratic edge
3397 if(nbSame==0) { // quadratic quadrangle
3398 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3399 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3401 else if(nbSame==1) { // quadratic triangle
3403 return; // medium node on axis
3405 else if(sames[0]==0) {
3406 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3407 nextNod[2], midlNod[1], prevNod[2]);
3409 else { // sames[0]==1
3410 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3411 midlNod[0], nextNod[2], prevNod[2]);
3420 case 4: { // QUADRANGLE
3422 if ( nbSame == 0 ) // --- hexahedron
3423 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3424 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3426 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3427 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3428 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3429 nextNod[ iSameNode ]);
3430 newElems.push_back( aNewElem );
3431 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3432 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3433 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3435 else if ( nbSame == 2 ) { // pentahedron
3436 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3437 // iBeforeSame is same too
3438 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3439 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3440 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3442 // iAfterSame is same too
3443 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3444 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3445 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3449 case 6: { // quadratic triangle
3450 // create pentahedron with 15 nodes
3452 if(i0>0) { // reversed case
3453 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3454 nextNod[0], nextNod[2], nextNod[1],
3455 prevNod[5], prevNod[4], prevNod[3],
3456 nextNod[5], nextNod[4], nextNod[3],
3457 midlNod[0], midlNod[2], midlNod[1]);
3459 else { // not reversed case
3460 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3461 nextNod[0], nextNod[1], nextNod[2],
3462 prevNod[3], prevNod[4], prevNod[5],
3463 nextNod[3], nextNod[4], nextNod[5],
3464 midlNod[0], midlNod[1], midlNod[2]);
3467 else if(nbSame==1) {
3468 // 2d order pyramid of 13 nodes
3469 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3470 // int n12,int n23,int n34,int n41,
3471 // int n15,int n25,int n35,int n45, int ID);
3473 int n1,n4,n41,n15,n45;
3474 if(i0>0) { // reversed case
3475 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3476 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3482 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3483 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3488 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3489 nextNod[n4], prevNod[n4], prevNod[n5],
3490 midlNod[n1], nextNod[n41],
3491 midlNod[n4], prevNod[n41],
3492 prevNod[n15], nextNod[n15],
3493 nextNod[n45], prevNod[n45]);
3495 else if(nbSame==2) {
3496 // 2d order tetrahedron of 10 nodes
3497 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3498 // int n12,int n23,int n31,
3499 // int n14,int n24,int n34, int ID);
3500 int n1 = iNotSameNode;
3501 int n2,n3,n12,n23,n31;
3502 if(i0>0) { // reversed case
3503 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3504 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3510 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3511 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3516 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3517 prevNod[n12], prevNod[n23], prevNod[n31],
3518 midlNod[n1], nextNod[n12], nextNod[n31]);
3522 case 8: { // quadratic quadrangle
3524 // create hexahedron with 20 nodes
3525 if(i0>0) { // reversed case
3526 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3527 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3528 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3529 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3530 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3532 else { // not reversed case
3533 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3534 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3535 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3536 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3537 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3540 else if(nbSame==1) {
3541 // --- pyramid + pentahedron - can not be created since it is needed
3542 // additional middle node ot the center of face
3543 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3546 else if(nbSame==2) {
3547 // 2d order Pentahedron with 15 nodes
3548 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3549 // int n12,int n23,int n31,int n45,int n56,int n64,
3550 // int n14,int n25,int n36, int ID);
3552 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3553 // iBeforeSame is same too
3560 // iAfterSame is same too
3566 int n12,n45,n14,n25;
3567 if(i0>0) { //reversed case
3579 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3580 prevNod[n4], prevNod[n5], nextNod[n5],
3581 prevNod[n12], midlNod[n2], nextNod[n12],
3582 prevNod[n45], midlNod[n5], nextNod[n45],
3583 prevNod[n14], prevNod[n25], nextNod[n25]);
3588 // realized for extrusion only
3589 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3590 //vector<int> quantities (nbNodes + 2);
3592 //quantities[0] = nbNodes; // bottom of prism
3593 //for (int inode = 0; inode < nbNodes; inode++) {
3594 // polyedre_nodes[inode] = prevNod[inode];
3597 //quantities[1] = nbNodes; // top of prism
3598 //for (int inode = 0; inode < nbNodes; inode++) {
3599 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3602 //for (int iface = 0; iface < nbNodes; iface++) {
3603 // quantities[iface + 2] = 4;
3604 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3605 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3606 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3607 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3608 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3610 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3617 // realized for extrusion only
3618 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3619 vector<int> quantities (nbNodes + 2);
3621 quantities[0] = nbNodes; // bottom of prism
3622 for (int inode = 0; inode < nbNodes; inode++) {
3623 polyedre_nodes[inode] = prevNod[inode];
3626 quantities[1] = nbNodes; // top of prism
3627 for (int inode = 0; inode < nbNodes; inode++) {
3628 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3631 for (int iface = 0; iface < nbNodes; iface++) {
3632 quantities[iface + 2] = 4;
3633 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3634 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3635 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3636 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3637 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3639 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3643 newElems.push_back( aNewElem );
3644 myLastCreatedElems.Append(aNewElem);
3645 srcElements.Append( elem );
3648 // set new prev nodes
3649 for ( iNode = 0; iNode < nbNodes; iNode++ )
3650 prevNod[ iNode ] = nextNod[ iNode ];
3655 //=======================================================================
3657 * \brief Create 1D and 2D elements around swept elements
3658 * \param mapNewNodes - source nodes and ones generated from them
3659 * \param newElemsMap - source elements and ones generated from them
3660 * \param elemNewNodesMap - nodes generated from each node of each element
3661 * \param elemSet - all swept elements
3662 * \param nbSteps - number of sweeping steps
3663 * \param srcElements - to append elem for each generated element
3665 //=======================================================================
3667 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3668 TElemOfElemListMap & newElemsMap,
3669 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3670 TIDSortedElemSet& elemSet,
3672 SMESH_SequenceOfElemPtr& srcElements)
3674 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3675 SMESHDS_Mesh* aMesh = GetMeshDS();
3677 // Find nodes belonging to only one initial element - sweep them to get edges.
3679 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3680 for ( ; nList != mapNewNodes.end(); nList++ ) {
3681 const SMDS_MeshNode* node =
3682 static_cast<const SMDS_MeshNode*>( nList->first );
3683 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3684 int nbInitElems = 0;
3685 const SMDS_MeshElement* el = 0;
3686 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3687 while ( eIt->more() && nbInitElems < 2 ) {
3689 SMDSAbs_ElementType type = el->GetType();
3690 if ( type == SMDSAbs_Volume || type < highType ) continue;
3691 if ( type > highType ) {
3695 if ( elemSet.find(el) != elemSet.end() )
3698 if ( nbInitElems < 2 ) {
3699 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3700 if(!NotCreateEdge) {
3701 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3702 list<const SMDS_MeshElement*> newEdges;
3703 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3708 // Make a ceiling for each element ie an equal element of last new nodes.
3709 // Find free links of faces - make edges and sweep them into faces.
3711 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3712 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3713 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3714 const SMDS_MeshElement* elem = itElem->first;
3715 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3717 if ( elem->GetType() == SMDSAbs_Edge ) {
3718 // create a ceiling edge
3719 if (!elem->IsQuadratic()) {
3720 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3721 vecNewNodes[ 1 ]->second.back())) {
3722 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3723 vecNewNodes[ 1 ]->second.back()));
3724 srcElements.Append( myLastCreatedElems.Last() );
3728 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3729 vecNewNodes[ 1 ]->second.back(),
3730 vecNewNodes[ 2 ]->second.back())) {
3731 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3732 vecNewNodes[ 1 ]->second.back(),
3733 vecNewNodes[ 2 ]->second.back()));
3734 srcElements.Append( myLastCreatedElems.Last() );
3738 if ( elem->GetType() != SMDSAbs_Face )
3741 if(itElem->second.size()==0) continue;
3743 bool hasFreeLinks = false;
3745 TIDSortedElemSet avoidSet;
3746 avoidSet.insert( elem );
3748 set<const SMDS_MeshNode*> aFaceLastNodes;
3749 int iNode, nbNodes = vecNewNodes.size();
3750 if(!elem->IsQuadratic()) {
3751 // loop on the face nodes
3752 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3753 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3754 // look for free links of the face
3755 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3756 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3757 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3758 // check if a link is free
3759 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3760 hasFreeLinks = true;
3761 // make an edge and a ceiling for a new edge
3762 if ( !aMesh->FindEdge( n1, n2 )) {
3763 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3764 srcElements.Append( myLastCreatedElems.Last() );
3766 n1 = vecNewNodes[ iNode ]->second.back();
3767 n2 = vecNewNodes[ iNext ]->second.back();
3768 if ( !aMesh->FindEdge( n1, n2 )) {
3769 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3770 srcElements.Append( myLastCreatedElems.Last() );
3775 else { // elem is quadratic face
3776 int nbn = nbNodes/2;
3777 for ( iNode = 0; iNode < nbn; iNode++ ) {
3778 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3779 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3780 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3781 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3782 // check if a link is free
3783 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3784 hasFreeLinks = true;
3785 // make an edge and a ceiling for a new edge
3787 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3788 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3789 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3790 srcElements.Append( myLastCreatedElems.Last() );
3792 n1 = vecNewNodes[ iNode ]->second.back();
3793 n2 = vecNewNodes[ iNext ]->second.back();
3794 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3795 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3796 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3797 srcElements.Append( myLastCreatedElems.Last() );
3801 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3802 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3806 // sweep free links into faces
3808 if ( hasFreeLinks ) {
3809 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3810 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3812 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3813 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3814 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3815 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3817 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3818 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3820 while ( iVol++ < volNb ) v++;
3821 // find indices of free faces of a volume and their source edges
3822 list< int > freeInd;
3823 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3824 SMDS_VolumeTool vTool( *v );
3825 int iF, nbF = vTool.NbFaces();
3826 for ( iF = 0; iF < nbF; iF ++ ) {
3827 if (vTool.IsFreeFace( iF ) &&
3828 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3829 initNodeSet != faceNodeSet) // except an initial face
3831 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3833 freeInd.push_back( iF );
3834 // find source edge of a free face iF
3835 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3836 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3837 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3838 initNodeSet.begin(), initNodeSet.end(),
3839 commonNodes.begin());
3840 if ( (*v)->IsQuadratic() )
3841 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3843 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3845 if ( !srcEdges.back() )
3847 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3848 << iF << " of volume #" << vTool.ID() << endl;
3853 if ( freeInd.empty() )
3856 // create faces for all steps;
3857 // if such a face has been already created by sweep of edge,
3858 // assure that its orientation is OK
3859 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3861 vTool.SetExternalNormal();
3862 list< int >::iterator ind = freeInd.begin();
3863 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3864 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3866 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3867 int nbn = vTool.NbFaceNodes( *ind );
3869 case 3: { ///// triangle
3870 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3872 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3873 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3874 aMesh->ChangeElementNodes( f, nodes, nbn );
3877 case 4: { ///// quadrangle
3878 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3880 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3881 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3882 aMesh->ChangeElementNodes( f, nodes, nbn );
3886 if( (*v)->IsQuadratic() ) {
3887 if(nbn==6) { /////// quadratic triangle
3888 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3889 nodes[1], nodes[3], nodes[5] );
3891 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3892 nodes[1], nodes[3], nodes[5]));
3894 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3895 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3896 tmpnodes[0] = nodes[0];
3897 tmpnodes[1] = nodes[2];
3898 tmpnodes[2] = nodes[4];
3899 tmpnodes[3] = nodes[1];
3900 tmpnodes[4] = nodes[3];
3901 tmpnodes[5] = nodes[5];
3902 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3905 else { /////// quadratic quadrangle
3906 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3907 nodes[1], nodes[3], nodes[5], nodes[7] );
3909 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3910 nodes[1], nodes[3], nodes[5], nodes[7]));
3912 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3913 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3914 tmpnodes[0] = nodes[0];
3915 tmpnodes[1] = nodes[2];
3916 tmpnodes[2] = nodes[4];
3917 tmpnodes[3] = nodes[6];
3918 tmpnodes[4] = nodes[1];
3919 tmpnodes[5] = nodes[3];
3920 tmpnodes[6] = nodes[5];
3921 tmpnodes[7] = nodes[7];
3922 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3926 else { //////// polygon
3927 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3928 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3930 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3931 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3932 aMesh->ChangeElementNodes( f, nodes, nbn );
3935 while ( srcElements.Length() < myLastCreatedElems.Length() )
3936 srcElements.Append( *srcEdge );
3938 } // loop on free faces
3940 // go to the next volume
3942 while ( iVol++ < nbVolumesByStep ) v++;
3945 } // sweep free links into faces
3947 // Make a ceiling face with a normal external to a volume
3949 SMDS_VolumeTool lastVol( itElem->second.back() );
3951 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3953 lastVol.SetExternalNormal();
3954 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3955 int nbn = lastVol.NbFaceNodes( iF );
3958 if (!hasFreeLinks ||
3959 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3960 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3963 if (!hasFreeLinks ||
3964 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3965 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3968 if(itElem->second.back()->IsQuadratic()) {
3970 if (!hasFreeLinks ||
3971 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3972 nodes[1], nodes[3], nodes[5]) ) {
3973 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3974 nodes[1], nodes[3], nodes[5]));
3978 if (!hasFreeLinks ||
3979 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3980 nodes[1], nodes[3], nodes[5], nodes[7]) )
3981 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982 nodes[1], nodes[3], nodes[5], nodes[7]));
3986 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3987 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3988 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3992 while ( srcElements.Length() < myLastCreatedElems.Length() )
3993 srcElements.Append( myLastCreatedElems.Last() );
3995 } // loop on swept elements
3998 //=======================================================================
3999 //function : RotationSweep
4001 //=======================================================================
4003 SMESH_MeshEditor::PGroupIDs
4004 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4005 const gp_Ax1& theAxis,
4006 const double theAngle,
4007 const int theNbSteps,
4008 const double theTol,
4009 const bool theMakeGroups,
4010 const bool theMakeWalls)
4012 myLastCreatedElems.Clear();
4013 myLastCreatedNodes.Clear();
4015 // source elements for each generated one
4016 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4018 MESSAGE( "RotationSweep()");
4020 aTrsf.SetRotation( theAxis, theAngle );
4022 aTrsf2.SetRotation( theAxis, theAngle/2. );
4024 gp_Lin aLine( theAxis );
4025 double aSqTol = theTol * theTol;
4027 SMESHDS_Mesh* aMesh = GetMeshDS();
4029 TNodeOfNodeListMap mapNewNodes;
4030 TElemOfVecOfNnlmiMap mapElemNewNodes;
4031 TElemOfElemListMap newElemsMap;
4034 TIDSortedElemSet::iterator itElem;
4035 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4036 const SMDS_MeshElement* elem = *itElem;
4037 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4039 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4040 newNodesItVec.reserve( elem->NbNodes() );
4042 // loop on elem nodes
4043 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4044 while ( itN->more() ) {
4045 // check if a node has been already sweeped
4046 const SMDS_MeshNode* node = cast2Node( itN->next() );
4048 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4050 aXYZ.Coord( coord[0], coord[1], coord[2] );
4051 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4053 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4054 if ( nIt == mapNewNodes.end() ) {
4055 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4056 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4059 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4061 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4062 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4063 const SMDS_MeshNode * newNode = node;
4064 for ( int i = 0; i < theNbSteps; i++ ) {
4066 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4068 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4069 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4070 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4071 myLastCreatedNodes.Append(newNode);
4072 srcNodes.Append( node );
4073 listNewNodes.push_back( newNode );
4074 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4075 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4078 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4080 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4081 myLastCreatedNodes.Append(newNode);
4082 srcNodes.Append( node );
4083 listNewNodes.push_back( newNode );
4086 listNewNodes.push_back( newNode );
4087 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4088 listNewNodes.push_back( newNode );
4095 // if current elem is quadratic and current node is not medium
4096 // we have to check - may be it is needed to insert additional nodes
4097 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4098 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4099 if(listNewNodes.size()==theNbSteps) {
4100 listNewNodes.clear();
4102 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4104 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4105 const SMDS_MeshNode * newNode = node;
4107 for(int i = 0; i<theNbSteps; i++) {
4108 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4109 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4110 cout<<" 3 AddNode: "<<newNode;
4111 myLastCreatedNodes.Append(newNode);
4112 listNewNodes.push_back( newNode );
4113 srcNodes.Append( node );
4114 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4115 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4116 cout<<" 4 AddNode: "<<newNode;
4117 myLastCreatedNodes.Append(newNode);
4118 srcNodes.Append( node );
4119 listNewNodes.push_back( newNode );
4123 listNewNodes.push_back( newNode );
4129 newNodesItVec.push_back( nIt );
4131 // make new elements
4132 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4136 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4138 PGroupIDs newGroupIDs;
4139 if ( theMakeGroups )
4140 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4146 //=======================================================================
4147 //function : CreateNode
4149 //=======================================================================
4150 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4153 const double tolnode,
4154 SMESH_SequenceOfNode& aNodes)
4156 myLastCreatedElems.Clear();
4157 myLastCreatedNodes.Clear();
4160 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4162 // try to search in sequence of existing nodes
4163 // if aNodes.Length()>0 we 'nave to use given sequence
4164 // else - use all nodes of mesh
4165 if(aNodes.Length()>0) {
4167 for(i=1; i<=aNodes.Length(); i++) {
4168 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4169 if(P1.Distance(P2)<tolnode)
4170 return aNodes.Value(i);
4174 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4175 while(itn->more()) {
4176 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4177 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4178 if(P1.Distance(P2)<tolnode)
4183 // create new node and return it
4184 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4185 myLastCreatedNodes.Append(NewNode);
4190 //=======================================================================
4191 //function : ExtrusionSweep
4193 //=======================================================================
4195 SMESH_MeshEditor::PGroupIDs
4196 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4197 const gp_Vec& theStep,
4198 const int theNbSteps,
4199 TElemOfElemListMap& newElemsMap,
4200 const bool theMakeGroups,
4202 const double theTolerance)
4204 ExtrusParam aParams;
4205 aParams.myDir = gp_Dir(theStep);
4206 aParams.myNodes.Clear();
4207 aParams.mySteps = new TColStd_HSequenceOfReal;
4209 for(i=1; i<=theNbSteps; i++)
4210 aParams.mySteps->Append(theStep.Magnitude());
4213 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4217 //=======================================================================
4218 //function : ExtrusionSweep
4220 //=======================================================================
4222 SMESH_MeshEditor::PGroupIDs
4223 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4224 ExtrusParam& theParams,
4225 TElemOfElemListMap& newElemsMap,
4226 const bool theMakeGroups,
4228 const double theTolerance)
4230 myLastCreatedElems.Clear();
4231 myLastCreatedNodes.Clear();
4233 // source elements for each generated one
4234 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4236 SMESHDS_Mesh* aMesh = GetMeshDS();
4238 int nbsteps = theParams.mySteps->Length();
4240 TNodeOfNodeListMap mapNewNodes;
4241 //TNodeOfNodeVecMap mapNewNodes;
4242 TElemOfVecOfNnlmiMap mapElemNewNodes;
4243 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4246 TIDSortedElemSet::iterator itElem;
4247 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4248 // check element type
4249 const SMDS_MeshElement* elem = *itElem;
4250 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4253 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4255 newNodesItVec.reserve( elem->NbNodes() );
4257 // loop on elem nodes
4258 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4259 while ( itN->more() )
4261 // check if a node has been already sweeped
4262 const SMDS_MeshNode* node = cast2Node( itN->next() );
4263 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4264 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4265 if ( nIt == mapNewNodes.end() ) {
4266 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4267 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4268 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4269 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4270 //vecNewNodes.reserve(nbsteps);
4273 double coord[] = { node->X(), node->Y(), node->Z() };
4274 //int nbsteps = theParams.mySteps->Length();
4275 for ( int i = 0; i < nbsteps; i++ ) {
4276 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4277 // create additional node
4278 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4279 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4280 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4281 if( theFlags & EXTRUSION_FLAG_SEW ) {
4282 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4283 theTolerance, theParams.myNodes);
4284 listNewNodes.push_back( newNode );
4287 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4288 myLastCreatedNodes.Append(newNode);
4289 srcNodes.Append( node );
4290 listNewNodes.push_back( newNode );
4293 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4294 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4295 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4296 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4297 if( theFlags & EXTRUSION_FLAG_SEW ) {
4298 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4299 theTolerance, theParams.myNodes);
4300 listNewNodes.push_back( newNode );
4301 //vecNewNodes[i]=newNode;
4304 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4305 myLastCreatedNodes.Append(newNode);
4306 srcNodes.Append( node );
4307 listNewNodes.push_back( newNode );
4308 //vecNewNodes[i]=newNode;
4313 // if current elem is quadratic and current node is not medium
4314 // we have to check - may be it is needed to insert additional nodes
4315 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4316 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4317 if(listNewNodes.size()==nbsteps) {
4318 listNewNodes.clear();
4319 double coord[] = { node->X(), node->Y(), node->Z() };
4320 for ( int i = 0; i < nbsteps; i++ ) {
4321 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4322 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4323 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4324 if( theFlags & EXTRUSION_FLAG_SEW ) {
4325 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4326 theTolerance, theParams.myNodes);
4327 listNewNodes.push_back( newNode );
4330 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4331 myLastCreatedNodes.Append(newNode);
4332 srcNodes.Append( node );
4333 listNewNodes.push_back( newNode );
4335 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4336 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4337 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4338 if( theFlags & EXTRUSION_FLAG_SEW ) {
4339 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4340 theTolerance, theParams.myNodes);
4341 listNewNodes.push_back( newNode );
4344 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4345 myLastCreatedNodes.Append(newNode);
4346 srcNodes.Append( node );
4347 listNewNodes.push_back( newNode );
4353 newNodesItVec.push_back( nIt );
4355 // make new elements
4356 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4359 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4360 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4362 PGroupIDs newGroupIDs;
4363 if ( theMakeGroups )
4364 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4370 //=======================================================================
4371 //class : SMESH_MeshEditor_PathPoint
4372 //purpose : auxiliary class
4373 //=======================================================================
4374 class SMESH_MeshEditor_PathPoint {
4376 SMESH_MeshEditor_PathPoint() {
4377 myPnt.SetCoord(99., 99., 99.);
4378 myTgt.SetCoord(1.,0.,0.);
4382 void SetPnt(const gp_Pnt& aP3D){
4385 void SetTangent(const gp_Dir& aTgt){
4388 void SetAngle(const double& aBeta){
4391 void SetParameter(const double& aPrm){
4394 const gp_Pnt& Pnt()const{
4397 const gp_Dir& Tangent()const{
4400 double Angle()const{
4403 double Parameter()const{
4415 //=======================================================================
4416 //function : ExtrusionAlongTrack
4418 //=======================================================================
4419 SMESH_MeshEditor::Extrusion_Error
4420 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4421 SMESH_subMesh* theTrack,
4422 const SMDS_MeshNode* theN1,
4423 const bool theHasAngles,
4424 list<double>& theAngles,
4425 const bool theLinearVariation,
4426 const bool theHasRefPoint,
4427 const gp_Pnt& theRefPoint,
4428 const bool theMakeGroups)
4430 myLastCreatedElems.Clear();
4431 myLastCreatedNodes.Clear();
4434 std::list<double> aPrms;
4435 TIDSortedElemSet::iterator itElem;
4438 TopoDS_Edge aTrackEdge;
4439 TopoDS_Vertex aV1, aV2;
4441 SMDS_ElemIteratorPtr aItE;
4442 SMDS_NodeIteratorPtr aItN;
4443 SMDSAbs_ElementType aTypeE;
4445 TNodeOfNodeListMap mapNewNodes;
4448 aNbE = theElements.size();
4451 return EXTR_NO_ELEMENTS;
4453 // 1.1 Track Pattern
4456 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4458 aItE = pSubMeshDS->GetElements();
4459 while ( aItE->more() ) {
4460 const SMDS_MeshElement* pE = aItE->next();
4461 aTypeE = pE->GetType();
4462 // Pattern must contain links only
4463 if ( aTypeE != SMDSAbs_Edge )
4464 return EXTR_PATH_NOT_EDGE;
4467 list<SMESH_MeshEditor_PathPoint> fullList;
4469 const TopoDS_Shape& aS = theTrack->GetSubShape();
4470 // Sub shape for the Pattern must be an Edge or Wire
4471 if( aS.ShapeType() == TopAbs_EDGE ) {
4472 aTrackEdge = TopoDS::Edge( aS );
4473 // the Edge must not be degenerated
4474 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4475 return EXTR_BAD_PATH_SHAPE;
4476 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4477 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4478 const SMDS_MeshNode* aN1 = aItN->next();
4479 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4480 const SMDS_MeshNode* aN2 = aItN->next();
4481 // starting node must be aN1 or aN2
4482 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4483 return EXTR_BAD_STARTING_NODE;
4484 aItN = pSubMeshDS->GetNodes();
4485 while ( aItN->more() ) {
4486 const SMDS_MeshNode* pNode = aItN->next();
4487 const SMDS_EdgePosition* pEPos =
4488 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4489 double aT = pEPos->GetUParameter();
4490 aPrms.push_back( aT );
4492 //Extrusion_Error err =
4493 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4495 else if( aS.ShapeType() == TopAbs_WIRE ) {
4496 list< SMESH_subMesh* > LSM;
4497 TopTools_SequenceOfShape Edges;
4498 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4499 while(itSM->more()) {
4500 SMESH_subMesh* SM = itSM->next();
4502 const TopoDS_Shape& aS = SM->GetSubShape();
4505 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4506 int startNid = theN1->GetID();
4507 TColStd_MapOfInteger UsedNums;
4508 int NbEdges = Edges.Length();
4510 for(; i<=NbEdges; i++) {
4512 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4513 for(; itLSM!=LSM.end(); itLSM++) {
4515 if(UsedNums.Contains(k)) continue;
4516 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4517 SMESH_subMesh* locTrack = *itLSM;
4518 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4519 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4520 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4521 const SMDS_MeshNode* aN1 = aItN->next();
4522 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4523 const SMDS_MeshNode* aN2 = aItN->next();
4524 // starting node must be aN1 or aN2
4525 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4526 // 2. Collect parameters on the track edge
4528 aItN = locMeshDS->GetNodes();
4529 while ( aItN->more() ) {
4530 const SMDS_MeshNode* pNode = aItN->next();
4531 const SMDS_EdgePosition* pEPos =
4532 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4533 double aT = pEPos->GetUParameter();
4534 aPrms.push_back( aT );
4536 list<SMESH_MeshEditor_PathPoint> LPP;
4537 //Extrusion_Error err =
4538 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4539 LLPPs.push_back(LPP);
4541 // update startN for search following egde
4542 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4543 else startNid = aN1->GetID();
4547 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4548 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4549 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4550 for(; itPP!=firstList.end(); itPP++) {
4551 fullList.push_back( *itPP );
4553 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4554 fullList.pop_back();
4556 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4557 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4558 itPP = currList.begin();
4559 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4560 gp_Dir D1 = PP1.Tangent();
4561 gp_Dir D2 = PP2.Tangent();
4562 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4563 (D1.Z()+D2.Z())/2 ) );
4564 PP1.SetTangent(Dnew);
4565 fullList.push_back(PP1);
4567 for(; itPP!=firstList.end(); itPP++) {
4568 fullList.push_back( *itPP );
4570 PP1 = fullList.back();
4571 fullList.pop_back();
4573 // if wire not closed
4574 fullList.push_back(PP1);
4578 return EXTR_BAD_PATH_SHAPE;
4581 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4582 theHasRefPoint, theRefPoint, theMakeGroups);
4586 //=======================================================================
4587 //function : ExtrusionAlongTrack
4589 //=======================================================================
4590 SMESH_MeshEditor::Extrusion_Error
4591 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4592 SMESH_Mesh* theTrack,
4593 const SMDS_MeshNode* theN1,
4594 const bool theHasAngles,
4595 list<double>& theAngles,
4596 const bool theLinearVariation,
4597 const bool theHasRefPoint,
4598 const gp_Pnt& theRefPoint,
4599 const bool theMakeGroups)
4601 myLastCreatedElems.Clear();
4602 myLastCreatedNodes.Clear();
4605 std::list<double> aPrms;
4606 TIDSortedElemSet::iterator itElem;
4609 TopoDS_Edge aTrackEdge;
4610 TopoDS_Vertex aV1, aV2;
4612 SMDS_ElemIteratorPtr aItE;
4613 SMDS_NodeIteratorPtr aItN;
4614 SMDSAbs_ElementType aTypeE;
4616 TNodeOfNodeListMap mapNewNodes;
4619 aNbE = theElements.size();
4622 return EXTR_NO_ELEMENTS;
4624 // 1.1 Track Pattern
4627 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4629 aItE = pMeshDS->elementsIterator();
4630 while ( aItE->more() ) {
4631 const SMDS_MeshElement* pE = aItE->next();
4632 aTypeE = pE->GetType();
4633 // Pattern must contain links only
4634 if ( aTypeE != SMDSAbs_Edge )
4635 return EXTR_PATH_NOT_EDGE;
4638 list<SMESH_MeshEditor_PathPoint> fullList;
4640 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4641 // Sub shape for the Pattern must be an Edge or Wire
4642 if( aS.ShapeType() == TopAbs_EDGE ) {
4643 aTrackEdge = TopoDS::Edge( aS );
4644 // the Edge must not be degenerated
4645 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4646 return EXTR_BAD_PATH_SHAPE;
4647 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4648 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4649 const SMDS_MeshNode* aN1 = aItN->next();
4650 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4651 const SMDS_MeshNode* aN2 = aItN->next();
4652 // starting node must be aN1 or aN2
4653 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4654 return EXTR_BAD_STARTING_NODE;
4655 aItN = pMeshDS->nodesIterator();
4656 while ( aItN->more() ) {
4657 const SMDS_MeshNode* pNode = aItN->next();
4658 if( pNode==aN1 || pNode==aN2 ) continue;
4659 const SMDS_EdgePosition* pEPos =
4660 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4661 double aT = pEPos->GetUParameter();
4662 aPrms.push_back( aT );
4664 //Extrusion_Error err =
4665 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4667 else if( aS.ShapeType() == TopAbs_WIRE ) {
4668 list< SMESH_subMesh* > LSM;
4669 TopTools_SequenceOfShape Edges;
4670 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4671 for(; eExp.More(); eExp.Next()) {
4672 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4673 if( BRep_Tool::Degenerated(E) ) continue;
4674 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4680 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4681 int startNid = theN1->GetID();
4682 TColStd_MapOfInteger UsedNums;
4683 int NbEdges = Edges.Length();
4685 for(; i<=NbEdges; i++) {
4687 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4688 for(; itLSM!=LSM.end(); itLSM++) {
4690 if(UsedNums.Contains(k)) continue;
4691 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4692 SMESH_subMesh* locTrack = *itLSM;
4693 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4694 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4695 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4696 const SMDS_MeshNode* aN1 = aItN->next();
4697 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4698 const SMDS_MeshNode* aN2 = aItN->next();
4699 // starting node must be aN1 or aN2
4700 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4701 // 2. Collect parameters on the track edge
4703 aItN = locMeshDS->GetNodes();
4704 while ( aItN->more() ) {
4705 const SMDS_MeshNode* pNode = aItN->next();
4706 const SMDS_EdgePosition* pEPos =
4707 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4708 double aT = pEPos->GetUParameter();
4709 aPrms.push_back( aT );
4711 list<SMESH_MeshEditor_PathPoint> LPP;
4712 //Extrusion_Error err =
4713 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4714 LLPPs.push_back(LPP);
4716 // update startN for search following egde
4717 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4718 else startNid = aN1->GetID();
4722 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4723 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4724 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4725 for(; itPP!=firstList.end(); itPP++) {
4726 fullList.push_back( *itPP );
4728 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4729 fullList.pop_back();
4731 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4732 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4733 itPP = currList.begin();
4734 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4735 gp_Pnt P1 = PP1.Pnt();
4736 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4737 gp_Pnt P2 = PP2.Pnt();
4738 gp_Dir D1 = PP1.Tangent();
4739 gp_Dir D2 = PP2.Tangent();
4740 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4741 (D1.Z()+D2.Z())/2 ) );
4742 PP1.SetTangent(Dnew);
4743 fullList.push_back(PP1);
4745 for(; itPP!=currList.end(); itPP++) {
4746 fullList.push_back( *itPP );
4748 PP1 = fullList.back();
4749 fullList.pop_back();
4751 // if wire not closed
4752 fullList.push_back(PP1);
4756 return EXTR_BAD_PATH_SHAPE;
4759 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4760 theHasRefPoint, theRefPoint, theMakeGroups);
4764 //=======================================================================
4765 //function : MakeEdgePathPoints
4766 //purpose : auxilary for ExtrusionAlongTrack
4767 //=======================================================================
4768 SMESH_MeshEditor::Extrusion_Error
4769 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4770 const TopoDS_Edge& aTrackEdge,
4772 list<SMESH_MeshEditor_PathPoint>& LPP)
4774 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4776 aTolVec2=aTolVec*aTolVec;
4778 TopoDS_Vertex aV1, aV2;
4779 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4780 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4781 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4782 // 2. Collect parameters on the track edge
4783 aPrms.push_front( aT1 );
4784 aPrms.push_back( aT2 );
4787 if( FirstIsStart ) {
4798 SMESH_MeshEditor_PathPoint aPP;
4799 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4800 std::list<double>::iterator aItD = aPrms.begin();
4801 for(; aItD != aPrms.end(); ++aItD) {
4805 aC3D->D1( aT, aP3D, aVec );
4806 aL2 = aVec.SquareMagnitude();
4807 if ( aL2 < aTolVec2 )
4808 return EXTR_CANT_GET_TANGENT;
4809 gp_Dir aTgt( aVec );
4811 aPP.SetTangent( aTgt );
4812 aPP.SetParameter( aT );
4819 //=======================================================================
4820 //function : MakeExtrElements
4821 //purpose : auxilary for ExtrusionAlongTrack
4822 //=======================================================================
4823 SMESH_MeshEditor::Extrusion_Error
4824 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4825 list<SMESH_MeshEditor_PathPoint>& fullList,
4826 const bool theHasAngles,
4827 list<double>& theAngles,
4828 const bool theLinearVariation,
4829 const bool theHasRefPoint,
4830 const gp_Pnt& theRefPoint,
4831 const bool theMakeGroups)
4833 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4834 int aNbTP = fullList.size();
4835 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4837 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4838 LinearAngleVariation(aNbTP-1, theAngles);
4840 vector<double> aAngles( aNbTP );
4842 for(; j<aNbTP; ++j) {
4845 if ( theHasAngles ) {
4847 std::list<double>::iterator aItD = theAngles.begin();
4848 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4850 aAngles[j] = anAngle;
4853 // fill vector of path points with angles
4854 //aPPs.resize(fullList.size());
4856 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4857 for(; itPP!=fullList.end(); itPP++) {
4859 SMESH_MeshEditor_PathPoint PP = *itPP;
4860 PP.SetAngle(aAngles[j]);
4864 TNodeOfNodeListMap mapNewNodes;
4865 TElemOfVecOfNnlmiMap mapElemNewNodes;
4866 TElemOfElemListMap newElemsMap;
4867 TIDSortedElemSet::iterator itElem;
4870 SMDSAbs_ElementType aTypeE;
4871 // source elements for each generated one
4872 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4874 // 3. Center of rotation aV0
4875 gp_Pnt aV0 = theRefPoint;
4877 if ( !theHasRefPoint ) {
4879 aGC.SetCoord( 0.,0.,0. );
4881 itElem = theElements.begin();
4882 for ( ; itElem != theElements.end(); itElem++ ) {
4883 const SMDS_MeshElement* elem = *itElem;
4885 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4886 while ( itN->more() ) {
4887 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4892 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4893 list<const SMDS_MeshNode*> aLNx;
4894 mapNewNodes[node] = aLNx;
4896 gp_XYZ aXYZ( aX, aY, aZ );
4904 } // if (!theHasRefPoint) {
4905 mapNewNodes.clear();
4907 // 4. Processing the elements
4908 SMESHDS_Mesh* aMesh = GetMeshDS();
4910 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4911 // check element type
4912 const SMDS_MeshElement* elem = *itElem;
4913 aTypeE = elem->GetType();
4914 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4917 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4918 newNodesItVec.reserve( elem->NbNodes() );
4920 // loop on elem nodes
4922 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4923 while ( itN->more() )
4926 // check if a node has been already processed
4927 const SMDS_MeshNode* node =
4928 static_cast<const SMDS_MeshNode*>( itN->next() );
4929 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4930 if ( nIt == mapNewNodes.end() ) {
4931 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4932 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4935 aX = node->X(); aY = node->Y(); aZ = node->Z();
4937 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4938 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4939 gp_Ax1 anAx1, anAxT1T0;
4940 gp_Dir aDT1x, aDT0x, aDT1T0;
4945 aPN0.SetCoord(aX, aY, aZ);
4947 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4949 aDT0x= aPP0.Tangent();
4950 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4952 for ( j = 1; j < aNbTP; ++j ) {
4953 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4955 aDT1x = aPP1.Tangent();
4956 aAngle1x = aPP1.Angle();
4958 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4960 gp_Vec aV01x( aP0x, aP1x );
4961 aTrsf.SetTranslation( aV01x );
4964 aV1x = aV0x.Transformed( aTrsf );
4965 aPN1 = aPN0.Transformed( aTrsf );
4967 // rotation 1 [ T1,T0 ]
4968 aAngleT1T0=-aDT1x.Angle( aDT0x );
4969 if (fabs(aAngleT1T0) > aTolAng) {
4971 anAxT1T0.SetLocation( aV1x );
4972 anAxT1T0.SetDirection( aDT1T0 );
4973 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4975 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4979 if ( theHasAngles ) {
4980 anAx1.SetLocation( aV1x );
4981 anAx1.SetDirection( aDT1x );
4982 aTrsfRot.SetRotation( anAx1, aAngle1x );
4984 aPN1 = aPN1.Transformed( aTrsfRot );
4988 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4989 // create additional node
4990 double x = ( aPN1.X() + aPN0.X() )/2.;
4991 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4992 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4993 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4994 myLastCreatedNodes.Append(newNode);
4995 srcNodes.Append( node );
4996 listNewNodes.push_back( newNode );
5001 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5002 myLastCreatedNodes.Append(newNode);
5003 srcNodes.Append( node );
5004 listNewNodes.push_back( newNode );
5014 // if current elem is quadratic and current node is not medium
5015 // we have to check - may be it is needed to insert additional nodes
5016 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5017 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5018 if(listNewNodes.size()==aNbTP-1) {
5019 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5020 gp_XYZ P(node->X(), node->Y(), node->Z());
5021 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5023 for(i=0; i<aNbTP-1; i++) {
5024 const SMDS_MeshNode* N = *it;
5025 double x = ( N->X() + P.X() )/2.;
5026 double y = ( N->Y() + P.Y() )/2.;
5027 double z = ( N->Z() + P.Z() )/2.;
5028 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5029 srcNodes.Append( node );
5030 myLastCreatedNodes.Append(newN);
5033 P = gp_XYZ(N->X(),N->Y(),N->Z());
5035 listNewNodes.clear();
5036 for(i=0; i<2*(aNbTP-1); i++) {
5037 listNewNodes.push_back(aNodes[i]);
5043 newNodesItVec.push_back( nIt );
5045 // make new elements
5046 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5047 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5048 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5051 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5053 if ( theMakeGroups )
5054 generateGroups( srcNodes, srcElems, "extruded");
5060 //=======================================================================
5061 //function : LinearAngleVariation
5062 //purpose : auxilary for ExtrusionAlongTrack
5063 //=======================================================================
5064 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5065 list<double>& Angles)
5067 int nbAngles = Angles.size();
5068 if( nbSteps > nbAngles ) {
5069 vector<double> theAngles(nbAngles);
5070 list<double>::iterator it = Angles.begin();
5072 for(; it!=Angles.end(); it++) {
5074 theAngles[i] = (*it);
5077 double rAn2St = double( nbAngles ) / double( nbSteps );
5078 double angPrev = 0, angle;
5079 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5080 double angCur = rAn2St * ( iSt+1 );
5081 double angCurFloor = floor( angCur );
5082 double angPrevFloor = floor( angPrev );
5083 if ( angPrevFloor == angCurFloor )
5084 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5086 int iP = int( angPrevFloor );
5087 double angPrevCeil = ceil(angPrev);
5088 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5090 int iC = int( angCurFloor );
5091 if ( iC < nbAngles )
5092 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5094 iP = int( angPrevCeil );
5096 angle += theAngles[ iC ];
5098 res.push_back(angle);
5103 for(; it!=res.end(); it++)
5104 Angles.push_back( *it );
5109 //=======================================================================
5110 //function : Transform
5112 //=======================================================================
5114 SMESH_MeshEditor::PGroupIDs
5115 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5116 const gp_Trsf& theTrsf,
5118 const bool theMakeGroups,
5119 SMESH_Mesh* theTargetMesh)
5121 myLastCreatedElems.Clear();
5122 myLastCreatedNodes.Clear();
5124 bool needReverse = false;
5125 string groupPostfix;
5126 switch ( theTrsf.Form() ) {
5131 groupPostfix = "mirrored";
5134 groupPostfix = "rotated";
5136 case gp_Translation:
5137 groupPostfix = "translated";
5140 groupPostfix = "scaled";
5143 needReverse = false;
5144 groupPostfix = "transformed";
5147 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5148 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5149 SMESHDS_Mesh* aMesh = GetMeshDS();
5152 // map old node to new one
5153 TNodeNodeMap nodeMap;
5155 // elements sharing moved nodes; those of them which have all
5156 // nodes mirrored but are not in theElems are to be reversed
5157 TIDSortedElemSet inverseElemSet;
5159 // source elements for each generated one
5160 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5163 TIDSortedElemSet::iterator itElem;
5164 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5165 const SMDS_MeshElement* elem = *itElem;
5169 // loop on elem nodes
5170 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5171 while ( itN->more() ) {
5173 // check if a node has been already transformed
5174 const SMDS_MeshNode* node = cast2Node( itN->next() );
5175 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5176 nodeMap.insert( make_pair ( node, node ));
5177 if ( !n2n_isnew.second )
5181 coord[0] = node->X();
5182 coord[1] = node->Y();
5183 coord[2] = node->Z();
5184 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5185 if ( theTargetMesh ) {
5186 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5187 n2n_isnew.first->second = newNode;
5188 myLastCreatedNodes.Append(newNode);
5189 srcNodes.Append( node );
5191 else if ( theCopy ) {
5192 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5193 n2n_isnew.first->second = newNode;
5194 myLastCreatedNodes.Append(newNode);
5195 srcNodes.Append( node );
5198 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5199 // node position on shape becomes invalid
5200 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5201 ( SMDS_SpacePosition::originSpacePosition() );
5204 // keep inverse elements
5205 if ( !theCopy && !theTargetMesh && needReverse ) {
5206 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5207 while ( invElemIt->more() ) {
5208 const SMDS_MeshElement* iel = invElemIt->next();
5209 inverseElemSet.insert( iel );
5215 // either create new elements or reverse mirrored ones
5216 if ( !theCopy && !needReverse && !theTargetMesh )
5219 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5220 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5221 theElems.insert( *invElemIt );
5223 // replicate or reverse elements
5226 REV_TETRA = 0, // = nbNodes - 4
5227 REV_PYRAMID = 1, // = nbNodes - 4
5228 REV_PENTA = 2, // = nbNodes - 4
5230 REV_HEXA = 4, // = nbNodes - 4
5234 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5235 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5236 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5237 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5238 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5239 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5242 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5244 const SMDS_MeshElement* elem = *itElem;
5245 if ( !elem || elem->GetType() == SMDSAbs_Node )
5248 int nbNodes = elem->NbNodes();
5249 int elemType = elem->GetType();
5251 if (elem->IsPoly()) {
5252 // Polygon or Polyhedral Volume
5253 switch ( elemType ) {
5256 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5258 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5259 while (itN->more()) {
5260 const SMDS_MeshNode* node =
5261 static_cast<const SMDS_MeshNode*>(itN->next());
5262 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5263 if (nodeMapIt == nodeMap.end())
5264 break; // not all nodes transformed
5266 // reverse mirrored faces and volumes
5267 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5269 poly_nodes[iNode] = (*nodeMapIt).second;
5273 if ( iNode != nbNodes )
5274 continue; // not all nodes transformed
5276 if ( theTargetMesh ) {
5277 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5278 srcElems.Append( elem );
5280 else if ( theCopy ) {
5281 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5282 srcElems.Append( elem );
5285 aMesh->ChangePolygonNodes(elem, poly_nodes);
5289 case SMDSAbs_Volume:
5291 // ATTENTION: Reversing is not yet done!!!
5292 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5293 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5295 MESSAGE("Warning: bad volumic element");
5299 vector<const SMDS_MeshNode*> poly_nodes;
5300 vector<int> quantities;
5302 bool allTransformed = true;
5303 int nbFaces = aPolyedre->NbFaces();
5304 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5305 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5306 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5307 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5308 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5309 if (nodeMapIt == nodeMap.end()) {
5310 allTransformed = false; // not all nodes transformed
5312 poly_nodes.push_back((*nodeMapIt).second);
5315 quantities.push_back(nbFaceNodes);
5317 if ( !allTransformed )
5318 continue; // not all nodes transformed
5320 if ( theTargetMesh ) {
5321 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5322 srcElems.Append( elem );
5324 else if ( theCopy ) {
5325 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5326 srcElems.Append( elem );
5329 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5339 int* i = index[ FORWARD ];
5340 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5341 if ( elemType == SMDSAbs_Face )
5342 i = index[ REV_FACE ];
5344 i = index[ nbNodes - 4 ];
5346 if(elem->IsQuadratic()) {
5347 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5350 if(nbNodes==3) { // quadratic edge
5351 static int anIds[] = {1,0,2};
5354 else if(nbNodes==6) { // quadratic triangle
5355 static int anIds[] = {0,2,1,5,4,3};
5358 else if(nbNodes==8) { // quadratic quadrangle
5359 static int anIds[] = {0,3,2,1,7,6,5,4};
5362 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5363 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5366 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5367 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5370 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5371 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5374 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5375 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5381 // find transformed nodes
5382 vector<const SMDS_MeshNode*> nodes(nbNodes);
5384 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5385 while ( itN->more() ) {
5386 const SMDS_MeshNode* node =
5387 static_cast<const SMDS_MeshNode*>( itN->next() );
5388 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5389 if ( nodeMapIt == nodeMap.end() )
5390 break; // not all nodes transformed
5391 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5393 if ( iNode != nbNodes )
5394 continue; // not all nodes transformed
5396 if ( theTargetMesh ) {
5397 if ( SMDS_MeshElement* copy =
5398 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5399 myLastCreatedElems.Append( copy );
5400 srcElems.Append( elem );
5403 else if ( theCopy ) {
5404 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5405 myLastCreatedElems.Append( copy );
5406 srcElems.Append( elem );
5410 // reverse element as it was reversed by transformation
5412 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5416 PGroupIDs newGroupIDs;
5418 if ( theMakeGroups && theCopy ||
5419 theMakeGroups && theTargetMesh )
5420 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5426 //=======================================================================
5429 //=======================================================================
5431 SMESH_MeshEditor::PGroupIDs
5432 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5433 const gp_Pnt& thePoint,
5434 const std::list<double>& theScaleFact,
5436 const bool theMakeGroups,
5437 SMESH_Mesh* theTargetMesh)
5439 myLastCreatedElems.Clear();
5440 myLastCreatedNodes.Clear();
5442 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5443 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5444 SMESHDS_Mesh* aMesh = GetMeshDS();
5446 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5447 std::list<double>::const_iterator itS = theScaleFact.begin();
5449 if(theScaleFact.size()==1) {
5453 if(theScaleFact.size()==2) {
5458 if(theScaleFact.size()>2) {
5465 // map old node to new one
5466 TNodeNodeMap nodeMap;
5468 // elements sharing moved nodes; those of them which have all
5469 // nodes mirrored but are not in theElems are to be reversed
5470 TIDSortedElemSet inverseElemSet;
5472 // source elements for each generated one
5473 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5476 TIDSortedElemSet::iterator itElem;
5477 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5478 const SMDS_MeshElement* elem = *itElem;
5482 // loop on elem nodes
5483 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5484 while ( itN->more() ) {
5486 // check if a node has been already transformed
5487 const SMDS_MeshNode* node = cast2Node( itN->next() );
5488 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5489 nodeMap.insert( make_pair ( node, node ));
5490 if ( !n2n_isnew.second )
5494 //coord[0] = node->X();
5495 //coord[1] = node->Y();
5496 //coord[2] = node->Z();
5497 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5498 double dx = (node->X() - thePoint.X()) * scaleX;
5499 double dy = (node->Y() - thePoint.Y()) * scaleY;
5500 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5501 if ( theTargetMesh ) {
5502 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5503 const SMDS_MeshNode * newNode =
5504 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5505 n2n_isnew.first->second = newNode;
5506 myLastCreatedNodes.Append(newNode);
5507 srcNodes.Append( node );
5509 else if ( theCopy ) {
5510 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5511 const SMDS_MeshNode * newNode =
5512 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5513 n2n_isnew.first->second = newNode;
5514 myLastCreatedNodes.Append(newNode);
5515 srcNodes.Append( node );
5518 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5519 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5520 // node position on shape becomes invalid
5521 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5522 ( SMDS_SpacePosition::originSpacePosition() );
5525 // keep inverse elements
5526 //if ( !theCopy && !theTargetMesh && needReverse ) {
5527 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5528 // while ( invElemIt->more() ) {
5529 // const SMDS_MeshElement* iel = invElemIt->next();
5530 // inverseElemSet.insert( iel );
5536 // either create new elements or reverse mirrored ones
5537 //if ( !theCopy && !needReverse && !theTargetMesh )
5538 if ( !theCopy && !theTargetMesh )
5541 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5542 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5543 theElems.insert( *invElemIt );
5545 // replicate or reverse elements
5548 REV_TETRA = 0, // = nbNodes - 4
5549 REV_PYRAMID = 1, // = nbNodes - 4
5550 REV_PENTA = 2, // = nbNodes - 4
5552 REV_HEXA = 4, // = nbNodes - 4
5556 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5557 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5558 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5559 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5560 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5561 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5564 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5566 const SMDS_MeshElement* elem = *itElem;
5567 if ( !elem || elem->GetType() == SMDSAbs_Node )
5570 int nbNodes = elem->NbNodes();
5571 int elemType = elem->GetType();
5573 if (elem->IsPoly()) {
5574 // Polygon or Polyhedral Volume
5575 switch ( elemType ) {
5578 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5580 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5581 while (itN->more()) {
5582 const SMDS_MeshNode* node =
5583 static_cast<const SMDS_MeshNode*>(itN->next());
5584 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5585 if (nodeMapIt == nodeMap.end())
5586 break; // not all nodes transformed
5587 //if (needReverse) {
5588 // // reverse mirrored faces and volumes
5589 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5591 poly_nodes[iNode] = (*nodeMapIt).second;
5595 if ( iNode != nbNodes )
5596 continue; // not all nodes transformed
5598 if ( theTargetMesh ) {
5599 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5600 srcElems.Append( elem );
5602 else if ( theCopy ) {
5603 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5604 srcElems.Append( elem );
5607 aMesh->ChangePolygonNodes(elem, poly_nodes);
5611 case SMDSAbs_Volume:
5613 // ATTENTION: Reversing is not yet done!!!
5614 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5615 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5617 MESSAGE("Warning: bad volumic element");
5621 vector<const SMDS_MeshNode*> poly_nodes;
5622 vector<int> quantities;
5624 bool allTransformed = true;
5625 int nbFaces = aPolyedre->NbFaces();
5626 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5627 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5628 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5629 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5630 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5631 if (nodeMapIt == nodeMap.end()) {
5632 allTransformed = false; // not all nodes transformed
5634 poly_nodes.push_back((*nodeMapIt).second);
5637 quantities.push_back(nbFaceNodes);
5639 if ( !allTransformed )
5640 continue; // not all nodes transformed
5642 if ( theTargetMesh ) {
5643 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5644 srcElems.Append( elem );
5646 else if ( theCopy ) {
5647 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5648 srcElems.Append( elem );
5651 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5661 int* i = index[ FORWARD ];
5662 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5663 // if ( elemType == SMDSAbs_Face )
5664 // i = index[ REV_FACE ];
5666 // i = index[ nbNodes - 4 ];
5668 if(elem->IsQuadratic()) {
5669 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5672 // if(nbNodes==3) { // quadratic edge
5673 // static int anIds[] = {1,0,2};
5676 // else if(nbNodes==6) { // quadratic triangle
5677 // static int anIds[] = {0,2,1,5,4,3};
5680 // else if(nbNodes==8) { // quadratic quadrangle
5681 // static int anIds[] = {0,3,2,1,7,6,5,4};
5684 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5685 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5688 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5689 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5692 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5693 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5696 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5697 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5703 // find transformed nodes
5704 vector<const SMDS_MeshNode*> nodes(nbNodes);
5706 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5707 while ( itN->more() ) {
5708 const SMDS_MeshNode* node =
5709 static_cast<const SMDS_MeshNode*>( itN->next() );
5710 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5711 if ( nodeMapIt == nodeMap.end() )
5712 break; // not all nodes transformed
5713 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5715 if ( iNode != nbNodes )
5716 continue; // not all nodes transformed
5718 if ( theTargetMesh ) {
5719 if ( SMDS_MeshElement* copy =
5720 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5721 myLastCreatedElems.Append( copy );
5722 srcElems.Append( elem );
5725 else if ( theCopy ) {
5726 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5727 myLastCreatedElems.Append( copy );
5728 srcElems.Append( elem );
5732 // reverse element as it was reversed by transformation
5734 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5738 PGroupIDs newGroupIDs;
5740 if ( theMakeGroups && theCopy ||
5741 theMakeGroups && theTargetMesh ) {
5742 string groupPostfix = "scaled";
5743 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5750 //=======================================================================
5752 * \brief Create groups of elements made during transformation
5753 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5754 * \param elemGens - elements making corresponding myLastCreatedElems
5755 * \param postfix - to append to names of new groups
5757 //=======================================================================
5759 SMESH_MeshEditor::PGroupIDs
5760 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5761 const SMESH_SequenceOfElemPtr& elemGens,
5762 const std::string& postfix,
5763 SMESH_Mesh* targetMesh)
5765 PGroupIDs newGroupIDs( new list<int> );
5766 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5768 // Sort existing groups by types and collect their names
5770 // to store an old group and a generated new one
5771 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5772 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5774 set< string > groupNames;
5776 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5777 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5778 while ( groupIt->more() ) {
5779 SMESH_Group * group = groupIt->next();
5780 if ( !group ) continue;
5781 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5782 if ( !groupDS || groupDS->IsEmpty() ) continue;
5783 groupNames.insert( group->GetName() );
5784 groupDS->SetStoreName( group->GetName() );
5785 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5790 // loop on nodes and elements
5791 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5793 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5794 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5795 if ( gens.Length() != elems.Length() )
5796 throw SALOME_Exception(LOCALIZED("invalid args"));
5798 // loop on created elements
5799 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5801 const SMDS_MeshElement* sourceElem = gens( iElem );
5802 if ( !sourceElem ) {
5803 MESSAGE("generateGroups(): NULL source element");
5806 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5807 if ( groupsOldNew.empty() ) {
5808 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5809 ++iElem; // skip all elements made by sourceElem
5812 // collect all elements made by sourceElem
5813 list< const SMDS_MeshElement* > resultElems;
5814 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5815 if ( resElem != sourceElem )
5816 resultElems.push_back( resElem );
5817 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5818 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5819 if ( resElem != sourceElem )
5820 resultElems.push_back( resElem );
5821 // do not generate element groups from node ones
5822 if ( sourceElem->GetType() == SMDSAbs_Node &&
5823 elems( iElem )->GetType() != SMDSAbs_Node )
5826 // add resultElems to groups made by ones the sourceElem belongs to
5827 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5828 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5830 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5831 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5833 SMDS_MeshGroup* & newGroup = gOldNew->second;
5834 if ( !newGroup )// create a new group
5837 string name = oldGroup->GetStoreName();
5838 if ( !targetMesh ) {
5842 while ( !groupNames.insert( name ).second ) // name exists
5848 TCollection_AsciiString nbStr(nb+1);
5849 name.resize( name.rfind('_')+1 );
5850 name += nbStr.ToCString();
5857 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5859 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5860 newGroup = & groupDS->SMDSGroup();
5861 newGroupIDs->push_back( id );
5864 // fill in a new group
5865 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5866 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5867 newGroup->Add( *resElemIt );
5870 } // loop on created elements
5871 }// loop on nodes and elements
5876 //================================================================================
5878 * \brief Return list of group of nodes close to each other within theTolerance
5879 * Search among theNodes or in the whole mesh if theNodes is empty using
5880 * an Octree algorithm
5882 //================================================================================
5884 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5885 const double theTolerance,
5886 TListOfListOfNodes & theGroupsOfNodes)
5888 myLastCreatedElems.Clear();
5889 myLastCreatedNodes.Clear();
5891 set<const SMDS_MeshNode*> nodes;
5892 if ( theNodes.empty() )
5893 { // get all nodes in the mesh
5894 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5895 while ( nIt->more() )
5896 nodes.insert( nodes.end(),nIt->next());
5901 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5905 //=======================================================================
5907 * \brief Implementation of search for the node closest to point
5909 //=======================================================================
5911 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5913 //---------------------------------------------------------------------
5915 * \brief Constructor
5917 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5919 myMesh = ( SMESHDS_Mesh* ) theMesh;
5921 set<const SMDS_MeshNode*> nodes;
5923 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5924 while ( nIt->more() )
5925 nodes.insert( nodes.end(), nIt->next() );
5927 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5929 // get max size of a leaf box
5930 SMESH_OctreeNode* tree = myOctreeNode;
5931 while ( !tree->isLeaf() )
5933 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5937 myHalfLeafSize = tree->maxSize() / 2.;
5940 //---------------------------------------------------------------------
5942 * \brief Move node and update myOctreeNode accordingly
5944 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5946 myOctreeNode->UpdateByMoveNode( node, toPnt );
5947 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5950 //---------------------------------------------------------------------
5952 * \brief Do it's job
5954 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5956 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5957 map<double, const SMDS_MeshNode*> dist2Nodes;
5958 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5959 if ( !dist2Nodes.empty() )
5960 return dist2Nodes.begin()->second;
5961 list<const SMDS_MeshNode*> nodes;
5962 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5964 double minSqDist = DBL_MAX;
5965 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5967 // sort leafs by their distance from thePnt
5968 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5969 TDistTreeMap treeMap;
5970 list< SMESH_OctreeNode* > treeList;
5971 list< SMESH_OctreeNode* >::iterator trIt;
5972 treeList.push_back( myOctreeNode );
5974 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
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 ( !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 double getTolerance();
6272 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6273 const double tolerance, double & param);
6274 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6275 bool isOuterBoundary(const SMDS_MeshElement* face) const
6277 return _outerFaces.empty() || _outerFaces.count(face);
6279 struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6281 const SMDS_MeshElement* _face;
6283 bool _coincides; //!< the line lays in face plane
6284 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6285 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6287 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6290 TIDSortedElemSet _faces;
6291 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6292 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6296 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6298 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6299 << ", _coincides="<<i._coincides << ")";
6302 //=======================================================================
6304 * \brief define tolerance for search
6306 //=======================================================================
6308 double SMESH_ElementSearcherImpl::getTolerance()
6310 if ( _tolerance < 0 )
6312 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6315 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6317 double boxSize = _nodeSearcher->getTree()->maxSize();
6318 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6320 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6322 double boxSize = _ebbTree->maxSize();
6323 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6325 if ( _tolerance == 0 )
6327 // define tolerance by size of a most complex element
6328 int complexType = SMDSAbs_Volume;
6329 while ( complexType > SMDSAbs_All &&
6330 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6332 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6335 if ( complexType == int( SMDSAbs_Node ))
6337 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6339 if ( meshInfo.NbNodes() > 2 )
6340 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6344 const SMDS_MeshElement* elem =
6345 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6346 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6347 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6348 while ( nodeIt->more() )
6350 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6351 elemSize = max( dist, elemSize );
6354 _tolerance = 1e-6 * elemSize;
6360 //================================================================================
6362 * \brief Find intersection of the line and an edge of face and return parameter on line
6364 //================================================================================
6366 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6367 const SMDS_MeshElement* face,
6374 GeomAPI_ExtremaCurveCurve anExtCC;
6375 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6377 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6378 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6380 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6381 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6382 anExtCC.Init( lineCurve, edge);
6383 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6385 Quantity_Parameter pl, pe;
6386 anExtCC.LowerDistanceParameters( pl, pe );
6388 if ( ++nbInts == 2 )
6392 if ( nbInts > 0 ) param /= nbInts;
6395 //================================================================================
6397 * \brief Find all faces belonging to the outer boundary of mesh
6399 //================================================================================
6401 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6403 if ( _outerFacesFound ) return;
6405 // Collect all outer faces by passing from one outer face to another via their links
6406 // and BTW find out if there are internal faces at all.
6408 // checked links and links where outer boundary meets internal one
6409 set< SMESH_TLink > visitedLinks, seamLinks;
6411 // links to treat with already visited faces sharing them
6412 list < TFaceLink > startLinks;
6414 // load startLinks with the first outerFace
6415 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6416 _outerFaces.insert( outerFace );
6418 TIDSortedElemSet emptySet;
6419 while ( !startLinks.empty() )
6421 const SMESH_TLink& link = startLinks.front()._link;
6422 TIDSortedElemSet& faces = startLinks.front()._faces;
6424 outerFace = *faces.begin();
6425 // find other faces sharing the link
6426 const SMDS_MeshElement* f;
6427 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6430 // select another outer face among the found
6431 const SMDS_MeshElement* outerFace2 = 0;
6432 if ( faces.size() == 2 )
6434 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6436 else if ( faces.size() > 2 )
6438 seamLinks.insert( link );
6440 // link direction within the outerFace
6441 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6442 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6443 int i1 = outerFace->GetNodeIndex( link.node1() );
6444 int i2 = outerFace->GetNodeIndex( link.node2() );
6445 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6446 if ( rev ) n1n2.Reverse();
6448 gp_XYZ ofNorm, fNorm;
6449 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6451 // direction from the link inside outerFace
6452 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6453 // sort all other faces by angle with the dirInOF
6454 map< double, const SMDS_MeshElement* > angle2Face;
6455 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6456 for ( ; face != faces.end(); ++face )
6458 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6460 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6461 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6462 if ( angle < 0 ) angle += 2*PI;
6463 angle2Face.insert( make_pair( angle, *face ));
6465 if ( !angle2Face.empty() )
6466 outerFace2 = angle2Face.begin()->second;
6469 // store the found outer face and add its links to continue seaching from
6472 _outerFaces.insert( outerFace );
6473 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6474 for ( int i = 0; i < nbNodes; ++i )
6476 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6477 if ( visitedLinks.insert( link2 ).second )
6478 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6481 startLinks.pop_front();
6483 _outerFacesFound = true;
6485 if ( !seamLinks.empty() )
6487 // There are internal boundaries touching the outher one,
6488 // find all faces of internal boundaries in order to find
6489 // faces of boundaries of holes, if any.
6494 _outerFaces.clear();
6498 //=======================================================================
6500 * \brief Find elements of given type where the given point is IN or ON.
6501 * Returns nb of found elements and elements them-selves.
6503 * 'ALL' type means elements of any type excluding nodes and 0D elements
6505 //=======================================================================
6507 int SMESH_ElementSearcherImpl::
6508 FindElementsByPoint(const gp_Pnt& point,
6509 SMDSAbs_ElementType type,
6510 vector< const SMDS_MeshElement* >& foundElements)
6512 foundElements.clear();
6514 double tolerance = getTolerance();
6516 // =================================================================================
6517 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6519 if ( !_nodeSearcher )
6520 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6522 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6523 if ( !closeNode ) return foundElements.size();
6525 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6526 return foundElements.size(); // to far from any node
6528 if ( type == SMDSAbs_Node )
6530 foundElements.push_back( closeNode );
6534 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6535 while ( elemIt->more() )
6536 foundElements.push_back( elemIt->next() );
6539 // =================================================================================
6540 else // elements more complex than 0D
6542 if ( !_ebbTree || _elementType != type )
6544 if ( _ebbTree ) delete _ebbTree;
6545 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6547 TIDSortedElemSet suspectElems;
6548 _ebbTree->getElementsNearPoint( point, suspectElems );
6549 TIDSortedElemSet::iterator elem = suspectElems.begin();
6550 for ( ; elem != suspectElems.end(); ++elem )
6551 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6552 foundElements.push_back( *elem );
6554 return foundElements.size();
6557 //================================================================================
6559 * \brief Classify the given point in the closed 2D mesh
6561 //================================================================================
6563 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6565 double tolerance = getTolerance();
6566 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6568 if ( _ebbTree ) delete _ebbTree;
6569 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6571 // Algo: analyse transition of a line starting at the point through mesh boundary;
6572 // try three lines parallel to axis of the coordinate system and perform rough
6573 // analysis. If solution is not clear perform thorough analysis.
6575 const int nbAxes = 3;
6576 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6577 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6578 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6579 multimap< int, int > nbInt2Axis; // to find the simplest case
6580 for ( int axis = 0; axis < nbAxes; ++axis )
6582 gp_Ax1 lineAxis( point, axisDir[axis]);
6583 gp_Lin line ( lineAxis );
6585 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6586 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6588 // Intersect faces with the line
6590 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6591 TIDSortedElemSet::iterator face = suspectFaces.begin();
6592 for ( ; face != suspectFaces.end(); ++face )
6596 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6597 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6599 // perform intersection
6600 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6601 if ( !intersection.IsDone() )
6603 if ( intersection.IsInQuadric() )
6605 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6607 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6609 gp_Pnt intersectionPoint = intersection.Point(1);
6610 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6611 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6614 // Analyse intersections roughly
6616 int nbInter = u2inters.size();
6620 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6621 if ( nbInter == 1 ) // not closed mesh
6622 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6624 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6627 if ( (f<0) == (l<0) )
6630 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6631 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6632 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6635 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6637 if ( _outerFacesFound ) break; // pass to thorough analysis
6639 } // three attempts - loop on CS axes
6641 // Analyse intersections thoroughly.
6642 // We make two loops maximum, on the first one we only exclude touching intersections,
6643 // on the second, if situation is still unclear, we gather and use information on
6644 // position of faces (internal or outer). If faces position is already gathered,
6645 // we make the second loop right away.
6647 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6649 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6650 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6652 int axis = nb_axis->second;
6653 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6655 gp_Ax1 lineAxis( point, axisDir[axis]);
6656 gp_Lin line ( lineAxis );
6658 // add tangent intersections to u2inters
6660 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6661 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6662 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6663 u2inters.insert(make_pair( param, *tgtInt ));
6664 tangentInters[ axis ].clear();
6666 // Count intersections before and after the point excluding touching ones.
6667 // If hasPositionInfo we count intersections of outer boundary only
6669 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6670 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6671 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6672 bool ok = ! u_int1->second._coincides;
6673 while ( ok && u_int1 != u2inters.end() )
6675 double u = u_int1->first;
6676 bool touchingInt = false;
6677 if ( ++u_int2 != u2inters.end() )
6679 // skip intersections at the same point (if the line passes through edge or node)
6681 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6687 // skip tangent intersections
6689 const SMDS_MeshElement* prevFace = u_int1->second._face;
6690 while ( ok && u_int2->second._coincides )
6692 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6698 ok = ( u_int2 != u2inters.end() );
6703 // skip intersections at the same point after tangent intersections
6706 double u2 = u_int2->first;
6708 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6714 // decide if we skipped a touching intersection
6715 if ( nbSamePnt + nbTgt > 0 )
6717 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6718 map< double, TInters >::iterator u_int = u_int1;
6719 for ( ; u_int != u_int2; ++u_int )
6721 if ( u_int->second._coincides ) continue;
6722 double dot = u_int->second._faceNorm * line.Direction();
6723 if ( dot > maxDot ) maxDot = dot;
6724 if ( dot < minDot ) minDot = dot;
6726 touchingInt = ( minDot*maxDot < 0 );
6731 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6742 u_int1 = u_int2; // to next intersection
6744 } // loop on intersections with one line
6748 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6751 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6754 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6755 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6757 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6760 if ( (f<0) == (l<0) )
6763 if ( hasPositionInfo )
6764 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6766 } // loop on intersections of the tree lines - thorough analysis
6768 if ( !hasPositionInfo )
6770 // gather info on faces position - is face in the outer boundary or not
6771 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6772 findOuterBoundary( u2inters.begin()->second._face );
6775 } // two attempts - with and w/o faces position info in the mesh
6777 return TopAbs_UNKNOWN;
6780 //=======================================================================
6782 * \brief Return SMESH_ElementSearcher
6784 //=======================================================================
6786 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6788 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6791 //=======================================================================
6793 * \brief Return true if the point is IN or ON of the element
6795 //=======================================================================
6797 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6799 if ( element->GetType() == SMDSAbs_Volume)
6801 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6804 // get ordered nodes
6806 vector< gp_XYZ > xyz;
6808 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6809 if ( element->IsQuadratic() )
6810 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6811 nodeIt = f->interlacedNodesElemIterator();
6812 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6813 nodeIt = e->interlacedNodesElemIterator();
6815 while ( nodeIt->more() )
6816 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6818 int i, nbNodes = element->NbNodes();
6820 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6822 // compute face normal
6823 gp_Vec faceNorm(0,0,0);
6824 xyz.push_back( xyz.front() );
6825 for ( i = 0; i < nbNodes; ++i )
6827 gp_Vec edge1( xyz[i+1], xyz[i]);
6828 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6829 faceNorm += edge1 ^ edge2;
6831 double normSize = faceNorm.Magnitude();
6832 if ( normSize <= tol )
6834 // degenerated face: point is out if it is out of all face edges
6835 for ( i = 0; i < nbNodes; ++i )
6837 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6838 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6839 SMDS_MeshEdge edge( &n1, &n2 );
6840 if ( !isOut( &edge, point, tol ))
6845 faceNorm /= normSize;
6847 // check if the point lays on face plane
6848 gp_Vec n2p( xyz[0], point );
6849 if ( fabs( n2p * faceNorm ) > tol )
6850 return true; // not on face plane
6852 // check if point is out of face boundary:
6853 // define it by closest transition of a ray point->infinity through face boundary
6854 // on the face plane.
6855 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6856 // to find intersections of the ray with the boundary.
6858 gp_Vec plnNorm = ray ^ faceNorm;
6859 normSize = plnNorm.Magnitude();
6860 if ( normSize <= tol ) return false; // point coincides with the first node
6861 plnNorm /= normSize;
6862 // for each node of the face, compute its signed distance to the plane
6863 vector<double> dist( nbNodes + 1);
6864 for ( i = 0; i < nbNodes; ++i )
6866 gp_Vec n2p( xyz[i], point );
6867 dist[i] = n2p * plnNorm;
6869 dist.back() = dist.front();
6870 // find the closest intersection
6872 double rClosest, distClosest = 1e100;;
6874 for ( i = 0; i < nbNodes; ++i )
6877 if ( fabs( dist[i]) < tol )
6879 else if ( fabs( dist[i+1]) < tol )
6881 else if ( dist[i] * dist[i+1] < 0 )
6882 r = dist[i] / ( dist[i] - dist[i+1] );
6884 continue; // no intersection
6885 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6886 gp_Vec p2int ( point, pInt);
6887 if ( p2int * ray > -tol ) // right half-space
6889 double intDist = p2int.SquareMagnitude();
6890 if ( intDist < distClosest )
6895 distClosest = intDist;
6900 return true; // no intesections - out
6902 // analyse transition
6903 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6904 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6905 gp_Vec p2int ( point, pClosest );
6906 bool out = (edgeNorm * p2int) < -tol;
6907 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6910 // ray pass through a face node; analyze transition through an adjacent edge
6911 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6912 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6913 gp_Vec edgeAdjacent( p1, p2 );
6914 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6915 bool out2 = (edgeNorm2 * p2int) < -tol;
6917 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6918 return covexCorner ? (out || out2) : (out && out2);
6920 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6922 // point is out of edge if it is NOT ON any straight part of edge
6923 // (we consider quadratic edge as being composed of two straight parts)
6924 for ( i = 1; i < nbNodes; ++i )
6926 gp_Vec edge( xyz[i-1], xyz[i]);
6927 gp_Vec n1p ( xyz[i-1], point);
6928 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6931 gp_Vec n2p( xyz[i], point );
6932 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6934 return false; // point is ON this part
6938 // Node or 0D element -------------------------------------------------------------------------
6940 gp_Vec n2p ( xyz[0], point );
6941 return n2p.Magnitude() <= tol;
6946 //=======================================================================
6947 //function : SimplifyFace
6949 //=======================================================================
6950 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6951 vector<const SMDS_MeshNode *>& poly_nodes,
6952 vector<int>& quantities) const
6954 int nbNodes = faceNodes.size();
6959 set<const SMDS_MeshNode*> nodeSet;
6961 // get simple seq of nodes
6962 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6963 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6964 int iSimple = 0, nbUnique = 0;
6966 simpleNodes[iSimple++] = faceNodes[0];
6968 for (int iCur = 1; iCur < nbNodes; iCur++) {
6969 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6970 simpleNodes[iSimple++] = faceNodes[iCur];
6971 if (nodeSet.insert( faceNodes[iCur] ).second)
6975 int nbSimple = iSimple;
6976 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6986 bool foundLoop = (nbSimple > nbUnique);
6989 set<const SMDS_MeshNode*> loopSet;
6990 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6991 const SMDS_MeshNode* n = simpleNodes[iSimple];
6992 if (!loopSet.insert( n ).second) {
6996 int iC = 0, curLast = iSimple;
6997 for (; iC < curLast; iC++) {
6998 if (simpleNodes[iC] == n) break;
7000 int loopLen = curLast - iC;
7002 // create sub-element
7004 quantities.push_back(loopLen);
7005 for (; iC < curLast; iC++) {
7006 poly_nodes.push_back(simpleNodes[iC]);
7009 // shift the rest nodes (place from the first loop position)
7010 for (iC = curLast + 1; iC < nbSimple; iC++) {
7011 simpleNodes[iC - loopLen] = simpleNodes[iC];
7013 nbSimple -= loopLen;
7016 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7017 } // while (foundLoop)
7021 quantities.push_back(iSimple);
7022 for (int i = 0; i < iSimple; i++)
7023 poly_nodes.push_back(simpleNodes[i]);
7029 //=======================================================================
7030 //function : MergeNodes
7031 //purpose : In each group, the cdr of nodes are substituted by the first one
7033 //=======================================================================
7035 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7037 myLastCreatedElems.Clear();
7038 myLastCreatedNodes.Clear();
7040 SMESHDS_Mesh* aMesh = GetMeshDS();
7042 TNodeNodeMap nodeNodeMap; // node to replace - new node
7043 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7044 list< int > rmElemIds, rmNodeIds;
7046 // Fill nodeNodeMap and elems
7048 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7049 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7050 list<const SMDS_MeshNode*>& nodes = *grIt;
7051 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7052 const SMDS_MeshNode* nToKeep = *nIt;
7053 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7054 const SMDS_MeshNode* nToRemove = *nIt;
7055 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7056 if ( nToRemove != nToKeep ) {
7057 rmNodeIds.push_back( nToRemove->GetID() );
7058 AddToSameGroups( nToKeep, nToRemove, aMesh );
7061 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7062 while ( invElemIt->more() ) {
7063 const SMDS_MeshElement* elem = invElemIt->next();
7068 // Change element nodes or remove an element
7070 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7071 for ( ; eIt != elems.end(); eIt++ ) {
7072 const SMDS_MeshElement* elem = *eIt;
7073 int nbNodes = elem->NbNodes();
7074 int aShapeId = FindShape( elem );
7076 set<const SMDS_MeshNode*> nodeSet;
7077 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7078 int iUnique = 0, iCur = 0, nbRepl = 0;
7079 vector<int> iRepl( nbNodes );
7081 // get new seq of nodes
7082 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7083 while ( itN->more() ) {
7084 const SMDS_MeshNode* n =
7085 static_cast<const SMDS_MeshNode*>( itN->next() );
7087 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7088 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7090 // BUG 0020185: begin
7092 bool stopRecur = false;
7093 set<const SMDS_MeshNode*> nodesRecur;
7094 nodesRecur.insert(n);
7095 while (!stopRecur) {
7096 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7097 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7098 n = (*nnIt_i).second;
7099 if (!nodesRecur.insert(n).second) {
7100 // error: recursive dependancy
7109 iRepl[ nbRepl++ ] = iCur;
7111 curNodes[ iCur ] = n;
7112 bool isUnique = nodeSet.insert( n ).second;
7114 uniqueNodes[ iUnique++ ] = n;
7118 // Analyse element topology after replacement
7121 int nbUniqueNodes = nodeSet.size();
7122 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7123 // Polygons and Polyhedral volumes
7124 if (elem->IsPoly()) {
7126 if (elem->GetType() == SMDSAbs_Face) {
7128 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7130 for (; inode < nbNodes; inode++) {
7131 face_nodes[inode] = curNodes[inode];
7134 vector<const SMDS_MeshNode *> polygons_nodes;
7135 vector<int> quantities;
7136 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7140 for (int iface = 0; iface < nbNew - 1; iface++) {
7141 int nbNodes = quantities[iface];
7142 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7143 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7144 poly_nodes[ii] = polygons_nodes[inode];
7146 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7147 myLastCreatedElems.Append(newElem);
7149 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7151 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7154 rmElemIds.push_back(elem->GetID());
7158 else if (elem->GetType() == SMDSAbs_Volume) {
7159 // Polyhedral volume
7160 if (nbUniqueNodes < 4) {
7161 rmElemIds.push_back(elem->GetID());
7164 // each face has to be analized in order to check volume validity
7165 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7166 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7168 int nbFaces = aPolyedre->NbFaces();
7170 vector<const SMDS_MeshNode *> poly_nodes;
7171 vector<int> quantities;
7173 for (int iface = 1; iface <= nbFaces; iface++) {
7174 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7175 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7177 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7178 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7179 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7180 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7181 faceNode = (*nnIt).second;
7183 faceNodes[inode - 1] = faceNode;
7186 SimplifyFace(faceNodes, poly_nodes, quantities);
7189 if (quantities.size() > 3) {
7190 // to be done: remove coincident faces
7193 if (quantities.size() > 3)
7194 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7196 rmElemIds.push_back(elem->GetID());
7200 rmElemIds.push_back(elem->GetID());
7211 switch ( nbNodes ) {
7212 case 2: ///////////////////////////////////// EDGE
7213 isOk = false; break;
7214 case 3: ///////////////////////////////////// TRIANGLE
7215 isOk = false; break;
7217 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7219 else { //////////////////////////////////// QUADRANGLE
7220 if ( nbUniqueNodes < 3 )
7222 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7223 isOk = false; // opposite nodes stick
7226 case 6: ///////////////////////////////////// PENTAHEDRON
7227 if ( nbUniqueNodes == 4 ) {
7228 // ---------------------------------> tetrahedron
7230 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7231 // all top nodes stick: reverse a bottom
7232 uniqueNodes[ 0 ] = curNodes [ 1 ];
7233 uniqueNodes[ 1 ] = curNodes [ 0 ];
7235 else if (nbRepl == 3 &&
7236 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7237 // all bottom nodes stick: set a top before
7238 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7239 uniqueNodes[ 0 ] = curNodes [ 3 ];
7240 uniqueNodes[ 1 ] = curNodes [ 4 ];
7241 uniqueNodes[ 2 ] = curNodes [ 5 ];
7243 else if (nbRepl == 4 &&
7244 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7245 // a lateral face turns into a line: reverse a bottom
7246 uniqueNodes[ 0 ] = curNodes [ 1 ];
7247 uniqueNodes[ 1 ] = curNodes [ 0 ];
7252 else if ( nbUniqueNodes == 5 ) {
7253 // PENTAHEDRON --------------------> 2 tetrahedrons
7254 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7255 // a bottom node sticks with a linked top one
7257 SMDS_MeshElement* newElem =
7258 aMesh->AddVolume(curNodes[ 3 ],
7261 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7262 myLastCreatedElems.Append(newElem);
7264 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7265 // 2. : reverse a bottom
7266 uniqueNodes[ 0 ] = curNodes [ 1 ];
7267 uniqueNodes[ 1 ] = curNodes [ 0 ];
7277 if(elem->IsQuadratic()) { // Quadratic quadrangle
7290 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7291 uniqueNodes[0] = curNodes[0];
7292 uniqueNodes[1] = curNodes[2];
7293 uniqueNodes[2] = curNodes[3];
7294 uniqueNodes[3] = curNodes[5];
7295 uniqueNodes[4] = curNodes[6];
7296 uniqueNodes[5] = curNodes[7];
7299 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7300 uniqueNodes[0] = curNodes[0];
7301 uniqueNodes[1] = curNodes[1];
7302 uniqueNodes[2] = curNodes[2];
7303 uniqueNodes[3] = curNodes[4];
7304 uniqueNodes[4] = curNodes[5];
7305 uniqueNodes[5] = curNodes[6];
7308 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7309 uniqueNodes[0] = curNodes[1];
7310 uniqueNodes[1] = curNodes[2];
7311 uniqueNodes[2] = curNodes[3];
7312 uniqueNodes[3] = curNodes[5];
7313 uniqueNodes[4] = curNodes[6];
7314 uniqueNodes[5] = curNodes[0];
7317 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7318 uniqueNodes[0] = curNodes[0];
7319 uniqueNodes[1] = curNodes[1];
7320 uniqueNodes[2] = curNodes[3];
7321 uniqueNodes[3] = curNodes[4];
7322 uniqueNodes[4] = curNodes[6];
7323 uniqueNodes[5] = curNodes[7];
7326 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7327 uniqueNodes[0] = curNodes[0];
7328 uniqueNodes[1] = curNodes[2];
7329 uniqueNodes[2] = curNodes[3];
7330 uniqueNodes[3] = curNodes[1];
7331 uniqueNodes[4] = curNodes[6];
7332 uniqueNodes[5] = curNodes[7];
7335 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7336 uniqueNodes[0] = curNodes[0];
7337 uniqueNodes[1] = curNodes[1];
7338 uniqueNodes[2] = curNodes[2];
7339 uniqueNodes[3] = curNodes[4];
7340 uniqueNodes[4] = curNodes[5];
7341 uniqueNodes[5] = curNodes[7];
7344 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7345 uniqueNodes[0] = curNodes[0];
7346 uniqueNodes[1] = curNodes[1];
7347 uniqueNodes[2] = curNodes[3];
7348 uniqueNodes[3] = curNodes[4];
7349 uniqueNodes[4] = curNodes[2];
7350 uniqueNodes[5] = curNodes[7];
7353 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7354 uniqueNodes[0] = curNodes[0];
7355 uniqueNodes[1] = curNodes[1];
7356 uniqueNodes[2] = curNodes[2];
7357 uniqueNodes[3] = curNodes[4];
7358 uniqueNodes[4] = curNodes[5];
7359 uniqueNodes[5] = curNodes[3];
7365 //////////////////////////////////// HEXAHEDRON
7367 SMDS_VolumeTool hexa (elem);
7368 hexa.SetExternalNormal();
7369 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7370 //////////////////////// ---> tetrahedron
7371 for ( int iFace = 0; iFace < 6; iFace++ ) {
7372 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7373 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7374 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7375 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7376 // one face turns into a point ...
7377 int iOppFace = hexa.GetOppFaceIndex( iFace );
7378 ind = hexa.GetFaceNodesIndices( iOppFace );
7380 iUnique = 2; // reverse a tetrahedron bottom
7381 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7382 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7384 else if ( iUnique >= 0 )
7385 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7387 if ( nbStick == 1 ) {
7388 // ... and the opposite one - into a triangle.
7390 ind = hexa.GetFaceNodesIndices( iFace );
7391 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7398 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7399 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7400 for ( int iFace = 0; iFace < 6; iFace++ ) {
7401 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7402 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7403 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7404 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7405 // one face turns into a point ...
7406 int iOppFace = hexa.GetOppFaceIndex( iFace );
7407 ind = hexa.GetFaceNodesIndices( iOppFace );
7409 iUnique = 2; // reverse a tetrahedron 1 bottom
7410 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7411 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7413 else if ( iUnique >= 0 )
7414 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7416 if ( nbStick == 0 ) {
7417 // ... and the opposite one is a quadrangle
7419 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7420 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7423 SMDS_MeshElement* newElem =
7424 aMesh->AddVolume(curNodes[ind[ 0 ]],
7427 curNodes[indTop[ 0 ]]);
7428 myLastCreatedElems.Append(newElem);
7430 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7437 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7438 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7439 // find indices of quad and tri faces
7440 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7441 for ( iFace = 0; iFace < 6; iFace++ ) {
7442 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7444 for ( iCur = 0; iCur < 4; iCur++ )
7445 nodeSet.insert( curNodes[ind[ iCur ]] );
7446 nbUniqueNodes = nodeSet.size();
7447 if ( nbUniqueNodes == 3 )
7448 iTriFace[ nbTri++ ] = iFace;
7449 else if ( nbUniqueNodes == 4 )
7450 iQuadFace[ nbQuad++ ] = iFace;
7452 if (nbQuad == 2 && nbTri == 4 &&
7453 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7454 // 2 opposite quadrangles stuck with a diagonal;
7455 // sample groups of merged indices: (0-4)(2-6)
7456 // --------------------------------------------> 2 tetrahedrons
7457 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7458 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7459 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7460 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7461 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7462 // stuck with 0-2 diagonal
7470 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7471 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7472 // stuck with 1-3 diagonal
7484 uniqueNodes[ 0 ] = curNodes [ i0 ];
7485 uniqueNodes[ 1 ] = curNodes [ i1d ];
7486 uniqueNodes[ 2 ] = curNodes [ i3d ];
7487 uniqueNodes[ 3 ] = curNodes [ i0t ];
7490 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7494 myLastCreatedElems.Append(newElem);
7496 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7499 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7500 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7501 // --------------------------------------------> prism
7502 // find 2 opposite triangles
7504 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7505 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7506 // find indices of kept and replaced nodes
7507 // and fill unique nodes of 2 opposite triangles
7508 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7509 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7510 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7511 // fill unique nodes
7514 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7515 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7516 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7518 // iCur of a linked node of the opposite face (make normals co-directed):
7519 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7520 // check that correspondent corners of triangles are linked
7521 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7524 uniqueNodes[ iUnique ] = n;
7525 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7534 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7540 } // switch ( nbNodes )
7542 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7545 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7546 // Change nodes of polyedre
7547 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7548 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7550 int nbFaces = aPolyedre->NbFaces();
7552 vector<const SMDS_MeshNode *> poly_nodes;
7553 vector<int> quantities (nbFaces);
7555 for (int iface = 1; iface <= nbFaces; iface++) {
7556 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7557 quantities[iface - 1] = nbFaceNodes;
7559 for (inode = 1; inode <= nbFaceNodes; inode++) {
7560 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7562 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7563 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7564 curNode = (*nnIt).second;
7566 poly_nodes.push_back(curNode);
7569 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7573 // Change regular element or polygon
7574 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7578 // Remove invalid regular element or invalid polygon
7579 rmElemIds.push_back( elem->GetID() );
7582 } // loop on elements
7584 // Remove equal nodes and bad elements
7586 Remove( rmNodeIds, true );
7587 Remove( rmElemIds, false );
7592 // ========================================================
7593 // class : SortableElement
7594 // purpose : allow sorting elements basing on their nodes
7595 // ========================================================
7596 class SortableElement : public set <const SMDS_MeshElement*>
7600 SortableElement( const SMDS_MeshElement* theElem )
7603 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7604 while ( nodeIt->more() )
7605 this->insert( nodeIt->next() );
7608 const SMDS_MeshElement* Get() const
7611 void Set(const SMDS_MeshElement* e) const
7616 mutable const SMDS_MeshElement* myElem;
7619 //=======================================================================
7620 //function : FindEqualElements
7621 //purpose : Return list of group of elements built on the same nodes.
7622 // Search among theElements or in the whole mesh if theElements is empty
7623 //=======================================================================
7624 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7625 TListOfListOfElementsID & theGroupsOfElementsID)
7627 myLastCreatedElems.Clear();
7628 myLastCreatedNodes.Clear();
7630 typedef set<const SMDS_MeshElement*> TElemsSet;
7631 typedef map< SortableElement, int > TMapOfNodeSet;
7632 typedef list<int> TGroupOfElems;
7635 if ( theElements.empty() )
7636 { // get all elements in the mesh
7637 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7638 while ( eIt->more() )
7639 elems.insert( elems.end(), eIt->next());
7642 elems = theElements;
7644 vector< TGroupOfElems > arrayOfGroups;
7645 TGroupOfElems groupOfElems;
7646 TMapOfNodeSet mapOfNodeSet;
7648 TElemsSet::iterator elemIt = elems.begin();
7649 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7650 const SMDS_MeshElement* curElem = *elemIt;
7651 SortableElement SE(curElem);
7654 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7655 if( !(pp.second) ) {
7656 TMapOfNodeSet::iterator& itSE = pp.first;
7657 ind = (*itSE).second;
7658 arrayOfGroups[ind].push_back(curElem->GetID());
7661 groupOfElems.clear();
7662 groupOfElems.push_back(curElem->GetID());
7663 arrayOfGroups.push_back(groupOfElems);
7668 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7669 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7670 groupOfElems = *groupIt;
7671 if ( groupOfElems.size() > 1 ) {
7672 groupOfElems.sort();
7673 theGroupsOfElementsID.push_back(groupOfElems);
7678 //=======================================================================
7679 //function : MergeElements
7680 //purpose : In each given group, substitute all elements by the first one.
7681 //=======================================================================
7683 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7685 myLastCreatedElems.Clear();
7686 myLastCreatedNodes.Clear();
7688 typedef list<int> TListOfIDs;
7689 TListOfIDs rmElemIds; // IDs of elems to remove
7691 SMESHDS_Mesh* aMesh = GetMeshDS();
7693 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7694 while ( groupsIt != theGroupsOfElementsID.end() ) {
7695 TListOfIDs& aGroupOfElemID = *groupsIt;
7696 aGroupOfElemID.sort();
7697 int elemIDToKeep = aGroupOfElemID.front();
7698 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7699 aGroupOfElemID.pop_front();
7700 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7701 while ( idIt != aGroupOfElemID.end() ) {
7702 int elemIDToRemove = *idIt;
7703 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7704 // add the kept element in groups of removed one (PAL15188)
7705 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7706 rmElemIds.push_back( elemIDToRemove );
7712 Remove( rmElemIds, false );
7715 //=======================================================================
7716 //function : MergeEqualElements
7717 //purpose : Remove all but one of elements built on the same nodes.
7718 //=======================================================================
7720 void SMESH_MeshEditor::MergeEqualElements()
7722 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7723 to merge equal elements in the whole mesh */
7724 TListOfListOfElementsID aGroupsOfElementsID;
7725 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7726 MergeElements(aGroupsOfElementsID);
7729 //=======================================================================
7730 //function : FindFaceInSet
7731 //purpose : Return a face having linked nodes n1 and n2 and which is
7732 // - not in avoidSet,
7733 // - in elemSet provided that !elemSet.empty()
7734 // i1 and i2 optionally returns indices of n1 and n2
7735 //=======================================================================
7737 const SMDS_MeshElement*
7738 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7739 const SMDS_MeshNode* n2,
7740 const TIDSortedElemSet& elemSet,
7741 const TIDSortedElemSet& avoidSet,
7747 const SMDS_MeshElement* face = 0;
7749 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7750 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7752 const SMDS_MeshElement* elem = invElemIt->next();
7753 if (avoidSet.count( elem ))
7755 if ( !elemSet.empty() && !elemSet.count( elem ))
7758 i1 = elem->GetNodeIndex( n1 );
7759 // find a n2 linked to n1
7760 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7761 for ( int di = -1; di < 2 && !face; di += 2 )
7763 i2 = (i1+di+nbN) % nbN;
7764 if ( elem->GetNode( i2 ) == n2 )
7767 if ( !face && elem->IsQuadratic())
7769 // analysis for quadratic elements using all nodes
7770 const SMDS_QuadraticFaceOfNodes* F =
7771 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7772 // use special nodes iterator
7773 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7774 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7775 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7777 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7778 if ( n1 == prevN && n2 == n )
7782 else if ( n2 == prevN && n1 == n )
7784 face = elem; swap( i1, i2 );
7790 if ( n1ind ) *n1ind = i1;
7791 if ( n2ind ) *n2ind = i2;
7795 //=======================================================================
7796 //function : findAdjacentFace
7798 //=======================================================================
7800 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7801 const SMDS_MeshNode* n2,
7802 const SMDS_MeshElement* elem)
7804 TIDSortedElemSet elemSet, avoidSet;
7806 avoidSet.insert ( elem );
7807 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7810 //=======================================================================
7811 //function : FindFreeBorder
7813 //=======================================================================
7815 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7817 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7818 const SMDS_MeshNode* theSecondNode,
7819 const SMDS_MeshNode* theLastNode,
7820 list< const SMDS_MeshNode* > & theNodes,
7821 list< const SMDS_MeshElement* >& theFaces)
7823 if ( !theFirstNode || !theSecondNode )
7825 // find border face between theFirstNode and theSecondNode
7826 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7830 theFaces.push_back( curElem );
7831 theNodes.push_back( theFirstNode );
7832 theNodes.push_back( theSecondNode );
7834 //vector<const SMDS_MeshNode*> nodes;
7835 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7836 TIDSortedElemSet foundElems;
7837 bool needTheLast = ( theLastNode != 0 );
7839 while ( nStart != theLastNode ) {
7840 if ( nStart == theFirstNode )
7841 return !needTheLast;
7843 // find all free border faces sharing form nStart
7845 list< const SMDS_MeshElement* > curElemList;
7846 list< const SMDS_MeshNode* > nStartList;
7847 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7848 while ( invElemIt->more() ) {
7849 const SMDS_MeshElement* e = invElemIt->next();
7850 if ( e == curElem || foundElems.insert( e ).second ) {
7852 int iNode = 0, nbNodes = e->NbNodes();
7853 //const SMDS_MeshNode* nodes[nbNodes+1];
7854 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7856 if(e->IsQuadratic()) {
7857 const SMDS_QuadraticFaceOfNodes* F =
7858 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7859 // use special nodes iterator
7860 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7861 while( anIter->more() ) {
7862 nodes[ iNode++ ] = anIter->next();
7866 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7867 while ( nIt->more() )
7868 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7870 nodes[ iNode ] = nodes[ 0 ];
7872 for ( iNode = 0; iNode < nbNodes; iNode++ )
7873 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7874 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7875 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7877 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7878 curElemList.push_back( e );
7882 // analyse the found
7884 int nbNewBorders = curElemList.size();
7885 if ( nbNewBorders == 0 ) {
7886 // no free border furthermore
7887 return !needTheLast;
7889 else if ( nbNewBorders == 1 ) {
7890 // one more element found
7892 nStart = nStartList.front();
7893 curElem = curElemList.front();
7894 theFaces.push_back( curElem );
7895 theNodes.push_back( nStart );
7898 // several continuations found
7899 list< const SMDS_MeshElement* >::iterator curElemIt;
7900 list< const SMDS_MeshNode* >::iterator nStartIt;
7901 // check if one of them reached the last node
7902 if ( needTheLast ) {
7903 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7904 curElemIt!= curElemList.end();
7905 curElemIt++, nStartIt++ )
7906 if ( *nStartIt == theLastNode ) {
7907 theFaces.push_back( *curElemIt );
7908 theNodes.push_back( *nStartIt );
7912 // find the best free border by the continuations
7913 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7914 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7915 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7916 curElemIt!= curElemList.end();
7917 curElemIt++, nStartIt++ )
7919 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7920 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7921 // find one more free border
7922 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7926 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7927 // choice: clear a worse one
7928 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7929 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7930 contNodes[ iWorse ].clear();
7931 contFaces[ iWorse ].clear();
7934 if ( contNodes[0].empty() && contNodes[1].empty() )
7937 // append the best free border
7938 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7939 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7940 theNodes.pop_back(); // remove nIgnore
7941 theNodes.pop_back(); // remove nStart
7942 theFaces.pop_back(); // remove curElem
7943 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7944 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7945 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7946 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7949 } // several continuations found
7950 } // while ( nStart != theLastNode )
7955 //=======================================================================
7956 //function : CheckFreeBorderNodes
7957 //purpose : Return true if the tree nodes are on a free border
7958 //=======================================================================
7960 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7961 const SMDS_MeshNode* theNode2,
7962 const SMDS_MeshNode* theNode3)
7964 list< const SMDS_MeshNode* > nodes;
7965 list< const SMDS_MeshElement* > faces;
7966 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7969 //=======================================================================
7970 //function : SewFreeBorder
7972 //=======================================================================
7974 SMESH_MeshEditor::Sew_Error
7975 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7976 const SMDS_MeshNode* theBordSecondNode,
7977 const SMDS_MeshNode* theBordLastNode,
7978 const SMDS_MeshNode* theSideFirstNode,
7979 const SMDS_MeshNode* theSideSecondNode,
7980 const SMDS_MeshNode* theSideThirdNode,
7981 const bool theSideIsFreeBorder,
7982 const bool toCreatePolygons,
7983 const bool toCreatePolyedrs)
7985 myLastCreatedElems.Clear();
7986 myLastCreatedNodes.Clear();
7988 MESSAGE("::SewFreeBorder()");
7989 Sew_Error aResult = SEW_OK;
7991 // ====================================
7992 // find side nodes and elements
7993 // ====================================
7995 list< const SMDS_MeshNode* > nSide[ 2 ];
7996 list< const SMDS_MeshElement* > eSide[ 2 ];
7997 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7998 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8002 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8003 nSide[0], eSide[0])) {
8004 MESSAGE(" Free Border 1 not found " );
8005 aResult = SEW_BORDER1_NOT_FOUND;
8007 if (theSideIsFreeBorder) {
8010 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8011 nSide[1], eSide[1])) {
8012 MESSAGE(" Free Border 2 not found " );
8013 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8016 if ( aResult != SEW_OK )
8019 if (!theSideIsFreeBorder) {
8023 // -------------------------------------------------------------------------
8025 // 1. If nodes to merge are not coincident, move nodes of the free border
8026 // from the coord sys defined by the direction from the first to last
8027 // nodes of the border to the correspondent sys of the side 2
8028 // 2. On the side 2, find the links most co-directed with the correspondent
8029 // links of the free border
8030 // -------------------------------------------------------------------------
8032 // 1. Since sewing may brake if there are volumes to split on the side 2,
8033 // we wont move nodes but just compute new coordinates for them
8034 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8035 TNodeXYZMap nBordXYZ;
8036 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8037 list< const SMDS_MeshNode* >::iterator nBordIt;
8039 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8040 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8041 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8042 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8043 double tol2 = 1.e-8;
8044 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8045 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8046 // Need node movement.
8048 // find X and Z axes to create trsf
8049 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8051 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8053 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8056 gp_Ax3 toBordAx( Pb1, Zb, X );
8057 gp_Ax3 fromSideAx( Ps1, Zs, X );
8058 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8060 gp_Trsf toBordSys, fromSide2Sys;
8061 toBordSys.SetTransformation( toBordAx );
8062 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8063 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8066 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8067 const SMDS_MeshNode* n = *nBordIt;
8068 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8069 toBordSys.Transforms( xyz );
8070 fromSide2Sys.Transforms( xyz );
8071 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8075 // just insert nodes XYZ in the nBordXYZ map
8076 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8077 const SMDS_MeshNode* n = *nBordIt;
8078 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8082 // 2. On the side 2, find the links most co-directed with the correspondent
8083 // links of the free border
8085 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8086 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8087 sideNodes.push_back( theSideFirstNode );
8089 bool hasVolumes = false;
8090 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8091 set<long> foundSideLinkIDs, checkedLinkIDs;
8092 SMDS_VolumeTool volume;
8093 //const SMDS_MeshNode* faceNodes[ 4 ];
8095 const SMDS_MeshNode* sideNode;
8096 const SMDS_MeshElement* sideElem;
8097 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8098 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8099 nBordIt = bordNodes.begin();
8101 // border node position and border link direction to compare with
8102 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8103 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8104 // choose next side node by link direction or by closeness to
8105 // the current border node:
8106 bool searchByDir = ( *nBordIt != theBordLastNode );
8108 // find the next node on the Side 2
8110 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8112 checkedLinkIDs.clear();
8113 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8115 // loop on inverse elements of current node (prevSideNode) on the Side 2
8116 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8117 while ( invElemIt->more() )
8119 const SMDS_MeshElement* elem = invElemIt->next();
8120 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8121 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8122 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8123 bool isVolume = volume.Set( elem );
8124 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8125 if ( isVolume ) // --volume
8127 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8128 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8129 if(elem->IsQuadratic()) {
8130 const SMDS_QuadraticFaceOfNodes* F =
8131 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8132 // use special nodes iterator
8133 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8134 while( anIter->more() ) {
8135 nodes[ iNode ] = anIter->next();
8136 if ( nodes[ iNode++ ] == prevSideNode )
8137 iPrevNode = iNode - 1;
8141 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8142 while ( nIt->more() ) {
8143 nodes[ iNode ] = cast2Node( nIt->next() );
8144 if ( nodes[ iNode++ ] == prevSideNode )
8145 iPrevNode = iNode - 1;
8148 // there are 2 links to check
8153 // loop on links, to be precise, on the second node of links
8154 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8155 const SMDS_MeshNode* n = nodes[ iNode ];
8157 if ( !volume.IsLinked( n, prevSideNode ))
8161 if ( iNode ) // a node before prevSideNode
8162 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8163 else // a node after prevSideNode
8164 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8166 // check if this link was already used
8167 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8168 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8169 if (!isJustChecked &&
8170 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8172 // test a link geometrically
8173 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8174 bool linkIsBetter = false;
8175 double dot = 0.0, dist = 0.0;
8176 if ( searchByDir ) { // choose most co-directed link
8177 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8178 linkIsBetter = ( dot > maxDot );
8180 else { // choose link with the node closest to bordPos
8181 dist = ( nextXYZ - bordPos ).SquareModulus();
8182 linkIsBetter = ( dist < minDist );
8184 if ( linkIsBetter ) {
8193 } // loop on inverse elements of prevSideNode
8196 MESSAGE(" Cant find path by links of the Side 2 ");
8197 return SEW_BAD_SIDE_NODES;
8199 sideNodes.push_back( sideNode );
8200 sideElems.push_back( sideElem );
8201 foundSideLinkIDs.insert ( linkID );
8202 prevSideNode = sideNode;
8204 if ( *nBordIt == theBordLastNode )
8205 searchByDir = false;
8207 // find the next border link to compare with
8208 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8209 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8210 // move to next border node if sideNode is before forward border node (bordPos)
8211 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8212 prevBordNode = *nBordIt;
8214 bordPos = nBordXYZ[ *nBordIt ];
8215 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8216 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8220 while ( sideNode != theSideSecondNode );
8222 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8223 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8224 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8226 } // end nodes search on the side 2
8228 // ============================
8229 // sew the border to the side 2
8230 // ============================
8232 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8233 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8235 TListOfListOfNodes nodeGroupsToMerge;
8236 if ( nbNodes[0] == nbNodes[1] ||
8237 ( theSideIsFreeBorder && !theSideThirdNode)) {
8239 // all nodes are to be merged
8241 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8242 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8243 nIt[0]++, nIt[1]++ )
8245 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8246 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8247 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8252 // insert new nodes into the border and the side to get equal nb of segments
8254 // get normalized parameters of nodes on the borders
8255 //double param[ 2 ][ maxNbNodes ];
8257 param[0] = new double [ maxNbNodes ];
8258 param[1] = new double [ maxNbNodes ];
8260 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8261 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8262 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8263 const SMDS_MeshNode* nPrev = *nIt;
8264 double bordLength = 0;
8265 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8266 const SMDS_MeshNode* nCur = *nIt;
8267 gp_XYZ segment (nCur->X() - nPrev->X(),
8268 nCur->Y() - nPrev->Y(),
8269 nCur->Z() - nPrev->Z());
8270 double segmentLen = segment.Modulus();
8271 bordLength += segmentLen;
8272 param[ iBord ][ iNode ] = bordLength;
8275 // normalize within [0,1]
8276 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8277 param[ iBord ][ iNode ] /= bordLength;
8281 // loop on border segments
8282 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8283 int i[ 2 ] = { 0, 0 };
8284 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8285 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8287 TElemOfNodeListMap insertMap;
8288 TElemOfNodeListMap::iterator insertMapIt;
8290 // key: elem to insert nodes into
8291 // value: 2 nodes to insert between + nodes to be inserted
8293 bool next[ 2 ] = { false, false };
8295 // find min adjacent segment length after sewing
8296 double nextParam = 10., prevParam = 0;
8297 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8298 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8299 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8300 if ( i[ iBord ] > 0 )
8301 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8303 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8304 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8305 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8307 // choose to insert or to merge nodes
8308 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8309 if ( Abs( du ) <= minSegLen * 0.2 ) {
8312 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8313 const SMDS_MeshNode* n0 = *nIt[0];
8314 const SMDS_MeshNode* n1 = *nIt[1];
8315 nodeGroupsToMerge.back().push_back( n1 );
8316 nodeGroupsToMerge.back().push_back( n0 );
8317 // position of node of the border changes due to merge
8318 param[ 0 ][ i[0] ] += du;
8319 // move n1 for the sake of elem shape evaluation during insertion.
8320 // n1 will be removed by MergeNodes() anyway
8321 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8322 next[0] = next[1] = true;
8327 int intoBord = ( du < 0 ) ? 0 : 1;
8328 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8329 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8330 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8331 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8332 if ( intoBord == 1 ) {
8333 // move node of the border to be on a link of elem of the side
8334 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8335 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8336 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8337 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8338 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8340 insertMapIt = insertMap.find( elem );
8341 bool notFound = ( insertMapIt == insertMap.end() );
8342 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8344 // insert into another link of the same element:
8345 // 1. perform insertion into the other link of the elem
8346 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8347 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8348 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8349 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8350 // 2. perform insertion into the link of adjacent faces
8352 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8354 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8358 if (toCreatePolyedrs) {
8359 // perform insertion into the links of adjacent volumes
8360 UpdateVolumes(n12, n22, nodeList);
8362 // 3. find an element appeared on n1 and n2 after the insertion
8363 insertMap.erase( elem );
8364 elem = findAdjacentFace( n1, n2, 0 );
8366 if ( notFound || otherLink ) {
8367 // add element and nodes of the side into the insertMap
8368 insertMapIt = insertMap.insert
8369 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8370 (*insertMapIt).second.push_back( n1 );
8371 (*insertMapIt).second.push_back( n2 );
8373 // add node to be inserted into elem
8374 (*insertMapIt).second.push_back( nIns );
8375 next[ 1 - intoBord ] = true;
8378 // go to the next segment
8379 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8380 if ( next[ iBord ] ) {
8381 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8383 nPrev[ iBord ] = *nIt[ iBord ];
8384 nIt[ iBord ]++; i[ iBord ]++;
8388 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8390 // perform insertion of nodes into elements
8392 for (insertMapIt = insertMap.begin();
8393 insertMapIt != insertMap.end();
8396 const SMDS_MeshElement* elem = (*insertMapIt).first;
8397 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8398 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8399 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8401 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8403 if ( !theSideIsFreeBorder ) {
8404 // look for and insert nodes into the faces adjacent to elem
8406 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8408 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8413 if (toCreatePolyedrs) {
8414 // perform insertion into the links of adjacent volumes
8415 UpdateVolumes(n1, n2, nodeList);
8421 } // end: insert new nodes
8423 MergeNodes ( nodeGroupsToMerge );
8428 //=======================================================================
8429 //function : InsertNodesIntoLink
8430 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8431 // and theBetweenNode2 and split theElement
8432 //=======================================================================
8434 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8435 const SMDS_MeshNode* theBetweenNode1,
8436 const SMDS_MeshNode* theBetweenNode2,
8437 list<const SMDS_MeshNode*>& theNodesToInsert,
8438 const bool toCreatePoly)
8440 if ( theFace->GetType() != SMDSAbs_Face ) return;
8442 // find indices of 2 link nodes and of the rest nodes
8443 int iNode = 0, il1, il2, i3, i4;
8444 il1 = il2 = i3 = i4 = -1;
8445 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8446 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8448 if(theFace->IsQuadratic()) {
8449 const SMDS_QuadraticFaceOfNodes* F =
8450 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8451 // use special nodes iterator
8452 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8453 while( anIter->more() ) {
8454 const SMDS_MeshNode* n = anIter->next();
8455 if ( n == theBetweenNode1 )
8457 else if ( n == theBetweenNode2 )
8463 nodes[ iNode++ ] = n;
8467 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8468 while ( nodeIt->more() ) {
8469 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8470 if ( n == theBetweenNode1 )
8472 else if ( n == theBetweenNode2 )
8478 nodes[ iNode++ ] = n;
8481 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8484 // arrange link nodes to go one after another regarding the face orientation
8485 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8486 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8491 aNodesToInsert.reverse();
8493 // check that not link nodes of a quadrangles are in good order
8494 int nbFaceNodes = theFace->NbNodes();
8495 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8501 if (toCreatePoly || theFace->IsPoly()) {
8504 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8506 // add nodes of face up to first node of link
8509 if(theFace->IsQuadratic()) {
8510 const SMDS_QuadraticFaceOfNodes* F =
8511 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8512 // use special nodes iterator
8513 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8514 while( anIter->more() && !isFLN ) {
8515 const SMDS_MeshNode* n = anIter->next();
8516 poly_nodes[iNode++] = n;
8517 if (n == nodes[il1]) {
8521 // add nodes to insert
8522 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8523 for (; nIt != aNodesToInsert.end(); nIt++) {
8524 poly_nodes[iNode++] = *nIt;
8526 // add nodes of face starting from last node of link
8527 while ( anIter->more() ) {
8528 poly_nodes[iNode++] = anIter->next();
8532 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8533 while ( nodeIt->more() && !isFLN ) {
8534 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8535 poly_nodes[iNode++] = n;
8536 if (n == nodes[il1]) {
8540 // add nodes to insert
8541 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8542 for (; nIt != aNodesToInsert.end(); nIt++) {
8543 poly_nodes[iNode++] = *nIt;
8545 // add nodes of face starting from last node of link
8546 while ( nodeIt->more() ) {
8547 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8548 poly_nodes[iNode++] = n;
8552 // edit or replace the face
8553 SMESHDS_Mesh *aMesh = GetMeshDS();
8555 if (theFace->IsPoly()) {
8556 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8559 int aShapeId = FindShape( theFace );
8561 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8562 myLastCreatedElems.Append(newElem);
8563 if ( aShapeId && newElem )
8564 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8566 aMesh->RemoveElement(theFace);
8571 if( !theFace->IsQuadratic() ) {
8573 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8574 int nbLinkNodes = 2 + aNodesToInsert.size();
8575 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8576 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8577 linkNodes[ 0 ] = nodes[ il1 ];
8578 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8579 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8580 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8581 linkNodes[ iNode++ ] = *nIt;
8583 // decide how to split a quadrangle: compare possible variants
8584 // and choose which of splits to be a quadrangle
8585 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8586 if ( nbFaceNodes == 3 ) {
8587 iBestQuad = nbSplits;
8590 else if ( nbFaceNodes == 4 ) {
8591 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8592 double aBestRate = DBL_MAX;
8593 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8595 double aBadRate = 0;
8596 // evaluate elements quality
8597 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8598 if ( iSplit == iQuad ) {
8599 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8603 aBadRate += getBadRate( &quad, aCrit );
8606 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8608 nodes[ iSplit < iQuad ? i4 : i3 ]);
8609 aBadRate += getBadRate( &tria, aCrit );
8613 if ( aBadRate < aBestRate ) {
8615 aBestRate = aBadRate;
8620 // create new elements
8621 SMESHDS_Mesh *aMesh = GetMeshDS();
8622 int aShapeId = FindShape( theFace );
8625 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8626 SMDS_MeshElement* newElem = 0;
8627 if ( iSplit == iBestQuad )
8628 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8633 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8635 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8636 myLastCreatedElems.Append(newElem);
8637 if ( aShapeId && newElem )
8638 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8641 // change nodes of theFace
8642 const SMDS_MeshNode* newNodes[ 4 ];
8643 newNodes[ 0 ] = linkNodes[ i1 ];
8644 newNodes[ 1 ] = linkNodes[ i2 ];
8645 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8646 newNodes[ 3 ] = nodes[ i4 ];
8647 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8648 } // end if(!theFace->IsQuadratic())
8649 else { // theFace is quadratic
8650 // we have to split theFace on simple triangles and one simple quadrangle
8652 int nbshift = tmp*2;
8653 // shift nodes in nodes[] by nbshift
8655 for(i=0; i<nbshift; i++) {
8656 const SMDS_MeshNode* n = nodes[0];
8657 for(j=0; j<nbFaceNodes-1; j++) {
8658 nodes[j] = nodes[j+1];
8660 nodes[nbFaceNodes-1] = n;
8662 il1 = il1 - nbshift;
8663 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8664 // n0 n1 n2 n0 n1 n2
8665 // +-----+-----+ +-----+-----+
8674 // create new elements
8675 SMESHDS_Mesh *aMesh = GetMeshDS();
8676 int aShapeId = FindShape( theFace );
8679 if(nbFaceNodes==6) { // quadratic triangle
8680 SMDS_MeshElement* newElem =
8681 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8682 myLastCreatedElems.Append(newElem);
8683 if ( aShapeId && newElem )
8684 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8685 if(theFace->IsMediumNode(nodes[il1])) {
8686 // create quadrangle
8687 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8688 myLastCreatedElems.Append(newElem);
8689 if ( aShapeId && newElem )
8690 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8696 // create quadrangle
8697 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8698 myLastCreatedElems.Append(newElem);
8699 if ( aShapeId && newElem )
8700 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8706 else { // nbFaceNodes==8 - quadratic quadrangle
8707 SMDS_MeshElement* newElem =
8708 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8709 myLastCreatedElems.Append(newElem);
8710 if ( aShapeId && newElem )
8711 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8712 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8713 myLastCreatedElems.Append(newElem);
8714 if ( aShapeId && newElem )
8715 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8716 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8717 myLastCreatedElems.Append(newElem);
8718 if ( aShapeId && newElem )
8719 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8720 if(theFace->IsMediumNode(nodes[il1])) {
8721 // create quadrangle
8722 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8723 myLastCreatedElems.Append(newElem);
8724 if ( aShapeId && newElem )
8725 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8731 // create quadrangle
8732 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8733 myLastCreatedElems.Append(newElem);
8734 if ( aShapeId && newElem )
8735 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8741 // create needed triangles using n1,n2,n3 and inserted nodes
8742 int nbn = 2 + aNodesToInsert.size();
8743 //const SMDS_MeshNode* aNodes[nbn];
8744 vector<const SMDS_MeshNode*> aNodes(nbn);
8745 aNodes[0] = nodes[n1];
8746 aNodes[nbn-1] = nodes[n2];
8747 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8748 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8749 aNodes[iNode++] = *nIt;
8751 for(i=1; i<nbn; i++) {
8752 SMDS_MeshElement* newElem =
8753 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8754 myLastCreatedElems.Append(newElem);
8755 if ( aShapeId && newElem )
8756 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8758 // remove old quadratic face
8759 aMesh->RemoveElement(theFace);
8763 //=======================================================================
8764 //function : UpdateVolumes
8766 //=======================================================================
8767 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8768 const SMDS_MeshNode* theBetweenNode2,
8769 list<const SMDS_MeshNode*>& theNodesToInsert)
8771 myLastCreatedElems.Clear();
8772 myLastCreatedNodes.Clear();
8774 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8775 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8776 const SMDS_MeshElement* elem = invElemIt->next();
8778 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8779 SMDS_VolumeTool aVolume (elem);
8780 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8783 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8784 int iface, nbFaces = aVolume.NbFaces();
8785 vector<const SMDS_MeshNode *> poly_nodes;
8786 vector<int> quantities (nbFaces);
8788 for (iface = 0; iface < nbFaces; iface++) {
8789 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8790 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8791 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8793 for (int inode = 0; inode < nbFaceNodes; inode++) {
8794 poly_nodes.push_back(faceNodes[inode]);
8796 if (nbInserted == 0) {
8797 if (faceNodes[inode] == theBetweenNode1) {
8798 if (faceNodes[inode + 1] == theBetweenNode2) {
8799 nbInserted = theNodesToInsert.size();
8801 // add nodes to insert
8802 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8803 for (; nIt != theNodesToInsert.end(); nIt++) {
8804 poly_nodes.push_back(*nIt);
8808 else if (faceNodes[inode] == theBetweenNode2) {
8809 if (faceNodes[inode + 1] == theBetweenNode1) {
8810 nbInserted = theNodesToInsert.size();
8812 // add nodes to insert in reversed order
8813 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8815 for (; nIt != theNodesToInsert.begin(); nIt--) {
8816 poly_nodes.push_back(*nIt);
8818 poly_nodes.push_back(*nIt);
8825 quantities[iface] = nbFaceNodes + nbInserted;
8828 // Replace or update the volume
8829 SMESHDS_Mesh *aMesh = GetMeshDS();
8831 if (elem->IsPoly()) {
8832 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8836 int aShapeId = FindShape( elem );
8838 SMDS_MeshElement* newElem =
8839 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8840 myLastCreatedElems.Append(newElem);
8841 if (aShapeId && newElem)
8842 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8844 aMesh->RemoveElement(elem);
8849 //=======================================================================
8851 * \brief Convert elements contained in a submesh to quadratic
8852 * \retval int - nb of checked elements
8854 //=======================================================================
8856 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8857 SMESH_MesherHelper& theHelper,
8858 const bool theForce3d)
8861 if( !theSm ) return nbElem;
8863 const bool notFromGroups = false;
8864 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8865 while(ElemItr->more())
8868 const SMDS_MeshElement* elem = ElemItr->next();
8869 if( !elem || elem->IsQuadratic() ) continue;
8871 int id = elem->GetID();
8872 int nbNodes = elem->NbNodes();
8873 vector<const SMDS_MeshNode *> aNds (nbNodes);
8875 for(int i = 0; i < nbNodes; i++)
8877 aNds[i] = elem->GetNode(i);
8879 SMDSAbs_ElementType aType = elem->GetType();
8881 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8883 const SMDS_MeshElement* NewElem = 0;
8889 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8897 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8900 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8907 case SMDSAbs_Volume :
8912 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8915 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8918 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8921 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8922 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8932 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8934 theSm->AddElement( NewElem );
8939 //=======================================================================
8940 //function : ConvertToQuadratic
8942 //=======================================================================
8943 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8945 SMESHDS_Mesh* meshDS = GetMeshDS();
8947 SMESH_MesherHelper aHelper(*myMesh);
8948 aHelper.SetIsQuadratic( true );
8949 const bool notFromGroups = false;
8951 int nbCheckedElems = 0;
8952 if ( myMesh->HasShapeToMesh() )
8954 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8956 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8957 while ( smIt->more() ) {
8958 SMESH_subMesh* sm = smIt->next();
8959 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8960 aHelper.SetSubShape( sm->GetSubShape() );
8961 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8966 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8967 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8969 SMESHDS_SubMesh *smDS = 0;
8970 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8971 while(aEdgeItr->more())
8973 const SMDS_MeshEdge* edge = aEdgeItr->next();
8974 if(edge && !edge->IsQuadratic())
8976 int id = edge->GetID();
8977 const SMDS_MeshNode* n1 = edge->GetNode(0);
8978 const SMDS_MeshNode* n2 = edge->GetNode(1);
8980 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8982 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8983 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8986 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8987 while(aFaceItr->more())
8989 const SMDS_MeshFace* face = aFaceItr->next();
8990 if(!face || face->IsQuadratic() ) continue;
8992 int id = face->GetID();
8993 int nbNodes = face->NbNodes();
8994 vector<const SMDS_MeshNode *> aNds (nbNodes);
8996 for(int i = 0; i < nbNodes; i++)
8998 aNds[i] = face->GetNode(i);
9001 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9003 SMDS_MeshFace * NewFace = 0;
9007 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9010 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9015 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9017 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9018 while(aVolumeItr->more())
9020 const SMDS_MeshVolume* volume = aVolumeItr->next();
9021 if(!volume || volume->IsQuadratic() ) continue;
9023 int id = volume->GetID();
9024 int nbNodes = volume->NbNodes();
9025 vector<const SMDS_MeshNode *> aNds (nbNodes);
9027 for(int i = 0; i < nbNodes; i++)
9029 aNds[i] = volume->GetNode(i);
9032 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9034 SMDS_MeshVolume * NewVolume = 0;
9038 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9039 aNds[3], id, theForce3d );
9042 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9043 aNds[3], aNds[4], id, theForce3d);
9046 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9047 aNds[3], aNds[4], aNds[5], id, theForce3d);
9050 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9051 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9056 ReplaceElemInGroups(volume, NewVolume, meshDS);
9059 if ( !theForce3d ) {
9060 aHelper.SetSubShape(0); // apply to the whole mesh
9061 aHelper.FixQuadraticElements();
9065 //=======================================================================
9067 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9068 * \retval int - nb of checked elements
9070 //=======================================================================
9072 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9073 SMDS_ElemIteratorPtr theItr,
9074 const int theShapeID)
9077 SMESHDS_Mesh* meshDS = GetMeshDS();
9078 const bool notFromGroups = false;
9080 while( theItr->more() )
9082 const SMDS_MeshElement* elem = theItr->next();
9084 if( elem && elem->IsQuadratic())
9086 int id = elem->GetID();
9087 int nbNodes = elem->NbNodes();
9088 vector<const SMDS_MeshNode *> aNds, mediumNodes;
9089 aNds.reserve( nbNodes );
9090 mediumNodes.reserve( nbNodes );
9092 for(int i = 0; i < nbNodes; i++)
9094 const SMDS_MeshNode* n = elem->GetNode(i);
9096 if( elem->IsMediumNode( n ) )
9097 mediumNodes.push_back( n );
9099 aNds.push_back( n );
9101 if( aNds.empty() ) continue;
9102 SMDSAbs_ElementType aType = elem->GetType();
9104 //remove old quadratic element
9105 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9107 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9108 ReplaceElemInGroups(elem, NewElem, meshDS);
9109 if( theSm && NewElem )
9110 theSm->AddElement( NewElem );
9112 // remove medium nodes
9113 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9114 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9115 const SMDS_MeshNode* n = *nIt;
9116 if ( n->NbInverseElements() == 0 ) {
9117 if ( n->GetPosition()->GetShapeId() != theShapeID )
9118 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9119 ( n->GetPosition()->GetShapeId() ));
9121 meshDS->RemoveFreeNode( n, theSm );
9129 //=======================================================================
9130 //function : ConvertFromQuadratic
9132 //=======================================================================
9133 bool SMESH_MeshEditor::ConvertFromQuadratic()
9135 int nbCheckedElems = 0;
9136 if ( myMesh->HasShapeToMesh() )
9138 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9140 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9141 while ( smIt->more() ) {
9142 SMESH_subMesh* sm = smIt->next();
9143 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9144 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9150 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9151 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9153 SMESHDS_SubMesh *aSM = 0;
9154 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9160 //=======================================================================
9161 //function : SewSideElements
9163 //=======================================================================
9165 SMESH_MeshEditor::Sew_Error
9166 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9167 TIDSortedElemSet& theSide2,
9168 const SMDS_MeshNode* theFirstNode1,
9169 const SMDS_MeshNode* theFirstNode2,
9170 const SMDS_MeshNode* theSecondNode1,
9171 const SMDS_MeshNode* theSecondNode2)
9173 myLastCreatedElems.Clear();
9174 myLastCreatedNodes.Clear();
9176 MESSAGE ("::::SewSideElements()");
9177 if ( theSide1.size() != theSide2.size() )
9178 return SEW_DIFF_NB_OF_ELEMENTS;
9180 Sew_Error aResult = SEW_OK;
9182 // 1. Build set of faces representing each side
9183 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9184 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9186 // =======================================================================
9187 // 1. Build set of faces representing each side:
9188 // =======================================================================
9189 // a. build set of nodes belonging to faces
9190 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9191 // c. create temporary faces representing side of volumes if correspondent
9192 // face does not exist
9194 SMESHDS_Mesh* aMesh = GetMeshDS();
9195 SMDS_Mesh aTmpFacesMesh;
9196 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9197 set<const SMDS_MeshElement*> volSet1, volSet2;
9198 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9199 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9200 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9201 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9202 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9203 int iSide, iFace, iNode;
9205 for ( iSide = 0; iSide < 2; iSide++ ) {
9206 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9207 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9208 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9209 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9210 set<const SMDS_MeshElement*>::iterator vIt;
9211 TIDSortedElemSet::iterator eIt;
9212 set<const SMDS_MeshNode*>::iterator nIt;
9214 // check that given nodes belong to given elements
9215 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9216 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9217 int firstIndex = -1, secondIndex = -1;
9218 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9219 const SMDS_MeshElement* elem = *eIt;
9220 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9221 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9222 if ( firstIndex > -1 && secondIndex > -1 ) break;
9224 if ( firstIndex < 0 || secondIndex < 0 ) {
9225 // we can simply return until temporary faces created
9226 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9229 // -----------------------------------------------------------
9230 // 1a. Collect nodes of existing faces
9231 // and build set of face nodes in order to detect missing
9232 // faces corresponing to sides of volumes
9233 // -----------------------------------------------------------
9235 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9237 // loop on the given element of a side
9238 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9239 //const SMDS_MeshElement* elem = *eIt;
9240 const SMDS_MeshElement* elem = *eIt;
9241 if ( elem->GetType() == SMDSAbs_Face ) {
9242 faceSet->insert( elem );
9243 set <const SMDS_MeshNode*> faceNodeSet;
9244 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9245 while ( nodeIt->more() ) {
9246 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9247 nodeSet->insert( n );
9248 faceNodeSet.insert( n );
9250 setOfFaceNodeSet.insert( faceNodeSet );
9252 else if ( elem->GetType() == SMDSAbs_Volume )
9253 volSet->insert( elem );
9255 // ------------------------------------------------------------------------------
9256 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9257 // ------------------------------------------------------------------------------
9259 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9260 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9261 while ( fIt->more() ) { // loop on faces sharing a node
9262 const SMDS_MeshElement* f = fIt->next();
9263 if ( faceSet->find( f ) == faceSet->end() ) {
9264 // check if all nodes are in nodeSet and
9265 // complete setOfFaceNodeSet if they are
9266 set <const SMDS_MeshNode*> faceNodeSet;
9267 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9268 bool allInSet = true;
9269 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9270 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9271 if ( nodeSet->find( n ) == nodeSet->end() )
9274 faceNodeSet.insert( n );
9277 faceSet->insert( f );
9278 setOfFaceNodeSet.insert( faceNodeSet );
9284 // -------------------------------------------------------------------------
9285 // 1c. Create temporary faces representing sides of volumes if correspondent
9286 // face does not exist
9287 // -------------------------------------------------------------------------
9289 if ( !volSet->empty() ) {
9290 //int nodeSetSize = nodeSet->size();
9292 // loop on given volumes
9293 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9294 SMDS_VolumeTool vol (*vIt);
9295 // loop on volume faces: find free faces
9296 // --------------------------------------
9297 list<const SMDS_MeshElement* > freeFaceList;
9298 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9299 if ( !vol.IsFreeFace( iFace ))
9301 // check if there is already a face with same nodes in a face set
9302 const SMDS_MeshElement* aFreeFace = 0;
9303 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9304 int nbNodes = vol.NbFaceNodes( iFace );
9305 set <const SMDS_MeshNode*> faceNodeSet;
9306 vol.GetFaceNodes( iFace, faceNodeSet );
9307 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9309 // no such a face is given but it still can exist, check it
9310 if ( nbNodes == 3 ) {
9311 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9313 else if ( nbNodes == 4 ) {
9314 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9317 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9318 aFreeFace = aMesh->FindFace(poly_nodes);
9322 // create a temporary face
9323 if ( nbNodes == 3 ) {
9324 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9326 else if ( nbNodes == 4 ) {
9327 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9330 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9331 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9335 freeFaceList.push_back( aFreeFace );
9337 } // loop on faces of a volume
9339 // choose one of several free faces
9340 // --------------------------------------
9341 if ( freeFaceList.size() > 1 ) {
9342 // choose a face having max nb of nodes shared by other elems of a side
9343 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9344 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9345 while ( fIt != freeFaceList.end() ) { // loop on free faces
9346 int nbSharedNodes = 0;
9347 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9348 while ( nodeIt->more() ) { // loop on free face nodes
9349 const SMDS_MeshNode* n =
9350 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9351 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9352 while ( invElemIt->more() ) {
9353 const SMDS_MeshElement* e = invElemIt->next();
9354 if ( faceSet->find( e ) != faceSet->end() )
9356 if ( elemSet->find( e ) != elemSet->end() )
9360 if ( nbSharedNodes >= maxNbNodes ) {
9361 maxNbNodes = nbSharedNodes;
9365 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9367 if ( freeFaceList.size() > 1 )
9369 // could not choose one face, use another way
9370 // choose a face most close to the bary center of the opposite side
9371 gp_XYZ aBC( 0., 0., 0. );
9372 set <const SMDS_MeshNode*> addedNodes;
9373 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9374 eIt = elemSet2->begin();
9375 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9376 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9377 while ( nodeIt->more() ) { // loop on free face nodes
9378 const SMDS_MeshNode* n =
9379 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9380 if ( addedNodes.insert( n ).second )
9381 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9384 aBC /= addedNodes.size();
9385 double minDist = DBL_MAX;
9386 fIt = freeFaceList.begin();
9387 while ( fIt != freeFaceList.end() ) { // loop on free faces
9389 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9390 while ( nodeIt->more() ) { // loop on free face nodes
9391 const SMDS_MeshNode* n =
9392 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9393 gp_XYZ p( n->X(),n->Y(),n->Z() );
9394 dist += ( aBC - p ).SquareModulus();
9396 if ( dist < minDist ) {
9398 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9401 fIt = freeFaceList.erase( fIt++ );
9404 } // choose one of several free faces of a volume
9406 if ( freeFaceList.size() == 1 ) {
9407 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9408 faceSet->insert( aFreeFace );
9409 // complete a node set with nodes of a found free face
9410 // for ( iNode = 0; iNode < ; iNode++ )
9411 // nodeSet->insert( fNodes[ iNode ] );
9414 } // loop on volumes of a side
9416 // // complete a set of faces if new nodes in a nodeSet appeared
9417 // // ----------------------------------------------------------
9418 // if ( nodeSetSize != nodeSet->size() ) {
9419 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9420 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9421 // while ( fIt->more() ) { // loop on faces sharing a node
9422 // const SMDS_MeshElement* f = fIt->next();
9423 // if ( faceSet->find( f ) == faceSet->end() ) {
9424 // // check if all nodes are in nodeSet and
9425 // // complete setOfFaceNodeSet if they are
9426 // set <const SMDS_MeshNode*> faceNodeSet;
9427 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9428 // bool allInSet = true;
9429 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9430 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9431 // if ( nodeSet->find( n ) == nodeSet->end() )
9432 // allInSet = false;
9434 // faceNodeSet.insert( n );
9436 // if ( allInSet ) {
9437 // faceSet->insert( f );
9438 // setOfFaceNodeSet.insert( faceNodeSet );
9444 } // Create temporary faces, if there are volumes given
9447 if ( faceSet1.size() != faceSet2.size() ) {
9448 // delete temporary faces: they are in reverseElements of actual nodes
9449 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9450 while ( tmpFaceIt->more() )
9451 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9452 MESSAGE("Diff nb of faces");
9453 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9456 // ============================================================
9457 // 2. Find nodes to merge:
9458 // bind a node to remove to a node to put instead
9459 // ============================================================
9461 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9462 if ( theFirstNode1 != theFirstNode2 )
9463 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9464 if ( theSecondNode1 != theSecondNode2 )
9465 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9467 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9468 set< long > linkIdSet; // links to process
9469 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9471 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9472 list< NLink > linkList[2];
9473 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9474 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9475 // loop on links in linkList; find faces by links and append links
9476 // of the found faces to linkList
9477 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9478 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9479 NLink link[] = { *linkIt[0], *linkIt[1] };
9480 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9481 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9484 // by links, find faces in the face sets,
9485 // and find indices of link nodes in the found faces;
9486 // in a face set, there is only one or no face sharing a link
9487 // ---------------------------------------------------------------
9489 const SMDS_MeshElement* face[] = { 0, 0 };
9490 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9491 vector<const SMDS_MeshNode*> fnodes1(9);
9492 vector<const SMDS_MeshNode*> fnodes2(9);
9493 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9494 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9495 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9496 int iLinkNode[2][2];
9497 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9498 const SMDS_MeshNode* n1 = link[iSide].first;
9499 const SMDS_MeshNode* n2 = link[iSide].second;
9500 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9501 set< const SMDS_MeshElement* > fMap;
9502 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9503 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9504 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9505 while ( fIt->more() ) { // loop on faces sharing a node
9506 const SMDS_MeshElement* f = fIt->next();
9507 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9508 ! fMap.insert( f ).second ) // f encounters twice
9510 if ( face[ iSide ] ) {
9511 MESSAGE( "2 faces per link " );
9512 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9516 faceSet->erase( f );
9517 // get face nodes and find ones of a link
9522 fnodes1.resize(f->NbNodes()+1);
9523 notLinkNodes1.resize(f->NbNodes()-2);
9526 fnodes2.resize(f->NbNodes()+1);
9527 notLinkNodes2.resize(f->NbNodes()-2);
9530 if(!f->IsQuadratic()) {
9531 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9532 while ( nIt->more() ) {
9533 const SMDS_MeshNode* n =
9534 static_cast<const SMDS_MeshNode*>( nIt->next() );
9536 iLinkNode[ iSide ][ 0 ] = iNode;
9538 else if ( n == n2 ) {
9539 iLinkNode[ iSide ][ 1 ] = iNode;
9541 //else if ( notLinkNodes[ iSide ][ 0 ] )
9542 // notLinkNodes[ iSide ][ 1 ] = n;
9544 // notLinkNodes[ iSide ][ 0 ] = n;
9548 notLinkNodes1[nbl] = n;
9549 //notLinkNodes1.push_back(n);
9551 notLinkNodes2[nbl] = n;
9552 //notLinkNodes2.push_back(n);
9554 //faceNodes[ iSide ][ iNode++ ] = n;
9556 fnodes1[iNode++] = n;
9559 fnodes2[iNode++] = n;
9563 else { // f->IsQuadratic()
9564 const SMDS_QuadraticFaceOfNodes* F =
9565 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9566 // use special nodes iterator
9567 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9568 while ( anIter->more() ) {
9569 const SMDS_MeshNode* n =
9570 static_cast<const SMDS_MeshNode*>( anIter->next() );
9572 iLinkNode[ iSide ][ 0 ] = iNode;
9574 else if ( n == n2 ) {
9575 iLinkNode[ iSide ][ 1 ] = iNode;
9580 notLinkNodes1[nbl] = n;
9583 notLinkNodes2[nbl] = n;
9587 fnodes1[iNode++] = n;
9590 fnodes2[iNode++] = n;
9594 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9596 fnodes1[iNode] = fnodes1[0];
9599 fnodes2[iNode] = fnodes1[0];
9606 // check similarity of elements of the sides
9607 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9608 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9609 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9610 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9613 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9615 break; // do not return because it s necessary to remove tmp faces
9618 // set nodes to merge
9619 // -------------------
9621 if ( face[0] && face[1] ) {
9622 int nbNodes = face[0]->NbNodes();
9623 if ( nbNodes != face[1]->NbNodes() ) {
9624 MESSAGE("Diff nb of face nodes");
9625 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9626 break; // do not return because it s necessary to remove tmp faces
9628 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9629 if ( nbNodes == 3 ) {
9630 //nReplaceMap.insert( TNodeNodeMap::value_type
9631 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9632 nReplaceMap.insert( TNodeNodeMap::value_type
9633 ( notLinkNodes1[0], notLinkNodes2[0] ));
9636 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9637 // analyse link orientation in faces
9638 int i1 = iLinkNode[ iSide ][ 0 ];
9639 int i2 = iLinkNode[ iSide ][ 1 ];
9640 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9641 // if notLinkNodes are the first and the last ones, then
9642 // their order does not correspond to the link orientation
9643 if (( i1 == 1 && i2 == 2 ) ||
9644 ( i1 == 2 && i2 == 1 ))
9645 reverse[ iSide ] = !reverse[ iSide ];
9647 if ( reverse[0] == reverse[1] ) {
9648 //nReplaceMap.insert( TNodeNodeMap::value_type
9649 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9650 //nReplaceMap.insert( TNodeNodeMap::value_type
9651 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9652 for(int nn=0; nn<nbNodes-2; nn++) {
9653 nReplaceMap.insert( TNodeNodeMap::value_type
9654 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9658 //nReplaceMap.insert( TNodeNodeMap::value_type
9659 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9660 //nReplaceMap.insert( TNodeNodeMap::value_type
9661 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9662 for(int nn=0; nn<nbNodes-2; nn++) {
9663 nReplaceMap.insert( TNodeNodeMap::value_type
9664 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9669 // add other links of the faces to linkList
9670 // -----------------------------------------
9672 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9673 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9674 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9675 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9676 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9677 if ( !iter_isnew.second ) { // already in a set: no need to process
9678 linkIdSet.erase( iter_isnew.first );
9680 else // new in set == encountered for the first time: add
9682 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9683 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9684 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9685 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9686 linkList[0].push_back ( NLink( n1, n2 ));
9687 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9691 } // loop on link lists
9693 if ( aResult == SEW_OK &&
9694 ( linkIt[0] != linkList[0].end() ||
9695 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9696 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9697 " " << (faceSetPtr[1]->empty()));
9698 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9701 // ====================================================================
9702 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9703 // ====================================================================
9705 // delete temporary faces: they are in reverseElements of actual nodes
9706 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9707 while ( tmpFaceIt->more() )
9708 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9710 if ( aResult != SEW_OK)
9713 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9714 // loop on nodes replacement map
9715 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9716 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9717 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9718 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9719 nodeIDsToRemove.push_back( nToRemove->GetID() );
9720 // loop on elements sharing nToRemove
9721 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9722 while ( invElemIt->more() ) {
9723 const SMDS_MeshElement* e = invElemIt->next();
9724 // get a new suite of nodes: make replacement
9725 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9726 vector< const SMDS_MeshNode*> nodes( nbNodes );
9727 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9728 while ( nIt->more() ) {
9729 const SMDS_MeshNode* n =
9730 static_cast<const SMDS_MeshNode*>( nIt->next() );
9731 nnIt = nReplaceMap.find( n );
9732 if ( nnIt != nReplaceMap.end() ) {
9738 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9739 // elemIDsToRemove.push_back( e->GetID() );
9742 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9746 Remove( nodeIDsToRemove, true );
9751 //================================================================================
9753 * \brief Find corresponding nodes in two sets of faces
9754 * \param theSide1 - first face set
9755 * \param theSide2 - second first face
9756 * \param theFirstNode1 - a boundary node of set 1
9757 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9758 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9759 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9760 * \param nReplaceMap - output map of corresponding nodes
9761 * \retval bool - is a success or not
9763 //================================================================================
9766 //#define DEBUG_MATCHING_NODES
9769 SMESH_MeshEditor::Sew_Error
9770 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9771 set<const SMDS_MeshElement*>& theSide2,
9772 const SMDS_MeshNode* theFirstNode1,
9773 const SMDS_MeshNode* theFirstNode2,
9774 const SMDS_MeshNode* theSecondNode1,
9775 const SMDS_MeshNode* theSecondNode2,
9776 TNodeNodeMap & nReplaceMap)
9778 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9780 nReplaceMap.clear();
9781 if ( theFirstNode1 != theFirstNode2 )
9782 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9783 if ( theSecondNode1 != theSecondNode2 )
9784 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9786 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9787 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9789 list< NLink > linkList[2];
9790 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9791 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9793 // loop on links in linkList; find faces by links and append links
9794 // of the found faces to linkList
9795 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9796 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9797 NLink link[] = { *linkIt[0], *linkIt[1] };
9798 if ( linkSet.find( link[0] ) == linkSet.end() )
9801 // by links, find faces in the face sets,
9802 // and find indices of link nodes in the found faces;
9803 // in a face set, there is only one or no face sharing a link
9804 // ---------------------------------------------------------------
9806 const SMDS_MeshElement* face[] = { 0, 0 };
9807 list<const SMDS_MeshNode*> notLinkNodes[2];
9808 //bool reverse[] = { false, false }; // order of notLinkNodes
9810 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9812 const SMDS_MeshNode* n1 = link[iSide].first;
9813 const SMDS_MeshNode* n2 = link[iSide].second;
9814 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9815 set< const SMDS_MeshElement* > facesOfNode1;
9816 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9818 // during a loop of the first node, we find all faces around n1,
9819 // during a loop of the second node, we find one face sharing both n1 and n2
9820 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9821 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9822 while ( fIt->more() ) { // loop on faces sharing a node
9823 const SMDS_MeshElement* f = fIt->next();
9824 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9825 ! facesOfNode1.insert( f ).second ) // f encounters twice
9827 if ( face[ iSide ] ) {
9828 MESSAGE( "2 faces per link " );
9829 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9832 faceSet->erase( f );
9834 // get not link nodes
9835 int nbN = f->NbNodes();
9836 if ( f->IsQuadratic() )
9838 nbNodes[ iSide ] = nbN;
9839 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9840 int i1 = f->GetNodeIndex( n1 );
9841 int i2 = f->GetNodeIndex( n2 );
9842 int iEnd = nbN, iBeg = -1, iDelta = 1;
9843 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9845 std::swap( iEnd, iBeg ); iDelta = -1;
9850 if ( i == iEnd ) i = iBeg + iDelta;
9851 if ( i == i1 ) break;
9852 nodes.push_back ( f->GetNode( i ) );
9858 // check similarity of elements of the sides
9859 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9860 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9861 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9862 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9865 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9869 // set nodes to merge
9870 // -------------------
9872 if ( face[0] && face[1] ) {
9873 if ( nbNodes[0] != nbNodes[1] ) {
9874 MESSAGE("Diff nb of face nodes");
9875 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9877 #ifdef DEBUG_MATCHING_NODES
9878 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9879 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9880 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9882 int nbN = nbNodes[0];
9884 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9885 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9886 for ( int i = 0 ; i < nbN - 2; ++i ) {
9887 #ifdef DEBUG_MATCHING_NODES
9888 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9890 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9894 // add other links of the face 1 to linkList
9895 // -----------------------------------------
9897 const SMDS_MeshElement* f0 = face[0];
9898 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9899 for ( int i = 0; i < nbN; i++ )
9901 const SMDS_MeshNode* n2 = f0->GetNode( i );
9902 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9903 linkSet.insert( SMESH_TLink( n1, n2 ));
9904 if ( !iter_isnew.second ) { // already in a set: no need to process
9905 linkSet.erase( iter_isnew.first );
9907 else // new in set == encountered for the first time: add
9909 #ifdef DEBUG_MATCHING_NODES
9910 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9911 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9913 linkList[0].push_back ( NLink( n1, n2 ));
9914 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9919 } // loop on link lists
9924 //================================================================================
9926 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9927 \param theElems - the list of elements (edges or faces) to be replicated
9928 The nodes for duplication could be found from these elements
9929 \param theNodesNot - list of nodes to NOT replicate
9930 \param theAffectedElems - the list of elements (cells and edges) to which the
9931 replicated nodes should be associated to.
9932 \return TRUE if operation has been completed successfully, FALSE otherwise
9934 //================================================================================
9936 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9937 const TIDSortedElemSet& theNodesNot,
9938 const TIDSortedElemSet& theAffectedElems )
9940 myLastCreatedElems.Clear();
9941 myLastCreatedNodes.Clear();
9943 if ( theElems.size() == 0 )
9946 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9951 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9952 // duplicate elements and nodes
9953 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9954 // replce nodes by duplications
9955 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9959 //================================================================================
9961 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9962 \param theMeshDS - mesh instance
9963 \param theElems - the elements replicated or modified (nodes should be changed)
9964 \param theNodesNot - nodes to NOT replicate
9965 \param theNodeNodeMap - relation of old node to new created node
9966 \param theIsDoubleElem - flag os to replicate element or modify
9967 \return TRUE if operation has been completed successfully, FALSE otherwise
9969 //================================================================================
9971 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9972 const TIDSortedElemSet& theElems,
9973 const TIDSortedElemSet& theNodesNot,
9974 std::map< const SMDS_MeshNode*,
9975 const SMDS_MeshNode* >& theNodeNodeMap,
9976 const bool theIsDoubleElem )
9978 // iterate on through element and duplicate them (by nodes duplication)
9980 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9981 for ( ; elemItr != theElems.end(); ++elemItr )
9983 const SMDS_MeshElement* anElem = *elemItr;
9987 bool isDuplicate = false;
9988 // duplicate nodes to duplicate element
9989 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9990 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9992 while ( anIter->more() )
9995 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9996 SMDS_MeshNode* aNewNode = aCurrNode;
9997 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9998 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9999 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10002 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10003 theNodeNodeMap[ aCurrNode ] = aNewNode;
10004 myLastCreatedNodes.Append( aNewNode );
10006 isDuplicate |= (aCurrNode != aNewNode);
10007 newNodes[ ind++ ] = aNewNode;
10009 if ( !isDuplicate )
10012 if ( theIsDoubleElem )
10013 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10015 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10022 //================================================================================
10024 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10025 \param theNodes - identifiers of nodes to be doubled
10026 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10027 nodes. If list of element identifiers is empty then nodes are doubled but
10028 they not assigned to elements
10029 \return TRUE if operation has been completed successfully, FALSE otherwise
10031 //================================================================================
10033 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10034 const std::list< int >& theListOfModifiedElems )
10036 myLastCreatedElems.Clear();
10037 myLastCreatedNodes.Clear();
10039 if ( theListOfNodes.size() == 0 )
10042 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10046 // iterate through nodes and duplicate them
10048 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10050 std::list< int >::const_iterator aNodeIter;
10051 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10053 int aCurr = *aNodeIter;
10054 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10060 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10063 anOldNodeToNewNode[ aNode ] = aNewNode;
10064 myLastCreatedNodes.Append( aNewNode );
10068 // Create map of new nodes for modified elements
10070 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10072 std::list< int >::const_iterator anElemIter;
10073 for ( anElemIter = theListOfModifiedElems.begin();
10074 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10076 int aCurr = *anElemIter;
10077 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10081 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10083 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10085 while ( anIter->more() )
10087 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10088 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10090 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10091 aNodeArr[ ind++ ] = aNewNode;
10094 aNodeArr[ ind++ ] = aCurrNode;
10096 anElemToNodes[ anElem ] = aNodeArr;
10099 // Change nodes of elements
10101 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10102 anElemToNodesIter = anElemToNodes.begin();
10103 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10105 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10106 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10108 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10116 //================================================================================
10118 \brief Check if element located inside shape
10119 \return TRUE if IN or ON shape, FALSE otherwise
10121 //================================================================================
10123 template<class Classifier>
10124 bool isInside(const SMDS_MeshElement* theElem,
10125 Classifier& theClassifier,
10126 const double theTol)
10128 gp_XYZ centerXYZ (0, 0, 0);
10129 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10130 while (aNodeItr->more())
10131 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10133 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10134 theClassifier.Perform(aPnt, theTol);
10135 TopAbs_State aState = theClassifier.State();
10136 return (aState == TopAbs_IN || aState == TopAbs_ON );
10139 //================================================================================
10141 * \brief Classifier of the 3D point on the TopoDS_Face
10142 * with interaface suitable for isInside()
10144 //================================================================================
10146 struct _FaceClassifier
10148 Extrema_ExtPS _extremum;
10149 BRepAdaptor_Surface _surface;
10150 TopAbs_State _state;
10152 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10154 _extremum.Initialize( _surface,
10155 _surface.FirstUParameter(), _surface.LastUParameter(),
10156 _surface.FirstVParameter(), _surface.LastVParameter(),
10157 _surface.Tolerance(), _surface.Tolerance() );
10159 void Perform(const gp_Pnt& aPnt, double theTol)
10161 _state = TopAbs_OUT;
10162 _extremum.Perform(aPnt);
10163 if ( _extremum.IsDone() )
10164 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10165 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10167 TopAbs_State State() const
10174 //================================================================================
10176 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10177 \param theElems - group of of elements (edges or faces) to be replicated
10178 \param theNodesNot - group of nodes not to replicate
10179 \param theShape - shape to detect affected elements (element which geometric center
10180 located on or inside shape).
10181 The replicated nodes should be associated to affected elements.
10182 \return TRUE if operation has been completed successfully, FALSE otherwise
10184 //================================================================================
10186 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10187 const TIDSortedElemSet& theNodesNot,
10188 const TopoDS_Shape& theShape )
10190 if ( theShape.IsNull() )
10193 const double aTol = Precision::Confusion();
10194 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10195 auto_ptr<_FaceClassifier> aFaceClassifier;
10196 if ( theShape.ShapeType() == TopAbs_SOLID )
10198 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10199 bsc3d->PerformInfinitePoint(aTol);
10201 else if (theShape.ShapeType() == TopAbs_FACE )
10203 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10206 // iterates on indicated elements and get elements by back references from their nodes
10207 TIDSortedElemSet anAffected;
10208 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10209 for ( ; elemItr != theElems.end(); ++elemItr )
10211 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10215 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10216 while ( nodeItr->more() )
10218 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10219 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10221 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10222 while ( backElemItr->more() )
10224 const SMDS_MeshElement* curElem = backElemItr->next();
10225 if ( curElem && theElems.find(curElem) == theElems.end() &&
10227 isInside( curElem, *bsc3d, aTol ) :
10228 isInside( curElem, *aFaceClassifier, aTol )))
10229 anAffected.insert( curElem );
10233 return DoubleNodes( theElems, theNodesNot, anAffected );
10236 //================================================================================
10238 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10239 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10240 * \return TRUE if operation has been completed successfully, FALSE otherwise
10242 //================================================================================
10244 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10246 // iterates on volume elements and detect all free faces on them
10247 SMESHDS_Mesh* aMesh = GetMeshDS();
10250 //bool res = false;
10251 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10252 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10255 const SMDS_MeshVolume* volume = vIt->next();
10256 SMDS_VolumeTool vTool( volume );
10257 vTool.SetExternalNormal();
10258 const bool isPoly = volume->IsPoly();
10259 const bool isQuad = volume->IsQuadratic();
10260 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10262 if (!vTool.IsFreeFace(iface))
10265 vector<const SMDS_MeshNode *> nodes;
10266 int nbFaceNodes = vTool.NbFaceNodes(iface);
10267 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10269 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10270 nodes.push_back(faceNodes[inode]);
10272 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10273 nodes.push_back(faceNodes[inode]);
10275 // add new face based on volume nodes
10276 if (aMesh->FindFace( nodes ) ) {
10278 continue; // face already exsist
10280 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10284 return ( nbFree==(nbExisted+nbCreated) );