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 void GetElementsNearLine( const gp_Ax1& line,
6275 SMDSAbs_ElementType type,
6276 vector< const SMDS_MeshElement* >& foundElems);
6277 double getTolerance();
6278 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6279 const double tolerance, double & param);
6280 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6281 bool isOuterBoundary(const SMDS_MeshElement* face) const
6283 return _outerFaces.empty() || _outerFaces.count(face);
6285 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6287 const SMDS_MeshElement* _face;
6289 bool _coincides; //!< the line lays in face plane
6290 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6291 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6293 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6296 TIDSortedElemSet _faces;
6297 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6298 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6302 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6304 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6305 << ", _coincides="<<i._coincides << ")";
6308 //=======================================================================
6310 * \brief define tolerance for search
6312 //=======================================================================
6314 double SMESH_ElementSearcherImpl::getTolerance()
6316 if ( _tolerance < 0 )
6318 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6321 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6323 double boxSize = _nodeSearcher->getTree()->maxSize();
6324 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6326 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6328 double boxSize = _ebbTree->maxSize();
6329 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6331 if ( _tolerance == 0 )
6333 // define tolerance by size of a most complex element
6334 int complexType = SMDSAbs_Volume;
6335 while ( complexType > SMDSAbs_All &&
6336 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6338 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6341 if ( complexType == int( SMDSAbs_Node ))
6343 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6345 if ( meshInfo.NbNodes() > 2 )
6346 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6350 const SMDS_MeshElement* elem =
6351 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6352 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6353 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6354 while ( nodeIt->more() )
6356 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6357 elemSize = max( dist, elemSize );
6360 _tolerance = 1e-6 * elemSize;
6366 //================================================================================
6368 * \brief Find intersection of the line and an edge of face and return parameter on line
6370 //================================================================================
6372 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6373 const SMDS_MeshElement* face,
6380 GeomAPI_ExtremaCurveCurve anExtCC;
6381 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6383 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6384 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6386 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6387 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6388 anExtCC.Init( lineCurve, edge);
6389 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6391 Quantity_Parameter pl, pe;
6392 anExtCC.LowerDistanceParameters( pl, pe );
6394 if ( ++nbInts == 2 )
6398 if ( nbInts > 0 ) param /= nbInts;
6401 //================================================================================
6403 * \brief Find all faces belonging to the outer boundary of mesh
6405 //================================================================================
6407 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6409 if ( _outerFacesFound ) return;
6411 // Collect all outer faces by passing from one outer face to another via their links
6412 // and BTW find out if there are internal faces at all.
6414 // checked links and links where outer boundary meets internal one
6415 set< SMESH_TLink > visitedLinks, seamLinks;
6417 // links to treat with already visited faces sharing them
6418 list < TFaceLink > startLinks;
6420 // load startLinks with the first outerFace
6421 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6422 _outerFaces.insert( outerFace );
6424 TIDSortedElemSet emptySet;
6425 while ( !startLinks.empty() )
6427 const SMESH_TLink& link = startLinks.front()._link;
6428 TIDSortedElemSet& faces = startLinks.front()._faces;
6430 outerFace = *faces.begin();
6431 // find other faces sharing the link
6432 const SMDS_MeshElement* f;
6433 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6436 // select another outer face among the found
6437 const SMDS_MeshElement* outerFace2 = 0;
6438 if ( faces.size() == 2 )
6440 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6442 else if ( faces.size() > 2 )
6444 seamLinks.insert( link );
6446 // link direction within the outerFace
6447 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6448 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6449 int i1 = outerFace->GetNodeIndex( link.node1() );
6450 int i2 = outerFace->GetNodeIndex( link.node2() );
6451 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6452 if ( rev ) n1n2.Reverse();
6454 gp_XYZ ofNorm, fNorm;
6455 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6457 // direction from the link inside outerFace
6458 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6459 // sort all other faces by angle with the dirInOF
6460 map< double, const SMDS_MeshElement* > angle2Face;
6461 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6462 for ( ; face != faces.end(); ++face )
6464 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6466 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6467 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6468 if ( angle < 0 ) angle += 2*PI;
6469 angle2Face.insert( make_pair( angle, *face ));
6471 if ( !angle2Face.empty() )
6472 outerFace2 = angle2Face.begin()->second;
6475 // store the found outer face and add its links to continue seaching from
6478 _outerFaces.insert( outerFace );
6479 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6480 for ( int i = 0; i < nbNodes; ++i )
6482 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6483 if ( visitedLinks.insert( link2 ).second )
6484 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6487 startLinks.pop_front();
6489 _outerFacesFound = true;
6491 if ( !seamLinks.empty() )
6493 // There are internal boundaries touching the outher one,
6494 // find all faces of internal boundaries in order to find
6495 // faces of boundaries of holes, if any.
6500 _outerFaces.clear();
6504 //=======================================================================
6506 * \brief Find elements of given type where the given point is IN or ON.
6507 * Returns nb of found elements and elements them-selves.
6509 * 'ALL' type means elements of any type excluding nodes and 0D elements
6511 //=======================================================================
6513 int SMESH_ElementSearcherImpl::
6514 FindElementsByPoint(const gp_Pnt& point,
6515 SMDSAbs_ElementType type,
6516 vector< const SMDS_MeshElement* >& foundElements)
6518 foundElements.clear();
6520 double tolerance = getTolerance();
6522 // =================================================================================
6523 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6525 if ( !_nodeSearcher )
6526 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6528 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6529 if ( !closeNode ) return foundElements.size();
6531 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6532 return foundElements.size(); // to far from any node
6534 if ( type == SMDSAbs_Node )
6536 foundElements.push_back( closeNode );
6540 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6541 while ( elemIt->more() )
6542 foundElements.push_back( elemIt->next() );
6545 // =================================================================================
6546 else // elements more complex than 0D
6548 if ( !_ebbTree || _elementType != type )
6550 if ( _ebbTree ) delete _ebbTree;
6551 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6553 TIDSortedElemSet suspectElems;
6554 _ebbTree->getElementsNearPoint( point, suspectElems );
6555 TIDSortedElemSet::iterator elem = suspectElems.begin();
6556 for ( ; elem != suspectElems.end(); ++elem )
6557 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6558 foundElements.push_back( *elem );
6560 return foundElements.size();
6563 //================================================================================
6565 * \brief Classify the given point in the closed 2D mesh
6567 //================================================================================
6569 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6571 double tolerance = getTolerance();
6572 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6574 if ( _ebbTree ) delete _ebbTree;
6575 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6577 // Algo: analyse transition of a line starting at the point through mesh boundary;
6578 // try three lines parallel to axis of the coordinate system and perform rough
6579 // analysis. If solution is not clear perform thorough analysis.
6581 const int nbAxes = 3;
6582 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6583 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6584 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6585 multimap< int, int > nbInt2Axis; // to find the simplest case
6586 for ( int axis = 0; axis < nbAxes; ++axis )
6588 gp_Ax1 lineAxis( point, axisDir[axis]);
6589 gp_Lin line ( lineAxis );
6591 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6592 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6594 // Intersect faces with the line
6596 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6597 TIDSortedElemSet::iterator face = suspectFaces.begin();
6598 for ( ; face != suspectFaces.end(); ++face )
6602 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6603 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6605 // perform intersection
6606 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6607 if ( !intersection.IsDone() )
6609 if ( intersection.IsInQuadric() )
6611 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6613 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6615 gp_Pnt intersectionPoint = intersection.Point(1);
6616 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6617 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6620 // Analyse intersections roughly
6622 int nbInter = u2inters.size();
6626 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6627 if ( nbInter == 1 ) // not closed mesh
6628 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6630 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6633 if ( (f<0) == (l<0) )
6636 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6637 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6638 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6641 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6643 if ( _outerFacesFound ) break; // pass to thorough analysis
6645 } // three attempts - loop on CS axes
6647 // Analyse intersections thoroughly.
6648 // We make two loops maximum, on the first one we only exclude touching intersections,
6649 // on the second, if situation is still unclear, we gather and use information on
6650 // position of faces (internal or outer). If faces position is already gathered,
6651 // we make the second loop right away.
6653 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6655 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6656 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6658 int axis = nb_axis->second;
6659 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6661 gp_Ax1 lineAxis( point, axisDir[axis]);
6662 gp_Lin line ( lineAxis );
6664 // add tangent intersections to u2inters
6666 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6667 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6668 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6669 u2inters.insert(make_pair( param, *tgtInt ));
6670 tangentInters[ axis ].clear();
6672 // Count intersections before and after the point excluding touching ones.
6673 // If hasPositionInfo we count intersections of outer boundary only
6675 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6676 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6677 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6678 bool ok = ! u_int1->second._coincides;
6679 while ( ok && u_int1 != u2inters.end() )
6681 double u = u_int1->first;
6682 bool touchingInt = false;
6683 if ( ++u_int2 != u2inters.end() )
6685 // skip intersections at the same point (if the line passes through edge or node)
6687 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6693 // skip tangent intersections
6695 const SMDS_MeshElement* prevFace = u_int1->second._face;
6696 while ( ok && u_int2->second._coincides )
6698 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6704 ok = ( u_int2 != u2inters.end() );
6709 // skip intersections at the same point after tangent intersections
6712 double u2 = u_int2->first;
6714 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6720 // decide if we skipped a touching intersection
6721 if ( nbSamePnt + nbTgt > 0 )
6723 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6724 map< double, TInters >::iterator u_int = u_int1;
6725 for ( ; u_int != u_int2; ++u_int )
6727 if ( u_int->second._coincides ) continue;
6728 double dot = u_int->second._faceNorm * line.Direction();
6729 if ( dot > maxDot ) maxDot = dot;
6730 if ( dot < minDot ) minDot = dot;
6732 touchingInt = ( minDot*maxDot < 0 );
6737 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6748 u_int1 = u_int2; // to next intersection
6750 } // loop on intersections with one line
6754 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6757 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6760 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6761 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6763 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6766 if ( (f<0) == (l<0) )
6769 if ( hasPositionInfo )
6770 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6772 } // loop on intersections of the tree lines - thorough analysis
6774 if ( !hasPositionInfo )
6776 // gather info on faces position - is face in the outer boundary or not
6777 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6778 findOuterBoundary( u2inters.begin()->second._face );
6781 } // two attempts - with and w/o faces position info in the mesh
6783 return TopAbs_UNKNOWN;
6786 //=======================================================================
6788 * \brief Return elements possibly intersecting the line
6790 //=======================================================================
6792 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
6793 SMDSAbs_ElementType type,
6794 vector< const SMDS_MeshElement* >& foundElems)
6796 if ( !_ebbTree || _elementType != type )
6798 if ( _ebbTree ) delete _ebbTree;
6799 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6801 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6802 _ebbTree->getElementsNearLine( line, suspectFaces );
6803 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6806 //=======================================================================
6808 * \brief Return SMESH_ElementSearcher
6810 //=======================================================================
6812 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6814 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6817 //=======================================================================
6819 * \brief Return true if the point is IN or ON of the element
6821 //=======================================================================
6823 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6825 if ( element->GetType() == SMDSAbs_Volume)
6827 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6830 // get ordered nodes
6832 vector< gp_XYZ > xyz;
6834 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6835 if ( element->IsQuadratic() )
6836 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6837 nodeIt = f->interlacedNodesElemIterator();
6838 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6839 nodeIt = e->interlacedNodesElemIterator();
6841 while ( nodeIt->more() )
6842 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6844 int i, nbNodes = element->NbNodes();
6846 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6848 // compute face normal
6849 gp_Vec faceNorm(0,0,0);
6850 xyz.push_back( xyz.front() );
6851 for ( i = 0; i < nbNodes; ++i )
6853 gp_Vec edge1( xyz[i+1], xyz[i]);
6854 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6855 faceNorm += edge1 ^ edge2;
6857 double normSize = faceNorm.Magnitude();
6858 if ( normSize <= tol )
6860 // degenerated face: point is out if it is out of all face edges
6861 for ( i = 0; i < nbNodes; ++i )
6863 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6864 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6865 SMDS_MeshEdge edge( &n1, &n2 );
6866 if ( !isOut( &edge, point, tol ))
6871 faceNorm /= normSize;
6873 // check if the point lays on face plane
6874 gp_Vec n2p( xyz[0], point );
6875 if ( fabs( n2p * faceNorm ) > tol )
6876 return true; // not on face plane
6878 // check if point is out of face boundary:
6879 // define it by closest transition of a ray point->infinity through face boundary
6880 // on the face plane.
6881 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6882 // to find intersections of the ray with the boundary.
6884 gp_Vec plnNorm = ray ^ faceNorm;
6885 normSize = plnNorm.Magnitude();
6886 if ( normSize <= tol ) return false; // point coincides with the first node
6887 plnNorm /= normSize;
6888 // for each node of the face, compute its signed distance to the plane
6889 vector<double> dist( nbNodes + 1);
6890 for ( i = 0; i < nbNodes; ++i )
6892 gp_Vec n2p( xyz[i], point );
6893 dist[i] = n2p * plnNorm;
6895 dist.back() = dist.front();
6896 // find the closest intersection
6898 double rClosest, distClosest = 1e100;;
6900 for ( i = 0; i < nbNodes; ++i )
6903 if ( fabs( dist[i]) < tol )
6905 else if ( fabs( dist[i+1]) < tol )
6907 else if ( dist[i] * dist[i+1] < 0 )
6908 r = dist[i] / ( dist[i] - dist[i+1] );
6910 continue; // no intersection
6911 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6912 gp_Vec p2int ( point, pInt);
6913 if ( p2int * ray > -tol ) // right half-space
6915 double intDist = p2int.SquareMagnitude();
6916 if ( intDist < distClosest )
6921 distClosest = intDist;
6926 return true; // no intesections - out
6928 // analyse transition
6929 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6930 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6931 gp_Vec p2int ( point, pClosest );
6932 bool out = (edgeNorm * p2int) < -tol;
6933 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6936 // ray pass through a face node; analyze transition through an adjacent edge
6937 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6938 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6939 gp_Vec edgeAdjacent( p1, p2 );
6940 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6941 bool out2 = (edgeNorm2 * p2int) < -tol;
6943 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6944 return covexCorner ? (out || out2) : (out && out2);
6946 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6948 // point is out of edge if it is NOT ON any straight part of edge
6949 // (we consider quadratic edge as being composed of two straight parts)
6950 for ( i = 1; i < nbNodes; ++i )
6952 gp_Vec edge( xyz[i-1], xyz[i]);
6953 gp_Vec n1p ( xyz[i-1], point);
6954 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6957 gp_Vec n2p( xyz[i], point );
6958 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6960 return false; // point is ON this part
6964 // Node or 0D element -------------------------------------------------------------------------
6966 gp_Vec n2p ( xyz[0], point );
6967 return n2p.Magnitude() <= tol;
6972 //=======================================================================
6973 //function : SimplifyFace
6975 //=======================================================================
6976 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6977 vector<const SMDS_MeshNode *>& poly_nodes,
6978 vector<int>& quantities) const
6980 int nbNodes = faceNodes.size();
6985 set<const SMDS_MeshNode*> nodeSet;
6987 // get simple seq of nodes
6988 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6989 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6990 int iSimple = 0, nbUnique = 0;
6992 simpleNodes[iSimple++] = faceNodes[0];
6994 for (int iCur = 1; iCur < nbNodes; iCur++) {
6995 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6996 simpleNodes[iSimple++] = faceNodes[iCur];
6997 if (nodeSet.insert( faceNodes[iCur] ).second)
7001 int nbSimple = iSimple;
7002 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7012 bool foundLoop = (nbSimple > nbUnique);
7015 set<const SMDS_MeshNode*> loopSet;
7016 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7017 const SMDS_MeshNode* n = simpleNodes[iSimple];
7018 if (!loopSet.insert( n ).second) {
7022 int iC = 0, curLast = iSimple;
7023 for (; iC < curLast; iC++) {
7024 if (simpleNodes[iC] == n) break;
7026 int loopLen = curLast - iC;
7028 // create sub-element
7030 quantities.push_back(loopLen);
7031 for (; iC < curLast; iC++) {
7032 poly_nodes.push_back(simpleNodes[iC]);
7035 // shift the rest nodes (place from the first loop position)
7036 for (iC = curLast + 1; iC < nbSimple; iC++) {
7037 simpleNodes[iC - loopLen] = simpleNodes[iC];
7039 nbSimple -= loopLen;
7042 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7043 } // while (foundLoop)
7047 quantities.push_back(iSimple);
7048 for (int i = 0; i < iSimple; i++)
7049 poly_nodes.push_back(simpleNodes[i]);
7055 //=======================================================================
7056 //function : MergeNodes
7057 //purpose : In each group, the cdr of nodes are substituted by the first one
7059 //=======================================================================
7061 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7063 myLastCreatedElems.Clear();
7064 myLastCreatedNodes.Clear();
7066 SMESHDS_Mesh* aMesh = GetMeshDS();
7068 TNodeNodeMap nodeNodeMap; // node to replace - new node
7069 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7070 list< int > rmElemIds, rmNodeIds;
7072 // Fill nodeNodeMap and elems
7074 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7075 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7076 list<const SMDS_MeshNode*>& nodes = *grIt;
7077 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7078 const SMDS_MeshNode* nToKeep = *nIt;
7079 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7080 const SMDS_MeshNode* nToRemove = *nIt;
7081 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7082 if ( nToRemove != nToKeep ) {
7083 rmNodeIds.push_back( nToRemove->GetID() );
7084 AddToSameGroups( nToKeep, nToRemove, aMesh );
7087 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7088 while ( invElemIt->more() ) {
7089 const SMDS_MeshElement* elem = invElemIt->next();
7094 // Change element nodes or remove an element
7096 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7097 for ( ; eIt != elems.end(); eIt++ ) {
7098 const SMDS_MeshElement* elem = *eIt;
7099 int nbNodes = elem->NbNodes();
7100 int aShapeId = FindShape( elem );
7102 set<const SMDS_MeshNode*> nodeSet;
7103 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7104 int iUnique = 0, iCur = 0, nbRepl = 0;
7105 vector<int> iRepl( nbNodes );
7107 // get new seq of nodes
7108 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7109 while ( itN->more() ) {
7110 const SMDS_MeshNode* n =
7111 static_cast<const SMDS_MeshNode*>( itN->next() );
7113 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7114 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7116 // BUG 0020185: begin
7118 bool stopRecur = false;
7119 set<const SMDS_MeshNode*> nodesRecur;
7120 nodesRecur.insert(n);
7121 while (!stopRecur) {
7122 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7123 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7124 n = (*nnIt_i).second;
7125 if (!nodesRecur.insert(n).second) {
7126 // error: recursive dependancy
7135 iRepl[ nbRepl++ ] = iCur;
7137 curNodes[ iCur ] = n;
7138 bool isUnique = nodeSet.insert( n ).second;
7140 uniqueNodes[ iUnique++ ] = n;
7144 // Analyse element topology after replacement
7147 int nbUniqueNodes = nodeSet.size();
7148 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7149 // Polygons and Polyhedral volumes
7150 if (elem->IsPoly()) {
7152 if (elem->GetType() == SMDSAbs_Face) {
7154 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7156 for (; inode < nbNodes; inode++) {
7157 face_nodes[inode] = curNodes[inode];
7160 vector<const SMDS_MeshNode *> polygons_nodes;
7161 vector<int> quantities;
7162 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7166 for (int iface = 0; iface < nbNew - 1; iface++) {
7167 int nbNodes = quantities[iface];
7168 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7169 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7170 poly_nodes[ii] = polygons_nodes[inode];
7172 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7173 myLastCreatedElems.Append(newElem);
7175 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7177 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7180 rmElemIds.push_back(elem->GetID());
7184 else if (elem->GetType() == SMDSAbs_Volume) {
7185 // Polyhedral volume
7186 if (nbUniqueNodes < 4) {
7187 rmElemIds.push_back(elem->GetID());
7190 // each face has to be analized in order to check volume validity
7191 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7192 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7194 int nbFaces = aPolyedre->NbFaces();
7196 vector<const SMDS_MeshNode *> poly_nodes;
7197 vector<int> quantities;
7199 for (int iface = 1; iface <= nbFaces; iface++) {
7200 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7201 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7203 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7204 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7205 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7206 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7207 faceNode = (*nnIt).second;
7209 faceNodes[inode - 1] = faceNode;
7212 SimplifyFace(faceNodes, poly_nodes, quantities);
7215 if (quantities.size() > 3) {
7216 // to be done: remove coincident faces
7219 if (quantities.size() > 3)
7220 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7222 rmElemIds.push_back(elem->GetID());
7226 rmElemIds.push_back(elem->GetID());
7237 switch ( nbNodes ) {
7238 case 2: ///////////////////////////////////// EDGE
7239 isOk = false; break;
7240 case 3: ///////////////////////////////////// TRIANGLE
7241 isOk = false; break;
7243 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7245 else { //////////////////////////////////// QUADRANGLE
7246 if ( nbUniqueNodes < 3 )
7248 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7249 isOk = false; // opposite nodes stick
7252 case 6: ///////////////////////////////////// PENTAHEDRON
7253 if ( nbUniqueNodes == 4 ) {
7254 // ---------------------------------> tetrahedron
7256 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7257 // all top nodes stick: reverse a bottom
7258 uniqueNodes[ 0 ] = curNodes [ 1 ];
7259 uniqueNodes[ 1 ] = curNodes [ 0 ];
7261 else if (nbRepl == 3 &&
7262 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7263 // all bottom nodes stick: set a top before
7264 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7265 uniqueNodes[ 0 ] = curNodes [ 3 ];
7266 uniqueNodes[ 1 ] = curNodes [ 4 ];
7267 uniqueNodes[ 2 ] = curNodes [ 5 ];
7269 else if (nbRepl == 4 &&
7270 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7271 // a lateral face turns into a line: reverse a bottom
7272 uniqueNodes[ 0 ] = curNodes [ 1 ];
7273 uniqueNodes[ 1 ] = curNodes [ 0 ];
7278 else if ( nbUniqueNodes == 5 ) {
7279 // PENTAHEDRON --------------------> 2 tetrahedrons
7280 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7281 // a bottom node sticks with a linked top one
7283 SMDS_MeshElement* newElem =
7284 aMesh->AddVolume(curNodes[ 3 ],
7287 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7288 myLastCreatedElems.Append(newElem);
7290 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7291 // 2. : reverse a bottom
7292 uniqueNodes[ 0 ] = curNodes [ 1 ];
7293 uniqueNodes[ 1 ] = curNodes [ 0 ];
7303 if(elem->IsQuadratic()) { // Quadratic quadrangle
7316 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7317 uniqueNodes[0] = curNodes[0];
7318 uniqueNodes[1] = curNodes[2];
7319 uniqueNodes[2] = curNodes[3];
7320 uniqueNodes[3] = curNodes[5];
7321 uniqueNodes[4] = curNodes[6];
7322 uniqueNodes[5] = curNodes[7];
7325 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7326 uniqueNodes[0] = curNodes[0];
7327 uniqueNodes[1] = curNodes[1];
7328 uniqueNodes[2] = curNodes[2];
7329 uniqueNodes[3] = curNodes[4];
7330 uniqueNodes[4] = curNodes[5];
7331 uniqueNodes[5] = curNodes[6];
7334 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7335 uniqueNodes[0] = curNodes[1];
7336 uniqueNodes[1] = curNodes[2];
7337 uniqueNodes[2] = curNodes[3];
7338 uniqueNodes[3] = curNodes[5];
7339 uniqueNodes[4] = curNodes[6];
7340 uniqueNodes[5] = curNodes[0];
7343 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7344 uniqueNodes[0] = curNodes[0];
7345 uniqueNodes[1] = curNodes[1];
7346 uniqueNodes[2] = curNodes[3];
7347 uniqueNodes[3] = curNodes[4];
7348 uniqueNodes[4] = curNodes[6];
7349 uniqueNodes[5] = curNodes[7];
7352 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7353 uniqueNodes[0] = curNodes[0];
7354 uniqueNodes[1] = curNodes[2];
7355 uniqueNodes[2] = curNodes[3];
7356 uniqueNodes[3] = curNodes[1];
7357 uniqueNodes[4] = curNodes[6];
7358 uniqueNodes[5] = curNodes[7];
7361 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7362 uniqueNodes[0] = curNodes[0];
7363 uniqueNodes[1] = curNodes[1];
7364 uniqueNodes[2] = curNodes[2];
7365 uniqueNodes[3] = curNodes[4];
7366 uniqueNodes[4] = curNodes[5];
7367 uniqueNodes[5] = curNodes[7];
7370 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7371 uniqueNodes[0] = curNodes[0];
7372 uniqueNodes[1] = curNodes[1];
7373 uniqueNodes[2] = curNodes[3];
7374 uniqueNodes[3] = curNodes[4];
7375 uniqueNodes[4] = curNodes[2];
7376 uniqueNodes[5] = curNodes[7];
7379 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7380 uniqueNodes[0] = curNodes[0];
7381 uniqueNodes[1] = curNodes[1];
7382 uniqueNodes[2] = curNodes[2];
7383 uniqueNodes[3] = curNodes[4];
7384 uniqueNodes[4] = curNodes[5];
7385 uniqueNodes[5] = curNodes[3];
7391 //////////////////////////////////// HEXAHEDRON
7393 SMDS_VolumeTool hexa (elem);
7394 hexa.SetExternalNormal();
7395 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7396 //////////////////////// ---> tetrahedron
7397 for ( int iFace = 0; iFace < 6; iFace++ ) {
7398 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7399 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7400 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7401 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7402 // one face turns into a point ...
7403 int iOppFace = hexa.GetOppFaceIndex( iFace );
7404 ind = hexa.GetFaceNodesIndices( iOppFace );
7406 iUnique = 2; // reverse a tetrahedron bottom
7407 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7408 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7410 else if ( iUnique >= 0 )
7411 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7413 if ( nbStick == 1 ) {
7414 // ... and the opposite one - into a triangle.
7416 ind = hexa.GetFaceNodesIndices( iFace );
7417 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7424 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7425 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7426 for ( int iFace = 0; iFace < 6; iFace++ ) {
7427 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7428 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7429 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7430 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7431 // one face turns into a point ...
7432 int iOppFace = hexa.GetOppFaceIndex( iFace );
7433 ind = hexa.GetFaceNodesIndices( iOppFace );
7435 iUnique = 2; // reverse a tetrahedron 1 bottom
7436 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7437 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7439 else if ( iUnique >= 0 )
7440 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7442 if ( nbStick == 0 ) {
7443 // ... and the opposite one is a quadrangle
7445 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7446 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7449 SMDS_MeshElement* newElem =
7450 aMesh->AddVolume(curNodes[ind[ 0 ]],
7453 curNodes[indTop[ 0 ]]);
7454 myLastCreatedElems.Append(newElem);
7456 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7463 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7464 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7465 // find indices of quad and tri faces
7466 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7467 for ( iFace = 0; iFace < 6; iFace++ ) {
7468 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7470 for ( iCur = 0; iCur < 4; iCur++ )
7471 nodeSet.insert( curNodes[ind[ iCur ]] );
7472 nbUniqueNodes = nodeSet.size();
7473 if ( nbUniqueNodes == 3 )
7474 iTriFace[ nbTri++ ] = iFace;
7475 else if ( nbUniqueNodes == 4 )
7476 iQuadFace[ nbQuad++ ] = iFace;
7478 if (nbQuad == 2 && nbTri == 4 &&
7479 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7480 // 2 opposite quadrangles stuck with a diagonal;
7481 // sample groups of merged indices: (0-4)(2-6)
7482 // --------------------------------------------> 2 tetrahedrons
7483 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7484 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7485 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7486 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7487 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7488 // stuck with 0-2 diagonal
7496 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7497 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7498 // stuck with 1-3 diagonal
7510 uniqueNodes[ 0 ] = curNodes [ i0 ];
7511 uniqueNodes[ 1 ] = curNodes [ i1d ];
7512 uniqueNodes[ 2 ] = curNodes [ i3d ];
7513 uniqueNodes[ 3 ] = curNodes [ i0t ];
7516 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7520 myLastCreatedElems.Append(newElem);
7522 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7525 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7526 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7527 // --------------------------------------------> prism
7528 // find 2 opposite triangles
7530 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7531 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7532 // find indices of kept and replaced nodes
7533 // and fill unique nodes of 2 opposite triangles
7534 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7535 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7536 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7537 // fill unique nodes
7540 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7541 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7542 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7544 // iCur of a linked node of the opposite face (make normals co-directed):
7545 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7546 // check that correspondent corners of triangles are linked
7547 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7550 uniqueNodes[ iUnique ] = n;
7551 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7560 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7566 } // switch ( nbNodes )
7568 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7571 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7572 // Change nodes of polyedre
7573 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7574 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7576 int nbFaces = aPolyedre->NbFaces();
7578 vector<const SMDS_MeshNode *> poly_nodes;
7579 vector<int> quantities (nbFaces);
7581 for (int iface = 1; iface <= nbFaces; iface++) {
7582 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7583 quantities[iface - 1] = nbFaceNodes;
7585 for (inode = 1; inode <= nbFaceNodes; inode++) {
7586 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7588 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7589 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7590 curNode = (*nnIt).second;
7592 poly_nodes.push_back(curNode);
7595 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7599 // Change regular element or polygon
7600 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7604 // Remove invalid regular element or invalid polygon
7605 rmElemIds.push_back( elem->GetID() );
7608 } // loop on elements
7610 // Remove equal nodes and bad elements
7612 Remove( rmNodeIds, true );
7613 Remove( rmElemIds, false );
7618 // ========================================================
7619 // class : SortableElement
7620 // purpose : allow sorting elements basing on their nodes
7621 // ========================================================
7622 class SortableElement : public set <const SMDS_MeshElement*>
7626 SortableElement( const SMDS_MeshElement* theElem )
7629 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7630 while ( nodeIt->more() )
7631 this->insert( nodeIt->next() );
7634 const SMDS_MeshElement* Get() const
7637 void Set(const SMDS_MeshElement* e) const
7642 mutable const SMDS_MeshElement* myElem;
7645 //=======================================================================
7646 //function : FindEqualElements
7647 //purpose : Return list of group of elements built on the same nodes.
7648 // Search among theElements or in the whole mesh if theElements is empty
7649 //=======================================================================
7650 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7651 TListOfListOfElementsID & theGroupsOfElementsID)
7653 myLastCreatedElems.Clear();
7654 myLastCreatedNodes.Clear();
7656 typedef set<const SMDS_MeshElement*> TElemsSet;
7657 typedef map< SortableElement, int > TMapOfNodeSet;
7658 typedef list<int> TGroupOfElems;
7661 if ( theElements.empty() )
7662 { // get all elements in the mesh
7663 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7664 while ( eIt->more() )
7665 elems.insert( elems.end(), eIt->next());
7668 elems = theElements;
7670 vector< TGroupOfElems > arrayOfGroups;
7671 TGroupOfElems groupOfElems;
7672 TMapOfNodeSet mapOfNodeSet;
7674 TElemsSet::iterator elemIt = elems.begin();
7675 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7676 const SMDS_MeshElement* curElem = *elemIt;
7677 SortableElement SE(curElem);
7680 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7681 if( !(pp.second) ) {
7682 TMapOfNodeSet::iterator& itSE = pp.first;
7683 ind = (*itSE).second;
7684 arrayOfGroups[ind].push_back(curElem->GetID());
7687 groupOfElems.clear();
7688 groupOfElems.push_back(curElem->GetID());
7689 arrayOfGroups.push_back(groupOfElems);
7694 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7695 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7696 groupOfElems = *groupIt;
7697 if ( groupOfElems.size() > 1 ) {
7698 groupOfElems.sort();
7699 theGroupsOfElementsID.push_back(groupOfElems);
7704 //=======================================================================
7705 //function : MergeElements
7706 //purpose : In each given group, substitute all elements by the first one.
7707 //=======================================================================
7709 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7711 myLastCreatedElems.Clear();
7712 myLastCreatedNodes.Clear();
7714 typedef list<int> TListOfIDs;
7715 TListOfIDs rmElemIds; // IDs of elems to remove
7717 SMESHDS_Mesh* aMesh = GetMeshDS();
7719 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7720 while ( groupsIt != theGroupsOfElementsID.end() ) {
7721 TListOfIDs& aGroupOfElemID = *groupsIt;
7722 aGroupOfElemID.sort();
7723 int elemIDToKeep = aGroupOfElemID.front();
7724 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7725 aGroupOfElemID.pop_front();
7726 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7727 while ( idIt != aGroupOfElemID.end() ) {
7728 int elemIDToRemove = *idIt;
7729 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7730 // add the kept element in groups of removed one (PAL15188)
7731 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7732 rmElemIds.push_back( elemIDToRemove );
7738 Remove( rmElemIds, false );
7741 //=======================================================================
7742 //function : MergeEqualElements
7743 //purpose : Remove all but one of elements built on the same nodes.
7744 //=======================================================================
7746 void SMESH_MeshEditor::MergeEqualElements()
7748 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7749 to merge equal elements in the whole mesh */
7750 TListOfListOfElementsID aGroupsOfElementsID;
7751 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7752 MergeElements(aGroupsOfElementsID);
7755 //=======================================================================
7756 //function : FindFaceInSet
7757 //purpose : Return a face having linked nodes n1 and n2 and which is
7758 // - not in avoidSet,
7759 // - in elemSet provided that !elemSet.empty()
7760 // i1 and i2 optionally returns indices of n1 and n2
7761 //=======================================================================
7763 const SMDS_MeshElement*
7764 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7765 const SMDS_MeshNode* n2,
7766 const TIDSortedElemSet& elemSet,
7767 const TIDSortedElemSet& avoidSet,
7773 const SMDS_MeshElement* face = 0;
7775 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7776 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7778 const SMDS_MeshElement* elem = invElemIt->next();
7779 if (avoidSet.count( elem ))
7781 if ( !elemSet.empty() && !elemSet.count( elem ))
7784 i1 = elem->GetNodeIndex( n1 );
7785 // find a n2 linked to n1
7786 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7787 for ( int di = -1; di < 2 && !face; di += 2 )
7789 i2 = (i1+di+nbN) % nbN;
7790 if ( elem->GetNode( i2 ) == n2 )
7793 if ( !face && elem->IsQuadratic())
7795 // analysis for quadratic elements using all nodes
7796 const SMDS_QuadraticFaceOfNodes* F =
7797 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7798 // use special nodes iterator
7799 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7800 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7801 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7803 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7804 if ( n1 == prevN && n2 == n )
7808 else if ( n2 == prevN && n1 == n )
7810 face = elem; swap( i1, i2 );
7816 if ( n1ind ) *n1ind = i1;
7817 if ( n2ind ) *n2ind = i2;
7821 //=======================================================================
7822 //function : findAdjacentFace
7824 //=======================================================================
7826 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7827 const SMDS_MeshNode* n2,
7828 const SMDS_MeshElement* elem)
7830 TIDSortedElemSet elemSet, avoidSet;
7832 avoidSet.insert ( elem );
7833 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7836 //=======================================================================
7837 //function : FindFreeBorder
7839 //=======================================================================
7841 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7843 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7844 const SMDS_MeshNode* theSecondNode,
7845 const SMDS_MeshNode* theLastNode,
7846 list< const SMDS_MeshNode* > & theNodes,
7847 list< const SMDS_MeshElement* >& theFaces)
7849 if ( !theFirstNode || !theSecondNode )
7851 // find border face between theFirstNode and theSecondNode
7852 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7856 theFaces.push_back( curElem );
7857 theNodes.push_back( theFirstNode );
7858 theNodes.push_back( theSecondNode );
7860 //vector<const SMDS_MeshNode*> nodes;
7861 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7862 TIDSortedElemSet foundElems;
7863 bool needTheLast = ( theLastNode != 0 );
7865 while ( nStart != theLastNode ) {
7866 if ( nStart == theFirstNode )
7867 return !needTheLast;
7869 // find all free border faces sharing form nStart
7871 list< const SMDS_MeshElement* > curElemList;
7872 list< const SMDS_MeshNode* > nStartList;
7873 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7874 while ( invElemIt->more() ) {
7875 const SMDS_MeshElement* e = invElemIt->next();
7876 if ( e == curElem || foundElems.insert( e ).second ) {
7878 int iNode = 0, nbNodes = e->NbNodes();
7879 //const SMDS_MeshNode* nodes[nbNodes+1];
7880 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7882 if(e->IsQuadratic()) {
7883 const SMDS_QuadraticFaceOfNodes* F =
7884 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7885 // use special nodes iterator
7886 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7887 while( anIter->more() ) {
7888 nodes[ iNode++ ] = anIter->next();
7892 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7893 while ( nIt->more() )
7894 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7896 nodes[ iNode ] = nodes[ 0 ];
7898 for ( iNode = 0; iNode < nbNodes; iNode++ )
7899 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7900 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7901 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7903 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7904 curElemList.push_back( e );
7908 // analyse the found
7910 int nbNewBorders = curElemList.size();
7911 if ( nbNewBorders == 0 ) {
7912 // no free border furthermore
7913 return !needTheLast;
7915 else if ( nbNewBorders == 1 ) {
7916 // one more element found
7918 nStart = nStartList.front();
7919 curElem = curElemList.front();
7920 theFaces.push_back( curElem );
7921 theNodes.push_back( nStart );
7924 // several continuations found
7925 list< const SMDS_MeshElement* >::iterator curElemIt;
7926 list< const SMDS_MeshNode* >::iterator nStartIt;
7927 // check if one of them reached the last node
7928 if ( needTheLast ) {
7929 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7930 curElemIt!= curElemList.end();
7931 curElemIt++, nStartIt++ )
7932 if ( *nStartIt == theLastNode ) {
7933 theFaces.push_back( *curElemIt );
7934 theNodes.push_back( *nStartIt );
7938 // find the best free border by the continuations
7939 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7940 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7941 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7942 curElemIt!= curElemList.end();
7943 curElemIt++, nStartIt++ )
7945 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7946 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7947 // find one more free border
7948 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7952 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7953 // choice: clear a worse one
7954 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7955 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7956 contNodes[ iWorse ].clear();
7957 contFaces[ iWorse ].clear();
7960 if ( contNodes[0].empty() && contNodes[1].empty() )
7963 // append the best free border
7964 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7965 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7966 theNodes.pop_back(); // remove nIgnore
7967 theNodes.pop_back(); // remove nStart
7968 theFaces.pop_back(); // remove curElem
7969 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7970 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7971 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7972 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7975 } // several continuations found
7976 } // while ( nStart != theLastNode )
7981 //=======================================================================
7982 //function : CheckFreeBorderNodes
7983 //purpose : Return true if the tree nodes are on a free border
7984 //=======================================================================
7986 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7987 const SMDS_MeshNode* theNode2,
7988 const SMDS_MeshNode* theNode3)
7990 list< const SMDS_MeshNode* > nodes;
7991 list< const SMDS_MeshElement* > faces;
7992 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7995 //=======================================================================
7996 //function : SewFreeBorder
7998 //=======================================================================
8000 SMESH_MeshEditor::Sew_Error
8001 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8002 const SMDS_MeshNode* theBordSecondNode,
8003 const SMDS_MeshNode* theBordLastNode,
8004 const SMDS_MeshNode* theSideFirstNode,
8005 const SMDS_MeshNode* theSideSecondNode,
8006 const SMDS_MeshNode* theSideThirdNode,
8007 const bool theSideIsFreeBorder,
8008 const bool toCreatePolygons,
8009 const bool toCreatePolyedrs)
8011 myLastCreatedElems.Clear();
8012 myLastCreatedNodes.Clear();
8014 MESSAGE("::SewFreeBorder()");
8015 Sew_Error aResult = SEW_OK;
8017 // ====================================
8018 // find side nodes and elements
8019 // ====================================
8021 list< const SMDS_MeshNode* > nSide[ 2 ];
8022 list< const SMDS_MeshElement* > eSide[ 2 ];
8023 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8024 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8028 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8029 nSide[0], eSide[0])) {
8030 MESSAGE(" Free Border 1 not found " );
8031 aResult = SEW_BORDER1_NOT_FOUND;
8033 if (theSideIsFreeBorder) {
8036 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8037 nSide[1], eSide[1])) {
8038 MESSAGE(" Free Border 2 not found " );
8039 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8042 if ( aResult != SEW_OK )
8045 if (!theSideIsFreeBorder) {
8049 // -------------------------------------------------------------------------
8051 // 1. If nodes to merge are not coincident, move nodes of the free border
8052 // from the coord sys defined by the direction from the first to last
8053 // nodes of the border to the correspondent sys of the side 2
8054 // 2. On the side 2, find the links most co-directed with the correspondent
8055 // links of the free border
8056 // -------------------------------------------------------------------------
8058 // 1. Since sewing may brake if there are volumes to split on the side 2,
8059 // we wont move nodes but just compute new coordinates for them
8060 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8061 TNodeXYZMap nBordXYZ;
8062 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8063 list< const SMDS_MeshNode* >::iterator nBordIt;
8065 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8066 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8067 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8068 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8069 double tol2 = 1.e-8;
8070 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8071 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8072 // Need node movement.
8074 // find X and Z axes to create trsf
8075 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8077 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8079 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8082 gp_Ax3 toBordAx( Pb1, Zb, X );
8083 gp_Ax3 fromSideAx( Ps1, Zs, X );
8084 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8086 gp_Trsf toBordSys, fromSide2Sys;
8087 toBordSys.SetTransformation( toBordAx );
8088 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8089 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8092 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8093 const SMDS_MeshNode* n = *nBordIt;
8094 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8095 toBordSys.Transforms( xyz );
8096 fromSide2Sys.Transforms( xyz );
8097 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8101 // just insert nodes XYZ in the nBordXYZ map
8102 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8103 const SMDS_MeshNode* n = *nBordIt;
8104 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8108 // 2. On the side 2, find the links most co-directed with the correspondent
8109 // links of the free border
8111 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8112 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8113 sideNodes.push_back( theSideFirstNode );
8115 bool hasVolumes = false;
8116 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8117 set<long> foundSideLinkIDs, checkedLinkIDs;
8118 SMDS_VolumeTool volume;
8119 //const SMDS_MeshNode* faceNodes[ 4 ];
8121 const SMDS_MeshNode* sideNode;
8122 const SMDS_MeshElement* sideElem;
8123 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8124 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8125 nBordIt = bordNodes.begin();
8127 // border node position and border link direction to compare with
8128 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8129 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8130 // choose next side node by link direction or by closeness to
8131 // the current border node:
8132 bool searchByDir = ( *nBordIt != theBordLastNode );
8134 // find the next node on the Side 2
8136 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8138 checkedLinkIDs.clear();
8139 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8141 // loop on inverse elements of current node (prevSideNode) on the Side 2
8142 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8143 while ( invElemIt->more() )
8145 const SMDS_MeshElement* elem = invElemIt->next();
8146 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8147 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8148 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8149 bool isVolume = volume.Set( elem );
8150 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8151 if ( isVolume ) // --volume
8153 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8154 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8155 if(elem->IsQuadratic()) {
8156 const SMDS_QuadraticFaceOfNodes* F =
8157 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8158 // use special nodes iterator
8159 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8160 while( anIter->more() ) {
8161 nodes[ iNode ] = anIter->next();
8162 if ( nodes[ iNode++ ] == prevSideNode )
8163 iPrevNode = iNode - 1;
8167 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8168 while ( nIt->more() ) {
8169 nodes[ iNode ] = cast2Node( nIt->next() );
8170 if ( nodes[ iNode++ ] == prevSideNode )
8171 iPrevNode = iNode - 1;
8174 // there are 2 links to check
8179 // loop on links, to be precise, on the second node of links
8180 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8181 const SMDS_MeshNode* n = nodes[ iNode ];
8183 if ( !volume.IsLinked( n, prevSideNode ))
8187 if ( iNode ) // a node before prevSideNode
8188 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8189 else // a node after prevSideNode
8190 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8192 // check if this link was already used
8193 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8194 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8195 if (!isJustChecked &&
8196 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8198 // test a link geometrically
8199 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8200 bool linkIsBetter = false;
8201 double dot = 0.0, dist = 0.0;
8202 if ( searchByDir ) { // choose most co-directed link
8203 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8204 linkIsBetter = ( dot > maxDot );
8206 else { // choose link with the node closest to bordPos
8207 dist = ( nextXYZ - bordPos ).SquareModulus();
8208 linkIsBetter = ( dist < minDist );
8210 if ( linkIsBetter ) {
8219 } // loop on inverse elements of prevSideNode
8222 MESSAGE(" Cant find path by links of the Side 2 ");
8223 return SEW_BAD_SIDE_NODES;
8225 sideNodes.push_back( sideNode );
8226 sideElems.push_back( sideElem );
8227 foundSideLinkIDs.insert ( linkID );
8228 prevSideNode = sideNode;
8230 if ( *nBordIt == theBordLastNode )
8231 searchByDir = false;
8233 // find the next border link to compare with
8234 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8235 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8236 // move to next border node if sideNode is before forward border node (bordPos)
8237 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8238 prevBordNode = *nBordIt;
8240 bordPos = nBordXYZ[ *nBordIt ];
8241 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8242 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8246 while ( sideNode != theSideSecondNode );
8248 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8249 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8250 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8252 } // end nodes search on the side 2
8254 // ============================
8255 // sew the border to the side 2
8256 // ============================
8258 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8259 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8261 TListOfListOfNodes nodeGroupsToMerge;
8262 if ( nbNodes[0] == nbNodes[1] ||
8263 ( theSideIsFreeBorder && !theSideThirdNode)) {
8265 // all nodes are to be merged
8267 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8268 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8269 nIt[0]++, nIt[1]++ )
8271 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8272 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8273 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8278 // insert new nodes into the border and the side to get equal nb of segments
8280 // get normalized parameters of nodes on the borders
8281 //double param[ 2 ][ maxNbNodes ];
8283 param[0] = new double [ maxNbNodes ];
8284 param[1] = new double [ maxNbNodes ];
8286 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8287 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8288 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8289 const SMDS_MeshNode* nPrev = *nIt;
8290 double bordLength = 0;
8291 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8292 const SMDS_MeshNode* nCur = *nIt;
8293 gp_XYZ segment (nCur->X() - nPrev->X(),
8294 nCur->Y() - nPrev->Y(),
8295 nCur->Z() - nPrev->Z());
8296 double segmentLen = segment.Modulus();
8297 bordLength += segmentLen;
8298 param[ iBord ][ iNode ] = bordLength;
8301 // normalize within [0,1]
8302 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8303 param[ iBord ][ iNode ] /= bordLength;
8307 // loop on border segments
8308 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8309 int i[ 2 ] = { 0, 0 };
8310 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8311 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8313 TElemOfNodeListMap insertMap;
8314 TElemOfNodeListMap::iterator insertMapIt;
8316 // key: elem to insert nodes into
8317 // value: 2 nodes to insert between + nodes to be inserted
8319 bool next[ 2 ] = { false, false };
8321 // find min adjacent segment length after sewing
8322 double nextParam = 10., prevParam = 0;
8323 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8324 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8325 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8326 if ( i[ iBord ] > 0 )
8327 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8329 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8330 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8331 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8333 // choose to insert or to merge nodes
8334 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8335 if ( Abs( du ) <= minSegLen * 0.2 ) {
8338 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8339 const SMDS_MeshNode* n0 = *nIt[0];
8340 const SMDS_MeshNode* n1 = *nIt[1];
8341 nodeGroupsToMerge.back().push_back( n1 );
8342 nodeGroupsToMerge.back().push_back( n0 );
8343 // position of node of the border changes due to merge
8344 param[ 0 ][ i[0] ] += du;
8345 // move n1 for the sake of elem shape evaluation during insertion.
8346 // n1 will be removed by MergeNodes() anyway
8347 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8348 next[0] = next[1] = true;
8353 int intoBord = ( du < 0 ) ? 0 : 1;
8354 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8355 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8356 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8357 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8358 if ( intoBord == 1 ) {
8359 // move node of the border to be on a link of elem of the side
8360 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8361 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8362 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8363 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8364 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8366 insertMapIt = insertMap.find( elem );
8367 bool notFound = ( insertMapIt == insertMap.end() );
8368 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8370 // insert into another link of the same element:
8371 // 1. perform insertion into the other link of the elem
8372 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8373 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8374 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8375 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8376 // 2. perform insertion into the link of adjacent faces
8378 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8380 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8384 if (toCreatePolyedrs) {
8385 // perform insertion into the links of adjacent volumes
8386 UpdateVolumes(n12, n22, nodeList);
8388 // 3. find an element appeared on n1 and n2 after the insertion
8389 insertMap.erase( elem );
8390 elem = findAdjacentFace( n1, n2, 0 );
8392 if ( notFound || otherLink ) {
8393 // add element and nodes of the side into the insertMap
8394 insertMapIt = insertMap.insert
8395 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8396 (*insertMapIt).second.push_back( n1 );
8397 (*insertMapIt).second.push_back( n2 );
8399 // add node to be inserted into elem
8400 (*insertMapIt).second.push_back( nIns );
8401 next[ 1 - intoBord ] = true;
8404 // go to the next segment
8405 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8406 if ( next[ iBord ] ) {
8407 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8409 nPrev[ iBord ] = *nIt[ iBord ];
8410 nIt[ iBord ]++; i[ iBord ]++;
8414 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8416 // perform insertion of nodes into elements
8418 for (insertMapIt = insertMap.begin();
8419 insertMapIt != insertMap.end();
8422 const SMDS_MeshElement* elem = (*insertMapIt).first;
8423 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8424 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8425 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8427 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8429 if ( !theSideIsFreeBorder ) {
8430 // look for and insert nodes into the faces adjacent to elem
8432 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8434 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8439 if (toCreatePolyedrs) {
8440 // perform insertion into the links of adjacent volumes
8441 UpdateVolumes(n1, n2, nodeList);
8447 } // end: insert new nodes
8449 MergeNodes ( nodeGroupsToMerge );
8454 //=======================================================================
8455 //function : InsertNodesIntoLink
8456 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8457 // and theBetweenNode2 and split theElement
8458 //=======================================================================
8460 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8461 const SMDS_MeshNode* theBetweenNode1,
8462 const SMDS_MeshNode* theBetweenNode2,
8463 list<const SMDS_MeshNode*>& theNodesToInsert,
8464 const bool toCreatePoly)
8466 if ( theFace->GetType() != SMDSAbs_Face ) return;
8468 // find indices of 2 link nodes and of the rest nodes
8469 int iNode = 0, il1, il2, i3, i4;
8470 il1 = il2 = i3 = i4 = -1;
8471 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8472 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8474 if(theFace->IsQuadratic()) {
8475 const SMDS_QuadraticFaceOfNodes* F =
8476 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8477 // use special nodes iterator
8478 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8479 while( anIter->more() ) {
8480 const SMDS_MeshNode* n = anIter->next();
8481 if ( n == theBetweenNode1 )
8483 else if ( n == theBetweenNode2 )
8489 nodes[ iNode++ ] = n;
8493 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8494 while ( nodeIt->more() ) {
8495 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8496 if ( n == theBetweenNode1 )
8498 else if ( n == theBetweenNode2 )
8504 nodes[ iNode++ ] = n;
8507 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8510 // arrange link nodes to go one after another regarding the face orientation
8511 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8512 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8517 aNodesToInsert.reverse();
8519 // check that not link nodes of a quadrangles are in good order
8520 int nbFaceNodes = theFace->NbNodes();
8521 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8527 if (toCreatePoly || theFace->IsPoly()) {
8530 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8532 // add nodes of face up to first node of link
8535 if(theFace->IsQuadratic()) {
8536 const SMDS_QuadraticFaceOfNodes* F =
8537 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8538 // use special nodes iterator
8539 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8540 while( anIter->more() && !isFLN ) {
8541 const SMDS_MeshNode* n = anIter->next();
8542 poly_nodes[iNode++] = n;
8543 if (n == nodes[il1]) {
8547 // add nodes to insert
8548 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8549 for (; nIt != aNodesToInsert.end(); nIt++) {
8550 poly_nodes[iNode++] = *nIt;
8552 // add nodes of face starting from last node of link
8553 while ( anIter->more() ) {
8554 poly_nodes[iNode++] = anIter->next();
8558 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8559 while ( nodeIt->more() && !isFLN ) {
8560 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8561 poly_nodes[iNode++] = n;
8562 if (n == nodes[il1]) {
8566 // add nodes to insert
8567 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8568 for (; nIt != aNodesToInsert.end(); nIt++) {
8569 poly_nodes[iNode++] = *nIt;
8571 // add nodes of face starting from last node of link
8572 while ( nodeIt->more() ) {
8573 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8574 poly_nodes[iNode++] = n;
8578 // edit or replace the face
8579 SMESHDS_Mesh *aMesh = GetMeshDS();
8581 if (theFace->IsPoly()) {
8582 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8585 int aShapeId = FindShape( theFace );
8587 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8588 myLastCreatedElems.Append(newElem);
8589 if ( aShapeId && newElem )
8590 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8592 aMesh->RemoveElement(theFace);
8597 if( !theFace->IsQuadratic() ) {
8599 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8600 int nbLinkNodes = 2 + aNodesToInsert.size();
8601 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8602 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8603 linkNodes[ 0 ] = nodes[ il1 ];
8604 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8605 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8606 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8607 linkNodes[ iNode++ ] = *nIt;
8609 // decide how to split a quadrangle: compare possible variants
8610 // and choose which of splits to be a quadrangle
8611 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8612 if ( nbFaceNodes == 3 ) {
8613 iBestQuad = nbSplits;
8616 else if ( nbFaceNodes == 4 ) {
8617 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8618 double aBestRate = DBL_MAX;
8619 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8621 double aBadRate = 0;
8622 // evaluate elements quality
8623 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8624 if ( iSplit == iQuad ) {
8625 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8629 aBadRate += getBadRate( &quad, aCrit );
8632 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8634 nodes[ iSplit < iQuad ? i4 : i3 ]);
8635 aBadRate += getBadRate( &tria, aCrit );
8639 if ( aBadRate < aBestRate ) {
8641 aBestRate = aBadRate;
8646 // create new elements
8647 SMESHDS_Mesh *aMesh = GetMeshDS();
8648 int aShapeId = FindShape( theFace );
8651 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8652 SMDS_MeshElement* newElem = 0;
8653 if ( iSplit == iBestQuad )
8654 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8659 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8661 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8662 myLastCreatedElems.Append(newElem);
8663 if ( aShapeId && newElem )
8664 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8667 // change nodes of theFace
8668 const SMDS_MeshNode* newNodes[ 4 ];
8669 newNodes[ 0 ] = linkNodes[ i1 ];
8670 newNodes[ 1 ] = linkNodes[ i2 ];
8671 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8672 newNodes[ 3 ] = nodes[ i4 ];
8673 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8674 } // end if(!theFace->IsQuadratic())
8675 else { // theFace is quadratic
8676 // we have to split theFace on simple triangles and one simple quadrangle
8678 int nbshift = tmp*2;
8679 // shift nodes in nodes[] by nbshift
8681 for(i=0; i<nbshift; i++) {
8682 const SMDS_MeshNode* n = nodes[0];
8683 for(j=0; j<nbFaceNodes-1; j++) {
8684 nodes[j] = nodes[j+1];
8686 nodes[nbFaceNodes-1] = n;
8688 il1 = il1 - nbshift;
8689 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8690 // n0 n1 n2 n0 n1 n2
8691 // +-----+-----+ +-----+-----+
8700 // create new elements
8701 SMESHDS_Mesh *aMesh = GetMeshDS();
8702 int aShapeId = FindShape( theFace );
8705 if(nbFaceNodes==6) { // quadratic triangle
8706 SMDS_MeshElement* newElem =
8707 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8708 myLastCreatedElems.Append(newElem);
8709 if ( aShapeId && newElem )
8710 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8711 if(theFace->IsMediumNode(nodes[il1])) {
8712 // create quadrangle
8713 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8714 myLastCreatedElems.Append(newElem);
8715 if ( aShapeId && newElem )
8716 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8722 // create quadrangle
8723 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8724 myLastCreatedElems.Append(newElem);
8725 if ( aShapeId && newElem )
8726 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8732 else { // nbFaceNodes==8 - quadratic quadrangle
8733 SMDS_MeshElement* newElem =
8734 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8735 myLastCreatedElems.Append(newElem);
8736 if ( aShapeId && newElem )
8737 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8738 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8739 myLastCreatedElems.Append(newElem);
8740 if ( aShapeId && newElem )
8741 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8742 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8743 myLastCreatedElems.Append(newElem);
8744 if ( aShapeId && newElem )
8745 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8746 if(theFace->IsMediumNode(nodes[il1])) {
8747 // create quadrangle
8748 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8749 myLastCreatedElems.Append(newElem);
8750 if ( aShapeId && newElem )
8751 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8757 // create quadrangle
8758 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8759 myLastCreatedElems.Append(newElem);
8760 if ( aShapeId && newElem )
8761 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8767 // create needed triangles using n1,n2,n3 and inserted nodes
8768 int nbn = 2 + aNodesToInsert.size();
8769 //const SMDS_MeshNode* aNodes[nbn];
8770 vector<const SMDS_MeshNode*> aNodes(nbn);
8771 aNodes[0] = nodes[n1];
8772 aNodes[nbn-1] = nodes[n2];
8773 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8774 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8775 aNodes[iNode++] = *nIt;
8777 for(i=1; i<nbn; i++) {
8778 SMDS_MeshElement* newElem =
8779 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8780 myLastCreatedElems.Append(newElem);
8781 if ( aShapeId && newElem )
8782 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8784 // remove old quadratic face
8785 aMesh->RemoveElement(theFace);
8789 //=======================================================================
8790 //function : UpdateVolumes
8792 //=======================================================================
8793 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8794 const SMDS_MeshNode* theBetweenNode2,
8795 list<const SMDS_MeshNode*>& theNodesToInsert)
8797 myLastCreatedElems.Clear();
8798 myLastCreatedNodes.Clear();
8800 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8801 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8802 const SMDS_MeshElement* elem = invElemIt->next();
8804 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8805 SMDS_VolumeTool aVolume (elem);
8806 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8809 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8810 int iface, nbFaces = aVolume.NbFaces();
8811 vector<const SMDS_MeshNode *> poly_nodes;
8812 vector<int> quantities (nbFaces);
8814 for (iface = 0; iface < nbFaces; iface++) {
8815 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8816 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8817 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8819 for (int inode = 0; inode < nbFaceNodes; inode++) {
8820 poly_nodes.push_back(faceNodes[inode]);
8822 if (nbInserted == 0) {
8823 if (faceNodes[inode] == theBetweenNode1) {
8824 if (faceNodes[inode + 1] == theBetweenNode2) {
8825 nbInserted = theNodesToInsert.size();
8827 // add nodes to insert
8828 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8829 for (; nIt != theNodesToInsert.end(); nIt++) {
8830 poly_nodes.push_back(*nIt);
8834 else if (faceNodes[inode] == theBetweenNode2) {
8835 if (faceNodes[inode + 1] == theBetweenNode1) {
8836 nbInserted = theNodesToInsert.size();
8838 // add nodes to insert in reversed order
8839 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8841 for (; nIt != theNodesToInsert.begin(); nIt--) {
8842 poly_nodes.push_back(*nIt);
8844 poly_nodes.push_back(*nIt);
8851 quantities[iface] = nbFaceNodes + nbInserted;
8854 // Replace or update the volume
8855 SMESHDS_Mesh *aMesh = GetMeshDS();
8857 if (elem->IsPoly()) {
8858 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8862 int aShapeId = FindShape( elem );
8864 SMDS_MeshElement* newElem =
8865 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8866 myLastCreatedElems.Append(newElem);
8867 if (aShapeId && newElem)
8868 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8870 aMesh->RemoveElement(elem);
8875 //=======================================================================
8877 * \brief Convert elements contained in a submesh to quadratic
8878 * \retval int - nb of checked elements
8880 //=======================================================================
8882 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8883 SMESH_MesherHelper& theHelper,
8884 const bool theForce3d)
8887 if( !theSm ) return nbElem;
8889 const bool notFromGroups = false;
8890 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8891 while(ElemItr->more())
8894 const SMDS_MeshElement* elem = ElemItr->next();
8895 if( !elem || elem->IsQuadratic() ) continue;
8897 int id = elem->GetID();
8898 int nbNodes = elem->NbNodes();
8899 vector<const SMDS_MeshNode *> aNds (nbNodes);
8901 for(int i = 0; i < nbNodes; i++)
8903 aNds[i] = elem->GetNode(i);
8905 SMDSAbs_ElementType aType = elem->GetType();
8907 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8909 const SMDS_MeshElement* NewElem = 0;
8915 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8923 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8926 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8933 case SMDSAbs_Volume :
8938 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8941 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8944 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8947 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8948 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8958 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8960 theSm->AddElement( NewElem );
8965 //=======================================================================
8966 //function : ConvertToQuadratic
8968 //=======================================================================
8969 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8971 SMESHDS_Mesh* meshDS = GetMeshDS();
8973 SMESH_MesherHelper aHelper(*myMesh);
8974 aHelper.SetIsQuadratic( true );
8975 const bool notFromGroups = false;
8977 int nbCheckedElems = 0;
8978 if ( myMesh->HasShapeToMesh() )
8980 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8982 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8983 while ( smIt->more() ) {
8984 SMESH_subMesh* sm = smIt->next();
8985 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8986 aHelper.SetSubShape( sm->GetSubShape() );
8987 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8992 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8993 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8995 SMESHDS_SubMesh *smDS = 0;
8996 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8997 while(aEdgeItr->more())
8999 const SMDS_MeshEdge* edge = aEdgeItr->next();
9000 if(edge && !edge->IsQuadratic())
9002 int id = edge->GetID();
9003 const SMDS_MeshNode* n1 = edge->GetNode(0);
9004 const SMDS_MeshNode* n2 = edge->GetNode(1);
9006 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
9008 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9009 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9012 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9013 while(aFaceItr->more())
9015 const SMDS_MeshFace* face = aFaceItr->next();
9016 if(!face || face->IsQuadratic() ) continue;
9018 int id = face->GetID();
9019 int nbNodes = face->NbNodes();
9020 vector<const SMDS_MeshNode *> aNds (nbNodes);
9022 for(int i = 0; i < nbNodes; i++)
9024 aNds[i] = face->GetNode(i);
9027 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9029 SMDS_MeshFace * NewFace = 0;
9033 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9036 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9041 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9043 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9044 while(aVolumeItr->more())
9046 const SMDS_MeshVolume* volume = aVolumeItr->next();
9047 if(!volume || volume->IsQuadratic() ) continue;
9049 int id = volume->GetID();
9050 int nbNodes = volume->NbNodes();
9051 vector<const SMDS_MeshNode *> aNds (nbNodes);
9053 for(int i = 0; i < nbNodes; i++)
9055 aNds[i] = volume->GetNode(i);
9058 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9060 SMDS_MeshVolume * NewVolume = 0;
9064 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9065 aNds[3], id, theForce3d );
9068 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9069 aNds[3], aNds[4], id, theForce3d);
9072 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9073 aNds[3], aNds[4], aNds[5], id, theForce3d);
9076 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9077 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9082 ReplaceElemInGroups(volume, NewVolume, meshDS);
9085 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9086 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9087 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9088 aHelper.FixQuadraticElements();
9092 //=======================================================================
9094 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9095 * \retval int - nb of checked elements
9097 //=======================================================================
9099 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9100 SMDS_ElemIteratorPtr theItr,
9101 const int theShapeID)
9104 SMESHDS_Mesh* meshDS = GetMeshDS();
9105 const bool notFromGroups = false;
9107 while( theItr->more() )
9109 const SMDS_MeshElement* elem = theItr->next();
9111 if( elem && elem->IsQuadratic())
9113 int id = elem->GetID();
9114 int nbNodes = elem->NbNodes();
9115 vector<const SMDS_MeshNode *> aNds, mediumNodes;
9116 aNds.reserve( nbNodes );
9117 mediumNodes.reserve( nbNodes );
9119 for(int i = 0; i < nbNodes; i++)
9121 const SMDS_MeshNode* n = elem->GetNode(i);
9123 if( elem->IsMediumNode( n ) )
9124 mediumNodes.push_back( n );
9126 aNds.push_back( n );
9128 if( aNds.empty() ) continue;
9129 SMDSAbs_ElementType aType = elem->GetType();
9131 //remove old quadratic element
9132 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9134 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9135 ReplaceElemInGroups(elem, NewElem, meshDS);
9136 if( theSm && NewElem )
9137 theSm->AddElement( NewElem );
9139 // remove medium nodes
9140 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9141 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9142 const SMDS_MeshNode* n = *nIt;
9143 if ( n->NbInverseElements() == 0 ) {
9144 if ( n->GetPosition()->GetShapeId() != theShapeID )
9145 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9146 ( n->GetPosition()->GetShapeId() ));
9148 meshDS->RemoveFreeNode( n, theSm );
9156 //=======================================================================
9157 //function : ConvertFromQuadratic
9159 //=======================================================================
9160 bool SMESH_MeshEditor::ConvertFromQuadratic()
9162 int nbCheckedElems = 0;
9163 if ( myMesh->HasShapeToMesh() )
9165 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9167 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9168 while ( smIt->more() ) {
9169 SMESH_subMesh* sm = smIt->next();
9170 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9171 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9177 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9178 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9180 SMESHDS_SubMesh *aSM = 0;
9181 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9187 //=======================================================================
9188 //function : SewSideElements
9190 //=======================================================================
9192 SMESH_MeshEditor::Sew_Error
9193 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9194 TIDSortedElemSet& theSide2,
9195 const SMDS_MeshNode* theFirstNode1,
9196 const SMDS_MeshNode* theFirstNode2,
9197 const SMDS_MeshNode* theSecondNode1,
9198 const SMDS_MeshNode* theSecondNode2)
9200 myLastCreatedElems.Clear();
9201 myLastCreatedNodes.Clear();
9203 MESSAGE ("::::SewSideElements()");
9204 if ( theSide1.size() != theSide2.size() )
9205 return SEW_DIFF_NB_OF_ELEMENTS;
9207 Sew_Error aResult = SEW_OK;
9209 // 1. Build set of faces representing each side
9210 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9211 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9213 // =======================================================================
9214 // 1. Build set of faces representing each side:
9215 // =======================================================================
9216 // a. build set of nodes belonging to faces
9217 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9218 // c. create temporary faces representing side of volumes if correspondent
9219 // face does not exist
9221 SMESHDS_Mesh* aMesh = GetMeshDS();
9222 SMDS_Mesh aTmpFacesMesh;
9223 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9224 set<const SMDS_MeshElement*> volSet1, volSet2;
9225 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9226 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9227 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9228 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9229 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9230 int iSide, iFace, iNode;
9232 for ( iSide = 0; iSide < 2; iSide++ ) {
9233 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9234 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9235 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9236 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9237 set<const SMDS_MeshElement*>::iterator vIt;
9238 TIDSortedElemSet::iterator eIt;
9239 set<const SMDS_MeshNode*>::iterator nIt;
9241 // check that given nodes belong to given elements
9242 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9243 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9244 int firstIndex = -1, secondIndex = -1;
9245 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9246 const SMDS_MeshElement* elem = *eIt;
9247 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9248 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9249 if ( firstIndex > -1 && secondIndex > -1 ) break;
9251 if ( firstIndex < 0 || secondIndex < 0 ) {
9252 // we can simply return until temporary faces created
9253 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9256 // -----------------------------------------------------------
9257 // 1a. Collect nodes of existing faces
9258 // and build set of face nodes in order to detect missing
9259 // faces corresponing to sides of volumes
9260 // -----------------------------------------------------------
9262 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9264 // loop on the given element of a side
9265 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9266 //const SMDS_MeshElement* elem = *eIt;
9267 const SMDS_MeshElement* elem = *eIt;
9268 if ( elem->GetType() == SMDSAbs_Face ) {
9269 faceSet->insert( elem );
9270 set <const SMDS_MeshNode*> faceNodeSet;
9271 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9272 while ( nodeIt->more() ) {
9273 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9274 nodeSet->insert( n );
9275 faceNodeSet.insert( n );
9277 setOfFaceNodeSet.insert( faceNodeSet );
9279 else if ( elem->GetType() == SMDSAbs_Volume )
9280 volSet->insert( elem );
9282 // ------------------------------------------------------------------------------
9283 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9284 // ------------------------------------------------------------------------------
9286 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9287 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9288 while ( fIt->more() ) { // loop on faces sharing a node
9289 const SMDS_MeshElement* f = fIt->next();
9290 if ( faceSet->find( f ) == faceSet->end() ) {
9291 // check if all nodes are in nodeSet and
9292 // complete setOfFaceNodeSet if they are
9293 set <const SMDS_MeshNode*> faceNodeSet;
9294 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9295 bool allInSet = true;
9296 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9297 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9298 if ( nodeSet->find( n ) == nodeSet->end() )
9301 faceNodeSet.insert( n );
9304 faceSet->insert( f );
9305 setOfFaceNodeSet.insert( faceNodeSet );
9311 // -------------------------------------------------------------------------
9312 // 1c. Create temporary faces representing sides of volumes if correspondent
9313 // face does not exist
9314 // -------------------------------------------------------------------------
9316 if ( !volSet->empty() ) {
9317 //int nodeSetSize = nodeSet->size();
9319 // loop on given volumes
9320 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9321 SMDS_VolumeTool vol (*vIt);
9322 // loop on volume faces: find free faces
9323 // --------------------------------------
9324 list<const SMDS_MeshElement* > freeFaceList;
9325 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9326 if ( !vol.IsFreeFace( iFace ))
9328 // check if there is already a face with same nodes in a face set
9329 const SMDS_MeshElement* aFreeFace = 0;
9330 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9331 int nbNodes = vol.NbFaceNodes( iFace );
9332 set <const SMDS_MeshNode*> faceNodeSet;
9333 vol.GetFaceNodes( iFace, faceNodeSet );
9334 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9336 // no such a face is given but it still can exist, check it
9337 if ( nbNodes == 3 ) {
9338 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9340 else if ( nbNodes == 4 ) {
9341 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9344 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9345 aFreeFace = aMesh->FindFace(poly_nodes);
9349 // create a temporary face
9350 if ( nbNodes == 3 ) {
9351 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9353 else if ( nbNodes == 4 ) {
9354 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9357 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9358 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9362 freeFaceList.push_back( aFreeFace );
9364 } // loop on faces of a volume
9366 // choose one of several free faces
9367 // --------------------------------------
9368 if ( freeFaceList.size() > 1 ) {
9369 // choose a face having max nb of nodes shared by other elems of a side
9370 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9371 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9372 while ( fIt != freeFaceList.end() ) { // loop on free faces
9373 int nbSharedNodes = 0;
9374 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9375 while ( nodeIt->more() ) { // loop on free face nodes
9376 const SMDS_MeshNode* n =
9377 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9378 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9379 while ( invElemIt->more() ) {
9380 const SMDS_MeshElement* e = invElemIt->next();
9381 if ( faceSet->find( e ) != faceSet->end() )
9383 if ( elemSet->find( e ) != elemSet->end() )
9387 if ( nbSharedNodes >= maxNbNodes ) {
9388 maxNbNodes = nbSharedNodes;
9392 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9394 if ( freeFaceList.size() > 1 )
9396 // could not choose one face, use another way
9397 // choose a face most close to the bary center of the opposite side
9398 gp_XYZ aBC( 0., 0., 0. );
9399 set <const SMDS_MeshNode*> addedNodes;
9400 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9401 eIt = elemSet2->begin();
9402 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9403 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9404 while ( nodeIt->more() ) { // loop on free face nodes
9405 const SMDS_MeshNode* n =
9406 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9407 if ( addedNodes.insert( n ).second )
9408 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9411 aBC /= addedNodes.size();
9412 double minDist = DBL_MAX;
9413 fIt = freeFaceList.begin();
9414 while ( fIt != freeFaceList.end() ) { // loop on free faces
9416 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9417 while ( nodeIt->more() ) { // loop on free face nodes
9418 const SMDS_MeshNode* n =
9419 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9420 gp_XYZ p( n->X(),n->Y(),n->Z() );
9421 dist += ( aBC - p ).SquareModulus();
9423 if ( dist < minDist ) {
9425 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9428 fIt = freeFaceList.erase( fIt++ );
9431 } // choose one of several free faces of a volume
9433 if ( freeFaceList.size() == 1 ) {
9434 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9435 faceSet->insert( aFreeFace );
9436 // complete a node set with nodes of a found free face
9437 // for ( iNode = 0; iNode < ; iNode++ )
9438 // nodeSet->insert( fNodes[ iNode ] );
9441 } // loop on volumes of a side
9443 // // complete a set of faces if new nodes in a nodeSet appeared
9444 // // ----------------------------------------------------------
9445 // if ( nodeSetSize != nodeSet->size() ) {
9446 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9447 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9448 // while ( fIt->more() ) { // loop on faces sharing a node
9449 // const SMDS_MeshElement* f = fIt->next();
9450 // if ( faceSet->find( f ) == faceSet->end() ) {
9451 // // check if all nodes are in nodeSet and
9452 // // complete setOfFaceNodeSet if they are
9453 // set <const SMDS_MeshNode*> faceNodeSet;
9454 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9455 // bool allInSet = true;
9456 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9457 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9458 // if ( nodeSet->find( n ) == nodeSet->end() )
9459 // allInSet = false;
9461 // faceNodeSet.insert( n );
9463 // if ( allInSet ) {
9464 // faceSet->insert( f );
9465 // setOfFaceNodeSet.insert( faceNodeSet );
9471 } // Create temporary faces, if there are volumes given
9474 if ( faceSet1.size() != faceSet2.size() ) {
9475 // delete temporary faces: they are in reverseElements of actual nodes
9476 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9477 while ( tmpFaceIt->more() )
9478 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9479 MESSAGE("Diff nb of faces");
9480 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9483 // ============================================================
9484 // 2. Find nodes to merge:
9485 // bind a node to remove to a node to put instead
9486 // ============================================================
9488 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9489 if ( theFirstNode1 != theFirstNode2 )
9490 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9491 if ( theSecondNode1 != theSecondNode2 )
9492 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9494 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9495 set< long > linkIdSet; // links to process
9496 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9498 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9499 list< NLink > linkList[2];
9500 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9501 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9502 // loop on links in linkList; find faces by links and append links
9503 // of the found faces to linkList
9504 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9505 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9506 NLink link[] = { *linkIt[0], *linkIt[1] };
9507 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9508 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9511 // by links, find faces in the face sets,
9512 // and find indices of link nodes in the found faces;
9513 // in a face set, there is only one or no face sharing a link
9514 // ---------------------------------------------------------------
9516 const SMDS_MeshElement* face[] = { 0, 0 };
9517 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9518 vector<const SMDS_MeshNode*> fnodes1(9);
9519 vector<const SMDS_MeshNode*> fnodes2(9);
9520 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9521 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9522 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9523 int iLinkNode[2][2];
9524 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9525 const SMDS_MeshNode* n1 = link[iSide].first;
9526 const SMDS_MeshNode* n2 = link[iSide].second;
9527 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9528 set< const SMDS_MeshElement* > fMap;
9529 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9530 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9531 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9532 while ( fIt->more() ) { // loop on faces sharing a node
9533 const SMDS_MeshElement* f = fIt->next();
9534 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9535 ! fMap.insert( f ).second ) // f encounters twice
9537 if ( face[ iSide ] ) {
9538 MESSAGE( "2 faces per link " );
9539 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9543 faceSet->erase( f );
9544 // get face nodes and find ones of a link
9549 fnodes1.resize(f->NbNodes()+1);
9550 notLinkNodes1.resize(f->NbNodes()-2);
9553 fnodes2.resize(f->NbNodes()+1);
9554 notLinkNodes2.resize(f->NbNodes()-2);
9557 if(!f->IsQuadratic()) {
9558 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9559 while ( nIt->more() ) {
9560 const SMDS_MeshNode* n =
9561 static_cast<const SMDS_MeshNode*>( nIt->next() );
9563 iLinkNode[ iSide ][ 0 ] = iNode;
9565 else if ( n == n2 ) {
9566 iLinkNode[ iSide ][ 1 ] = iNode;
9568 //else if ( notLinkNodes[ iSide ][ 0 ] )
9569 // notLinkNodes[ iSide ][ 1 ] = n;
9571 // notLinkNodes[ iSide ][ 0 ] = n;
9575 notLinkNodes1[nbl] = n;
9576 //notLinkNodes1.push_back(n);
9578 notLinkNodes2[nbl] = n;
9579 //notLinkNodes2.push_back(n);
9581 //faceNodes[ iSide ][ iNode++ ] = n;
9583 fnodes1[iNode++] = n;
9586 fnodes2[iNode++] = n;
9590 else { // f->IsQuadratic()
9591 const SMDS_QuadraticFaceOfNodes* F =
9592 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9593 // use special nodes iterator
9594 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9595 while ( anIter->more() ) {
9596 const SMDS_MeshNode* n =
9597 static_cast<const SMDS_MeshNode*>( anIter->next() );
9599 iLinkNode[ iSide ][ 0 ] = iNode;
9601 else if ( n == n2 ) {
9602 iLinkNode[ iSide ][ 1 ] = iNode;
9607 notLinkNodes1[nbl] = n;
9610 notLinkNodes2[nbl] = n;
9614 fnodes1[iNode++] = n;
9617 fnodes2[iNode++] = n;
9621 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9623 fnodes1[iNode] = fnodes1[0];
9626 fnodes2[iNode] = fnodes1[0];
9633 // check similarity of elements of the sides
9634 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9635 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9636 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9637 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9640 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9642 break; // do not return because it s necessary to remove tmp faces
9645 // set nodes to merge
9646 // -------------------
9648 if ( face[0] && face[1] ) {
9649 int nbNodes = face[0]->NbNodes();
9650 if ( nbNodes != face[1]->NbNodes() ) {
9651 MESSAGE("Diff nb of face nodes");
9652 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9653 break; // do not return because it s necessary to remove tmp faces
9655 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9656 if ( nbNodes == 3 ) {
9657 //nReplaceMap.insert( TNodeNodeMap::value_type
9658 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9659 nReplaceMap.insert( TNodeNodeMap::value_type
9660 ( notLinkNodes1[0], notLinkNodes2[0] ));
9663 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9664 // analyse link orientation in faces
9665 int i1 = iLinkNode[ iSide ][ 0 ];
9666 int i2 = iLinkNode[ iSide ][ 1 ];
9667 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9668 // if notLinkNodes are the first and the last ones, then
9669 // their order does not correspond to the link orientation
9670 if (( i1 == 1 && i2 == 2 ) ||
9671 ( i1 == 2 && i2 == 1 ))
9672 reverse[ iSide ] = !reverse[ iSide ];
9674 if ( reverse[0] == reverse[1] ) {
9675 //nReplaceMap.insert( TNodeNodeMap::value_type
9676 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9677 //nReplaceMap.insert( TNodeNodeMap::value_type
9678 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9679 for(int nn=0; nn<nbNodes-2; nn++) {
9680 nReplaceMap.insert( TNodeNodeMap::value_type
9681 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9685 //nReplaceMap.insert( TNodeNodeMap::value_type
9686 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9687 //nReplaceMap.insert( TNodeNodeMap::value_type
9688 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9689 for(int nn=0; nn<nbNodes-2; nn++) {
9690 nReplaceMap.insert( TNodeNodeMap::value_type
9691 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9696 // add other links of the faces to linkList
9697 // -----------------------------------------
9699 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9700 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9701 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9702 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9703 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9704 if ( !iter_isnew.second ) { // already in a set: no need to process
9705 linkIdSet.erase( iter_isnew.first );
9707 else // new in set == encountered for the first time: add
9709 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9710 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9711 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9712 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9713 linkList[0].push_back ( NLink( n1, n2 ));
9714 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9718 } // loop on link lists
9720 if ( aResult == SEW_OK &&
9721 ( linkIt[0] != linkList[0].end() ||
9722 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9723 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9724 " " << (faceSetPtr[1]->empty()));
9725 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9728 // ====================================================================
9729 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9730 // ====================================================================
9732 // delete temporary faces: they are in reverseElements of actual nodes
9733 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9734 while ( tmpFaceIt->more() )
9735 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9737 if ( aResult != SEW_OK)
9740 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9741 // loop on nodes replacement map
9742 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9743 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9744 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9745 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9746 nodeIDsToRemove.push_back( nToRemove->GetID() );
9747 // loop on elements sharing nToRemove
9748 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9749 while ( invElemIt->more() ) {
9750 const SMDS_MeshElement* e = invElemIt->next();
9751 // get a new suite of nodes: make replacement
9752 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9753 vector< const SMDS_MeshNode*> nodes( nbNodes );
9754 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9755 while ( nIt->more() ) {
9756 const SMDS_MeshNode* n =
9757 static_cast<const SMDS_MeshNode*>( nIt->next() );
9758 nnIt = nReplaceMap.find( n );
9759 if ( nnIt != nReplaceMap.end() ) {
9765 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9766 // elemIDsToRemove.push_back( e->GetID() );
9769 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9773 Remove( nodeIDsToRemove, true );
9778 //================================================================================
9780 * \brief Find corresponding nodes in two sets of faces
9781 * \param theSide1 - first face set
9782 * \param theSide2 - second first face
9783 * \param theFirstNode1 - a boundary node of set 1
9784 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9785 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9786 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9787 * \param nReplaceMap - output map of corresponding nodes
9788 * \retval bool - is a success or not
9790 //================================================================================
9793 //#define DEBUG_MATCHING_NODES
9796 SMESH_MeshEditor::Sew_Error
9797 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9798 set<const SMDS_MeshElement*>& theSide2,
9799 const SMDS_MeshNode* theFirstNode1,
9800 const SMDS_MeshNode* theFirstNode2,
9801 const SMDS_MeshNode* theSecondNode1,
9802 const SMDS_MeshNode* theSecondNode2,
9803 TNodeNodeMap & nReplaceMap)
9805 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9807 nReplaceMap.clear();
9808 if ( theFirstNode1 != theFirstNode2 )
9809 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9810 if ( theSecondNode1 != theSecondNode2 )
9811 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9813 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9814 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9816 list< NLink > linkList[2];
9817 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9818 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9820 // loop on links in linkList; find faces by links and append links
9821 // of the found faces to linkList
9822 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9823 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9824 NLink link[] = { *linkIt[0], *linkIt[1] };
9825 if ( linkSet.find( link[0] ) == linkSet.end() )
9828 // by links, find faces in the face sets,
9829 // and find indices of link nodes in the found faces;
9830 // in a face set, there is only one or no face sharing a link
9831 // ---------------------------------------------------------------
9833 const SMDS_MeshElement* face[] = { 0, 0 };
9834 list<const SMDS_MeshNode*> notLinkNodes[2];
9835 //bool reverse[] = { false, false }; // order of notLinkNodes
9837 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9839 const SMDS_MeshNode* n1 = link[iSide].first;
9840 const SMDS_MeshNode* n2 = link[iSide].second;
9841 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9842 set< const SMDS_MeshElement* > facesOfNode1;
9843 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9845 // during a loop of the first node, we find all faces around n1,
9846 // during a loop of the second node, we find one face sharing both n1 and n2
9847 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9848 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9849 while ( fIt->more() ) { // loop on faces sharing a node
9850 const SMDS_MeshElement* f = fIt->next();
9851 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9852 ! facesOfNode1.insert( f ).second ) // f encounters twice
9854 if ( face[ iSide ] ) {
9855 MESSAGE( "2 faces per link " );
9856 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9859 faceSet->erase( f );
9861 // get not link nodes
9862 int nbN = f->NbNodes();
9863 if ( f->IsQuadratic() )
9865 nbNodes[ iSide ] = nbN;
9866 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9867 int i1 = f->GetNodeIndex( n1 );
9868 int i2 = f->GetNodeIndex( n2 );
9869 int iEnd = nbN, iBeg = -1, iDelta = 1;
9870 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9872 std::swap( iEnd, iBeg ); iDelta = -1;
9877 if ( i == iEnd ) i = iBeg + iDelta;
9878 if ( i == i1 ) break;
9879 nodes.push_back ( f->GetNode( i ) );
9885 // check similarity of elements of the sides
9886 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9887 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9888 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9889 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9892 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9896 // set nodes to merge
9897 // -------------------
9899 if ( face[0] && face[1] ) {
9900 if ( nbNodes[0] != nbNodes[1] ) {
9901 MESSAGE("Diff nb of face nodes");
9902 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9904 #ifdef DEBUG_MATCHING_NODES
9905 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9906 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9907 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9909 int nbN = nbNodes[0];
9911 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9912 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9913 for ( int i = 0 ; i < nbN - 2; ++i ) {
9914 #ifdef DEBUG_MATCHING_NODES
9915 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9917 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9921 // add other links of the face 1 to linkList
9922 // -----------------------------------------
9924 const SMDS_MeshElement* f0 = face[0];
9925 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9926 for ( int i = 0; i < nbN; i++ )
9928 const SMDS_MeshNode* n2 = f0->GetNode( i );
9929 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9930 linkSet.insert( SMESH_TLink( n1, n2 ));
9931 if ( !iter_isnew.second ) { // already in a set: no need to process
9932 linkSet.erase( iter_isnew.first );
9934 else // new in set == encountered for the first time: add
9936 #ifdef DEBUG_MATCHING_NODES
9937 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9938 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9940 linkList[0].push_back ( NLink( n1, n2 ));
9941 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9946 } // loop on link lists
9951 //================================================================================
9953 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9954 \param theElems - the list of elements (edges or faces) to be replicated
9955 The nodes for duplication could be found from these elements
9956 \param theNodesNot - list of nodes to NOT replicate
9957 \param theAffectedElems - the list of elements (cells and edges) to which the
9958 replicated nodes should be associated to.
9959 \return TRUE if operation has been completed successfully, FALSE otherwise
9961 //================================================================================
9963 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9964 const TIDSortedElemSet& theNodesNot,
9965 const TIDSortedElemSet& theAffectedElems )
9967 myLastCreatedElems.Clear();
9968 myLastCreatedNodes.Clear();
9970 if ( theElems.size() == 0 )
9973 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9978 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9979 // duplicate elements and nodes
9980 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9981 // replce nodes by duplications
9982 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9986 //================================================================================
9988 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9989 \param theMeshDS - mesh instance
9990 \param theElems - the elements replicated or modified (nodes should be changed)
9991 \param theNodesNot - nodes to NOT replicate
9992 \param theNodeNodeMap - relation of old node to new created node
9993 \param theIsDoubleElem - flag os to replicate element or modify
9994 \return TRUE if operation has been completed successfully, FALSE otherwise
9996 //================================================================================
9998 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9999 const TIDSortedElemSet& theElems,
10000 const TIDSortedElemSet& theNodesNot,
10001 std::map< const SMDS_MeshNode*,
10002 const SMDS_MeshNode* >& theNodeNodeMap,
10003 const bool theIsDoubleElem )
10005 // iterate on through element and duplicate them (by nodes duplication)
10007 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10008 for ( ; elemItr != theElems.end(); ++elemItr )
10010 const SMDS_MeshElement* anElem = *elemItr;
10014 bool isDuplicate = false;
10015 // duplicate nodes to duplicate element
10016 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10017 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10019 while ( anIter->more() )
10022 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10023 SMDS_MeshNode* aNewNode = aCurrNode;
10024 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10025 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10026 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10029 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10030 theNodeNodeMap[ aCurrNode ] = aNewNode;
10031 myLastCreatedNodes.Append( aNewNode );
10033 isDuplicate |= (aCurrNode != aNewNode);
10034 newNodes[ ind++ ] = aNewNode;
10036 if ( !isDuplicate )
10039 if ( theIsDoubleElem )
10040 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10042 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10049 //================================================================================
10051 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10052 \param theNodes - identifiers of nodes to be doubled
10053 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10054 nodes. If list of element identifiers is empty then nodes are doubled but
10055 they not assigned to elements
10056 \return TRUE if operation has been completed successfully, FALSE otherwise
10058 //================================================================================
10060 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10061 const std::list< int >& theListOfModifiedElems )
10063 myLastCreatedElems.Clear();
10064 myLastCreatedNodes.Clear();
10066 if ( theListOfNodes.size() == 0 )
10069 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10073 // iterate through nodes and duplicate them
10075 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10077 std::list< int >::const_iterator aNodeIter;
10078 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10080 int aCurr = *aNodeIter;
10081 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10087 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10090 anOldNodeToNewNode[ aNode ] = aNewNode;
10091 myLastCreatedNodes.Append( aNewNode );
10095 // Create map of new nodes for modified elements
10097 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10099 std::list< int >::const_iterator anElemIter;
10100 for ( anElemIter = theListOfModifiedElems.begin();
10101 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10103 int aCurr = *anElemIter;
10104 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10108 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10110 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10112 while ( anIter->more() )
10114 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10115 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10117 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10118 aNodeArr[ ind++ ] = aNewNode;
10121 aNodeArr[ ind++ ] = aCurrNode;
10123 anElemToNodes[ anElem ] = aNodeArr;
10126 // Change nodes of elements
10128 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10129 anElemToNodesIter = anElemToNodes.begin();
10130 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10132 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10133 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10135 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10143 //================================================================================
10145 \brief Check if element located inside shape
10146 \return TRUE if IN or ON shape, FALSE otherwise
10148 //================================================================================
10150 template<class Classifier>
10151 bool isInside(const SMDS_MeshElement* theElem,
10152 Classifier& theClassifier,
10153 const double theTol)
10155 gp_XYZ centerXYZ (0, 0, 0);
10156 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10157 while (aNodeItr->more())
10158 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10160 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10161 theClassifier.Perform(aPnt, theTol);
10162 TopAbs_State aState = theClassifier.State();
10163 return (aState == TopAbs_IN || aState == TopAbs_ON );
10166 //================================================================================
10168 * \brief Classifier of the 3D point on the TopoDS_Face
10169 * with interaface suitable for isInside()
10171 //================================================================================
10173 struct _FaceClassifier
10175 Extrema_ExtPS _extremum;
10176 BRepAdaptor_Surface _surface;
10177 TopAbs_State _state;
10179 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10181 _extremum.Initialize( _surface,
10182 _surface.FirstUParameter(), _surface.LastUParameter(),
10183 _surface.FirstVParameter(), _surface.LastVParameter(),
10184 _surface.Tolerance(), _surface.Tolerance() );
10186 void Perform(const gp_Pnt& aPnt, double theTol)
10188 _state = TopAbs_OUT;
10189 _extremum.Perform(aPnt);
10190 if ( _extremum.IsDone() )
10191 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10192 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10194 TopAbs_State State() const
10201 //================================================================================
10203 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10204 \param theElems - group of of elements (edges or faces) to be replicated
10205 \param theNodesNot - group of nodes not to replicate
10206 \param theShape - shape to detect affected elements (element which geometric center
10207 located on or inside shape).
10208 The replicated nodes should be associated to affected elements.
10209 \return TRUE if operation has been completed successfully, FALSE otherwise
10211 //================================================================================
10213 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10214 const TIDSortedElemSet& theNodesNot,
10215 const TopoDS_Shape& theShape )
10217 if ( theShape.IsNull() )
10220 const double aTol = Precision::Confusion();
10221 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10222 auto_ptr<_FaceClassifier> aFaceClassifier;
10223 if ( theShape.ShapeType() == TopAbs_SOLID )
10225 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10226 bsc3d->PerformInfinitePoint(aTol);
10228 else if (theShape.ShapeType() == TopAbs_FACE )
10230 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10233 // iterates on indicated elements and get elements by back references from their nodes
10234 TIDSortedElemSet anAffected;
10235 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10236 for ( ; elemItr != theElems.end(); ++elemItr )
10238 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10242 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10243 while ( nodeItr->more() )
10245 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10246 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10248 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10249 while ( backElemItr->more() )
10251 const SMDS_MeshElement* curElem = backElemItr->next();
10252 if ( curElem && theElems.find(curElem) == theElems.end() &&
10254 isInside( curElem, *bsc3d, aTol ) :
10255 isInside( curElem, *aFaceClassifier, aTol )))
10256 anAffected.insert( curElem );
10260 return DoubleNodes( theElems, theNodesNot, anAffected );
10263 //================================================================================
10265 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10266 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10267 * \return TRUE if operation has been completed successfully, FALSE otherwise
10269 //================================================================================
10271 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10273 // iterates on volume elements and detect all free faces on them
10274 SMESHDS_Mesh* aMesh = GetMeshDS();
10277 //bool res = false;
10278 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10279 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10282 const SMDS_MeshVolume* volume = vIt->next();
10283 SMDS_VolumeTool vTool( volume );
10284 vTool.SetExternalNormal();
10285 const bool isPoly = volume->IsPoly();
10286 const bool isQuad = volume->IsQuadratic();
10287 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10289 if (!vTool.IsFreeFace(iface))
10292 vector<const SMDS_MeshNode *> nodes;
10293 int nbFaceNodes = vTool.NbFaceNodes(iface);
10294 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10296 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10297 nodes.push_back(faceNodes[inode]);
10299 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10300 nodes.push_back(faceNodes[inode]);
10302 // add new face based on volume nodes
10303 if (aMesh->FindFace( nodes ) ) {
10305 continue; // face already exsist
10307 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10311 return ( nbFree==(nbExisted+nbCreated) );