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