1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 #include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
39 #include "SMESHDS_Group.hxx"
40 #include "SMESHDS_Mesh.hxx"
42 #include "SMESH_Algo.hxx"
43 #include "SMESH_ControlsDef.hxx"
44 #include "SMESH_Group.hxx"
45 #include "SMESH_MesherHelper.hxx"
46 #include "SMESH_OctreeNode.hxx"
47 #include "SMESH_subMesh.hxx"
49 #include "utilities.h"
51 #include <BRepAdaptor_Surface.hxx>
52 #include <BRepClass3d_SolidClassifier.hxx>
53 #include <BRep_Tool.hxx>
55 #include <Extrema_GenExtPS.hxx>
56 #include <Extrema_POnCurv.hxx>
57 #include <Extrema_POnSurf.hxx>
58 #include <GC_MakeSegment.hxx>
59 #include <Geom2d_Curve.hxx>
60 #include <GeomAPI_ExtremaCurveCurve.hxx>
61 #include <GeomAdaptor_Surface.hxx>
62 #include <Geom_Curve.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Surface.hxx>
65 #include <IntAna_IntConicQuad.hxx>
66 #include <IntAna_Quadric.hxx>
67 #include <Precision.hxx>
68 #include <TColStd_ListOfInteger.hxx>
69 #include <TopAbs_State.hxx>
71 #include <TopExp_Explorer.hxx>
72 #include <TopTools_ListIteratorOfListOfShape.hxx>
73 #include <TopTools_ListOfShape.hxx>
74 #include <TopTools_SequenceOfShape.hxx>
76 #include <TopoDS_Face.hxx>
82 #include <gp_Trsf.hxx>
94 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
97 using namespace SMESH::Controls;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
102 //=======================================================================
103 //function : SMESH_MeshEditor
105 //=======================================================================
107 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
108 :myMesh( theMesh ) // theMesh may be NULL
112 //=======================================================================
116 //=======================================================================
119 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
120 const SMDSAbs_ElementType type,
124 SMDS_MeshElement* e = 0;
125 int nbnode = node.size();
126 SMESHDS_Mesh* mesh = GetMeshDS();
128 case SMDSAbs_0DElement:
130 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
131 else e = mesh->Add0DElement (node[0] );
135 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
136 else e = mesh->AddEdge (node[0], node[1] );
137 else if ( nbnode == 3 )
138 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
139 else e = mesh->AddEdge (node[0], node[1], node[2] );
144 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
145 else e = mesh->AddFace (node[0], node[1], node[2] );
146 else if (nbnode == 4)
147 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
149 else if (nbnode == 6)
150 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151 node[4], node[5], ID);
152 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
154 else if (nbnode == 8)
155 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
156 node[4], node[5], node[6], node[7], ID);
157 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
158 node[4], node[5], node[6], node[7] );
160 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
161 else e = mesh->AddPolygonalFace (node );
167 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
169 else if (nbnode == 5)
170 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
174 else if (nbnode == 6)
175 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176 node[4], node[5], ID);
177 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
179 else if (nbnode == 8)
180 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181 node[4], node[5], node[6], node[7], ID);
182 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7] );
184 else if (nbnode == 10)
185 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
186 node[4], node[5], node[6], node[7],
187 node[8], node[9], ID);
188 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7],
191 else if (nbnode == 13)
192 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193 node[4], node[5], node[6], node[7],
194 node[8], node[9], node[10],node[11],
196 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
197 node[4], node[5], node[6], node[7],
198 node[8], node[9], node[10],node[11],
200 else if (nbnode == 15)
201 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
202 node[4], node[5], node[6], node[7],
203 node[8], node[9], node[10],node[11],
204 node[12],node[13],node[14],ID);
205 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
206 node[4], node[5], node[6], node[7],
207 node[8], node[9], node[10],node[11],
208 node[12],node[13],node[14] );
209 else if (nbnode == 20)
210 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211 node[4], node[5], node[6], node[7],
212 node[8], node[9], node[10],node[11],
213 node[12],node[13],node[14],node[15],
214 node[16],node[17],node[18],node[19],ID);
215 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
216 node[4], node[5], node[6], node[7],
217 node[8], node[9], node[10],node[11],
218 node[12],node[13],node[14],node[15],
219 node[16],node[17],node[18],node[19] );
225 //=======================================================================
229 //=======================================================================
231 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
232 const SMDSAbs_ElementType type,
236 vector<const SMDS_MeshNode*> nodes;
237 nodes.reserve( nodeIDs.size() );
238 vector<int>::const_iterator id = nodeIDs.begin();
239 while ( id != nodeIDs.end() ) {
240 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
241 nodes.push_back( node );
245 return AddElement( nodes, type, isPoly, ID );
248 //=======================================================================
250 //purpose : Remove a node or an element.
251 // Modify a compute state of sub-meshes which become empty
252 //=======================================================================
254 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
257 myLastCreatedElems.Clear();
258 myLastCreatedNodes.Clear();
260 SMESHDS_Mesh* aMesh = GetMeshDS();
261 set< SMESH_subMesh *> smmap;
263 list<int>::const_iterator it = theIDs.begin();
264 for ( ; it != theIDs.end(); it++ ) {
265 const SMDS_MeshElement * elem;
267 elem = aMesh->FindNode( *it );
269 elem = aMesh->FindElement( *it );
273 // Notify VERTEX sub-meshes about modification
275 const SMDS_MeshNode* node = cast2Node( elem );
276 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
277 if ( int aShapeID = node->GetPosition()->GetShapeId() )
278 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
281 // Find sub-meshes to notify about modification
282 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
283 // while ( nodeIt->more() ) {
284 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
285 // const SMDS_PositionPtr& aPosition = node->GetPosition();
286 // if ( aPosition.get() ) {
287 // if ( int aShapeID = aPosition->GetShapeId() ) {
288 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
289 // smmap.insert( sm );
296 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
298 aMesh->RemoveElement( elem );
301 // Notify sub-meshes about modification
302 if ( !smmap.empty() ) {
303 set< SMESH_subMesh *>::iterator smIt;
304 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
305 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
308 // // Check if the whole mesh becomes empty
309 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
310 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
315 //=======================================================================
316 //function : FindShape
317 //purpose : Return an index of the shape theElem is on
318 // or zero if a shape not found
319 //=======================================================================
321 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
323 myLastCreatedElems.Clear();
324 myLastCreatedNodes.Clear();
326 SMESHDS_Mesh * aMesh = GetMeshDS();
327 if ( aMesh->ShapeToMesh().IsNull() )
330 if ( theElem->GetType() == SMDSAbs_Node ) {
331 const SMDS_PositionPtr& aPosition =
332 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
333 if ( aPosition.get() )
334 return aPosition->GetShapeId();
339 TopoDS_Shape aShape; // the shape a node is on
340 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
341 while ( nodeIt->more() ) {
342 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
343 const SMDS_PositionPtr& aPosition = node->GetPosition();
344 if ( aPosition.get() ) {
345 int aShapeID = aPosition->GetShapeId();
346 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
348 if ( sm->Contains( theElem ))
350 if ( aShape.IsNull() )
351 aShape = aMesh->IndexToShape( aShapeID );
354 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
359 // None of nodes is on a proper shape,
360 // find the shape among ancestors of aShape on which a node is
361 if ( aShape.IsNull() ) {
362 //MESSAGE ("::FindShape() - NONE node is on shape")
365 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
366 for ( ; ancIt.More(); ancIt.Next() ) {
367 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
368 if ( sm && sm->Contains( theElem ))
369 return aMesh->ShapeToIndex( ancIt.Value() );
372 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
376 //=======================================================================
377 //function : IsMedium
379 //=======================================================================
381 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
382 const SMDSAbs_ElementType typeToCheck)
384 bool isMedium = false;
385 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
386 while (it->more() && !isMedium ) {
387 const SMDS_MeshElement* elem = it->next();
388 isMedium = elem->IsMediumNode(node);
393 //=======================================================================
394 //function : ShiftNodesQuadTria
396 // Shift nodes in the array corresponded to quadratic triangle
397 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
398 //=======================================================================
399 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
401 const SMDS_MeshNode* nd1 = aNodes[0];
402 aNodes[0] = aNodes[1];
403 aNodes[1] = aNodes[2];
405 const SMDS_MeshNode* nd2 = aNodes[3];
406 aNodes[3] = aNodes[4];
407 aNodes[4] = aNodes[5];
411 //=======================================================================
412 //function : GetNodesFromTwoTria
414 // Shift nodes in the array corresponded to quadratic triangle
415 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
416 //=======================================================================
417 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
418 const SMDS_MeshElement * theTria2,
419 const SMDS_MeshNode* N1[],
420 const SMDS_MeshNode* N2[])
422 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
425 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
428 if(it->more()) return false;
429 it = theTria2->nodesIterator();
432 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
435 if(it->more()) return false;
437 int sames[3] = {-1,-1,-1};
449 if(nbsames!=2) return false;
451 ShiftNodesQuadTria(N1);
453 ShiftNodesQuadTria(N1);
456 i = sames[0] + sames[1] + sames[2];
458 ShiftNodesQuadTria(N2);
460 // now we receive following N1 and N2 (using numeration as above image)
461 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
462 // i.e. first nodes from both arrays determ new diagonal
466 //=======================================================================
467 //function : InverseDiag
468 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
469 // but having other common link.
470 // Return False if args are improper
471 //=======================================================================
473 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
474 const SMDS_MeshElement * theTria2 )
476 myLastCreatedElems.Clear();
477 myLastCreatedNodes.Clear();
479 if (!theTria1 || !theTria2)
482 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
483 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
486 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
487 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
491 // put nodes in array and find out indices of the same ones
492 const SMDS_MeshNode* aNodes [6];
493 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
495 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
496 while ( it->more() ) {
497 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
499 if ( i > 2 ) // theTria2
500 // find same node of theTria1
501 for ( int j = 0; j < 3; j++ )
502 if ( aNodes[ i ] == aNodes[ j ]) {
511 return false; // theTria1 is not a triangle
512 it = theTria2->nodesIterator();
514 if ( i == 6 && it->more() )
515 return false; // theTria2 is not a triangle
518 // find indices of 1,2 and of A,B in theTria1
519 int iA = 0, iB = 0, i1 = 0, i2 = 0;
520 for ( i = 0; i < 6; i++ ) {
521 if ( sameInd [ i ] == 0 )
528 // nodes 1 and 2 should not be the same
529 if ( aNodes[ i1 ] == aNodes[ i2 ] )
533 aNodes[ iA ] = aNodes[ i2 ];
535 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
537 //MESSAGE( theTria1 << theTria2 );
539 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
540 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
542 //MESSAGE( theTria1 << theTria2 );
546 } // end if(F1 && F2)
548 // check case of quadratic faces
549 const SMDS_QuadraticFaceOfNodes* QF1 =
550 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
551 if(!QF1) return false;
552 const SMDS_QuadraticFaceOfNodes* QF2 =
553 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
554 if(!QF2) return false;
557 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
558 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
566 const SMDS_MeshNode* N1 [6];
567 const SMDS_MeshNode* N2 [6];
568 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
570 // now we receive following N1 and N2 (using numeration as above image)
571 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
572 // i.e. first nodes from both arrays determ new diagonal
574 const SMDS_MeshNode* N1new [6];
575 const SMDS_MeshNode* N2new [6];
588 // replaces nodes in faces
589 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
590 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
595 //=======================================================================
596 //function : findTriangles
597 //purpose : find triangles sharing theNode1-theNode2 link
598 //=======================================================================
600 static bool findTriangles(const SMDS_MeshNode * theNode1,
601 const SMDS_MeshNode * theNode2,
602 const SMDS_MeshElement*& theTria1,
603 const SMDS_MeshElement*& theTria2)
605 if ( !theNode1 || !theNode2 ) return false;
607 theTria1 = theTria2 = 0;
609 set< const SMDS_MeshElement* > emap;
610 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
612 const SMDS_MeshElement* elem = it->next();
613 if ( elem->NbNodes() == 3 )
616 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
618 const SMDS_MeshElement* elem = it->next();
619 if ( emap.find( elem ) != emap.end() )
621 // theTria1 must be element with minimum ID
622 if( theTria1->GetID() < elem->GetID() ) {
635 return ( theTria1 && theTria2 );
638 //=======================================================================
639 //function : InverseDiag
640 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
641 // with ones built on the same 4 nodes but having other common link.
642 // Return false if proper faces not found
643 //=======================================================================
645 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
646 const SMDS_MeshNode * theNode2)
648 myLastCreatedElems.Clear();
649 myLastCreatedNodes.Clear();
651 MESSAGE( "::InverseDiag()" );
653 const SMDS_MeshElement *tr1, *tr2;
654 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
657 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
658 //if (!F1) return false;
659 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
660 //if (!F2) return false;
663 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
664 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
668 // put nodes in array
669 // and find indices of 1,2 and of A in tr1 and of B in tr2
670 int i, iA1 = 0, i1 = 0;
671 const SMDS_MeshNode* aNodes1 [3];
672 SMDS_ElemIteratorPtr it;
673 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
674 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
675 if ( aNodes1[ i ] == theNode1 )
676 iA1 = i; // node A in tr1
677 else if ( aNodes1[ i ] != theNode2 )
681 const SMDS_MeshNode* aNodes2 [3];
682 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
683 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
684 if ( aNodes2[ i ] == theNode2 )
685 iB2 = i; // node B in tr2
686 else if ( aNodes2[ i ] != theNode1 )
690 // nodes 1 and 2 should not be the same
691 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
695 aNodes1[ iA1 ] = aNodes2[ i2 ];
697 aNodes2[ iB2 ] = aNodes1[ i1 ];
699 //MESSAGE( tr1 << tr2 );
701 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
702 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
704 //MESSAGE( tr1 << tr2 );
709 // check case of quadratic faces
710 const SMDS_QuadraticFaceOfNodes* QF1 =
711 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
712 if(!QF1) return false;
713 const SMDS_QuadraticFaceOfNodes* QF2 =
714 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
715 if(!QF2) return false;
716 return InverseDiag(tr1,tr2);
719 //=======================================================================
720 //function : getQuadrangleNodes
721 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
722 // fusion of triangles tr1 and tr2 having shared link on
723 // theNode1 and theNode2
724 //=======================================================================
726 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
727 const SMDS_MeshNode * theNode1,
728 const SMDS_MeshNode * theNode2,
729 const SMDS_MeshElement * tr1,
730 const SMDS_MeshElement * tr2 )
732 if( tr1->NbNodes() != tr2->NbNodes() )
734 // find the 4-th node to insert into tr1
735 const SMDS_MeshNode* n4 = 0;
736 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
738 while ( !n4 && i<3 ) {
739 const SMDS_MeshNode * n = cast2Node( it->next() );
741 bool isDiag = ( n == theNode1 || n == theNode2 );
745 // Make an array of nodes to be in a quadrangle
746 int iNode = 0, iFirstDiag = -1;
747 it = tr1->nodesIterator();
750 const SMDS_MeshNode * n = cast2Node( it->next() );
752 bool isDiag = ( n == theNode1 || n == theNode2 );
754 if ( iFirstDiag < 0 )
756 else if ( iNode - iFirstDiag == 1 )
757 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
759 else if ( n == n4 ) {
760 return false; // tr1 and tr2 should not have all the same nodes
762 theQuadNodes[ iNode++ ] = n;
764 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
765 theQuadNodes[ iNode ] = n4;
770 //=======================================================================
771 //function : DeleteDiag
772 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
773 // with a quadrangle built on the same 4 nodes.
774 // Return false if proper faces not found
775 //=======================================================================
777 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
778 const SMDS_MeshNode * theNode2)
780 myLastCreatedElems.Clear();
781 myLastCreatedNodes.Clear();
783 MESSAGE( "::DeleteDiag()" );
785 const SMDS_MeshElement *tr1, *tr2;
786 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
789 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
790 //if (!F1) return false;
791 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
792 //if (!F2) return false;
795 const SMDS_MeshNode* aNodes [ 4 ];
796 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
799 //MESSAGE( endl << tr1 << tr2 );
801 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
802 myLastCreatedElems.Append(tr1);
803 GetMeshDS()->RemoveElement( tr2 );
805 //MESSAGE( endl << tr1 );
810 // check case of quadratic faces
811 const SMDS_QuadraticFaceOfNodes* QF1 =
812 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
813 if(!QF1) return false;
814 const SMDS_QuadraticFaceOfNodes* QF2 =
815 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
816 if(!QF2) return false;
819 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
820 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
828 const SMDS_MeshNode* N1 [6];
829 const SMDS_MeshNode* N2 [6];
830 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
832 // now we receive following N1 and N2 (using numeration as above image)
833 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
834 // i.e. first nodes from both arrays determ new diagonal
836 const SMDS_MeshNode* aNodes[8];
846 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
847 myLastCreatedElems.Append(tr1);
848 GetMeshDS()->RemoveElement( tr2 );
850 // remove middle node (9)
851 GetMeshDS()->RemoveNode( N1[4] );
856 //=======================================================================
857 //function : Reorient
858 //purpose : Reverse theElement orientation
859 //=======================================================================
861 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
863 myLastCreatedElems.Clear();
864 myLastCreatedNodes.Clear();
868 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
869 if ( !it || !it->more() )
872 switch ( theElem->GetType() ) {
876 if(!theElem->IsQuadratic()) {
877 int i = theElem->NbNodes();
878 vector<const SMDS_MeshNode*> aNodes( i );
880 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
881 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
884 // quadratic elements
885 if(theElem->GetType()==SMDSAbs_Edge) {
886 vector<const SMDS_MeshNode*> aNodes(3);
887 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
888 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
889 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
890 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
893 int nbn = theElem->NbNodes();
894 vector<const SMDS_MeshNode*> aNodes(nbn);
895 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
897 for(; i<nbn/2; i++) {
898 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
900 for(i=0; i<nbn/2; i++) {
901 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
903 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
907 case SMDSAbs_Volume: {
908 if (theElem->IsPoly()) {
909 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
910 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
912 MESSAGE("Warning: bad volumic element");
916 int nbFaces = aPolyedre->NbFaces();
917 vector<const SMDS_MeshNode *> poly_nodes;
918 vector<int> quantities (nbFaces);
920 // reverse each face of the polyedre
921 for (int iface = 1; iface <= nbFaces; iface++) {
922 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
923 quantities[iface - 1] = nbFaceNodes;
925 for (inode = nbFaceNodes; inode >= 1; inode--) {
926 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
927 poly_nodes.push_back(curNode);
931 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
935 SMDS_VolumeTool vTool;
936 if ( !vTool.Set( theElem ))
939 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
948 //=======================================================================
949 //function : getBadRate
951 //=======================================================================
953 static double getBadRate (const SMDS_MeshElement* theElem,
954 SMESH::Controls::NumericalFunctorPtr& theCrit)
956 SMESH::Controls::TSequenceOfXYZ P;
957 if ( !theElem || !theCrit->GetPoints( theElem, P ))
959 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
960 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
963 //=======================================================================
964 //function : QuadToTri
965 //purpose : Cut quadrangles into triangles.
966 // theCrit is used to select a diagonal to cut
967 //=======================================================================
969 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
970 SMESH::Controls::NumericalFunctorPtr theCrit)
972 myLastCreatedElems.Clear();
973 myLastCreatedNodes.Clear();
975 MESSAGE( "::QuadToTri()" );
977 if ( !theCrit.get() )
980 SMESHDS_Mesh * aMesh = GetMeshDS();
982 Handle(Geom_Surface) surface;
983 SMESH_MesherHelper helper( *GetMesh() );
985 TIDSortedElemSet::iterator itElem;
986 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
987 const SMDS_MeshElement* elem = *itElem;
988 if ( !elem || elem->GetType() != SMDSAbs_Face )
990 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
993 // retrieve element nodes
994 const SMDS_MeshNode* aNodes [8];
995 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
997 while ( itN->more() )
998 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1000 // compare two sets of possible triangles
1001 double aBadRate1, aBadRate2; // to what extent a set is bad
1002 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1003 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1004 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1006 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1007 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1008 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1010 int aShapeId = FindShape( elem );
1011 const SMDS_MeshElement* newElem = 0;
1013 if( !elem->IsQuadratic() ) {
1015 // split liner quadrangle
1017 if ( aBadRate1 <= aBadRate2 ) {
1018 // tr1 + tr2 is better
1019 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1020 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1023 // tr3 + tr4 is better
1024 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1025 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1030 // split quadratic quadrangle
1032 // get surface elem is on
1033 if ( aShapeId != helper.GetSubShapeID() ) {
1037 shape = aMesh->IndexToShape( aShapeId );
1038 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1039 TopoDS_Face face = TopoDS::Face( shape );
1040 surface = BRep_Tool::Surface( face );
1041 if ( !surface.IsNull() )
1042 helper.SetSubShape( shape );
1046 const SMDS_MeshNode* aNodes [8];
1047 const SMDS_MeshNode* inFaceNode = 0;
1048 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1050 while ( itN->more() ) {
1051 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1052 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1053 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1055 inFaceNode = aNodes[ i-1 ];
1058 // find middle point for (0,1,2,3)
1059 // and create a node in this point;
1061 if ( surface.IsNull() ) {
1063 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1067 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1070 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1072 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1074 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1075 myLastCreatedNodes.Append(newN);
1077 // create a new element
1078 const SMDS_MeshNode* N[6];
1079 if ( aBadRate1 <= aBadRate2 ) {
1086 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1087 aNodes[6], aNodes[7], newN );
1096 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1097 aNodes[7], aNodes[4], newN );
1099 aMesh->ChangeElementNodes( elem, N, 6 );
1103 // care of a new element
1105 myLastCreatedElems.Append(newElem);
1106 AddToSameGroups( newElem, elem, aMesh );
1108 // put a new triangle on the same shape
1110 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1115 //=======================================================================
1116 //function : BestSplit
1117 //purpose : Find better diagonal for cutting.
1118 //=======================================================================
1120 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1121 SMESH::Controls::NumericalFunctorPtr theCrit)
1123 myLastCreatedElems.Clear();
1124 myLastCreatedNodes.Clear();
1129 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1132 if( theQuad->NbNodes()==4 ||
1133 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1135 // retrieve element nodes
1136 const SMDS_MeshNode* aNodes [4];
1137 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1139 //while (itN->more())
1141 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1143 // compare two sets of possible triangles
1144 double aBadRate1, aBadRate2; // to what extent a set is bad
1145 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1146 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1147 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1149 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1150 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1151 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1153 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1154 return 1; // diagonal 1-3
1156 return 2; // diagonal 2-4
1163 // Methods of splitting volumes into tetra
1165 const int theHexTo5_1[5*4+1] =
1167 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1169 const int theHexTo5_2[5*4+1] =
1171 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1173 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1175 const int theHexTo6_1[6*4+1] =
1177 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1
1179 const int theHexTo6_2[6*4+1] =
1181 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1
1183 const int theHexTo6_3[6*4+1] =
1185 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1
1187 const int theHexTo6_4[6*4+1] =
1189 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1
1191 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1193 const int thePyraTo2_1[2*4+1] =
1195 0, 1, 2, 4, 0, 2, 3, 4, -1
1197 const int thePyraTo2_2[2*4+1] =
1199 1, 2, 3, 4, 1, 3, 0, 4, -1
1201 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1203 const int thePentaTo3_1[3*4+1] =
1205 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1207 const int thePentaTo3_2[3*4+1] =
1209 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1211 const int thePentaTo3_3[3*4+1] =
1213 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1215 const int thePentaTo3_4[3*4+1] =
1217 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1219 const int thePentaTo3_5[3*4+1] =
1221 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1223 const int thePentaTo3_6[3*4+1] =
1225 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1227 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1228 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1230 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1233 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1234 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1235 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1240 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1241 bool _baryNode; //!< additional node is to be created at cell barycenter
1242 bool _ownConn; //!< to delete _connectivity in destructor
1244 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1245 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1246 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1247 bool hasFacet( const TTriangleFacet& facet ) const
1249 const int* tetConn = _connectivity;
1250 for ( ; tetConn[0] >= 0; tetConn += 4 )
1251 if (( facet.contains( tetConn[0] ) +
1252 facet.contains( tetConn[1] ) +
1253 facet.contains( tetConn[2] ) +
1254 facet.contains( tetConn[3] )) == 3 )
1260 //=======================================================================
1262 * \brief return TSplitMethod for the given element
1264 //=======================================================================
1266 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1268 int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1270 // Find out how adjacent volumes are split
1272 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1273 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1274 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1276 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1277 maxTetConnSize += 4 * ( nbNodes - 2 );
1278 if ( nbNodes < 4 ) continue;
1280 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1281 const int* nInd = vol.GetFaceNodesIndices( iF );
1284 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1285 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1286 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1287 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1291 int iCom = 0; // common node of triangle faces to split into
1292 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1294 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1295 nInd[ iQ * ( (iCom+1)%nbNodes )],
1296 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1297 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1298 nInd[ iQ * ( (iCom+2)%nbNodes )],
1299 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1300 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1302 triaSplits.push_back( t012 );
1303 triaSplits.push_back( t023 );
1308 if ( !triaSplits.empty() )
1309 hasAdjacentSplits = true;
1312 // Among variants of split method select one compliant with adjacent volumes
1314 TSplitMethod method;
1315 if ( !vol.Element()->IsPoly() )
1317 int nbVariants = 2, nbTet = 0;
1318 const int** connVariants = 0;
1319 switch ( vol.Element()->GetEntityType() )
1321 case SMDSEntity_Hexa:
1322 case SMDSEntity_Quad_Hexa:
1323 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1324 connVariants = theHexTo5, nbTet = 5;
1326 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1328 case SMDSEntity_Pyramid:
1329 case SMDSEntity_Quad_Pyramid:
1330 connVariants = thePyraTo2; nbTet = 2;
1332 case SMDSEntity_Penta:
1333 case SMDSEntity_Quad_Penta:
1334 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1339 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1341 // check method compliancy with adjacent tetras,
1342 // all found splits must be among facets of tetras described by this method
1343 method = TSplitMethod( nbTet, connVariants[variant] );
1344 if ( hasAdjacentSplits && method._nbTetra > 0 )
1346 bool facetCreated = true;
1347 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1349 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1350 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1351 facetCreated = method.hasFacet( *facet );
1353 if ( !facetCreated )
1354 method = TSplitMethod(0); // incompatible method
1358 if ( method._nbTetra < 1 )
1360 // No standard method is applicable, use a generic solution:
1361 // each facet of a volume is split into triangles and
1362 // each of triangles and a volume barycenter form a tetrahedron.
1364 int* connectivity = new int[ maxTetConnSize + 1 ];
1365 method._connectivity = connectivity;
1366 method._ownConn = true;
1367 method._baryNode = true;
1370 int baryCenInd = vol.NbNodes();
1371 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1373 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1374 const int* nInd = vol.GetFaceNodesIndices( iF );
1375 // find common node of triangle facets of tetra to create
1376 int iCommon = 0; // index in linear numeration
1377 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1378 if ( !triaSplits.empty() )
1381 const TTriangleFacet* facet = &triaSplits.front();
1382 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1383 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1384 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1387 else if ( nbNodes > 3 )
1389 // find the best method of splitting into triangles by aspect ratio
1390 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1391 map< double, int > badness2iCommon;
1392 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1393 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1394 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1395 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1397 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1398 nodes[ iQ*((iLast-1)%nbNodes)],
1399 nodes[ iQ*((iLast )%nbNodes)]);
1400 double badness = getBadRate( &tria, aspectRatio );
1401 badness2iCommon.insert( make_pair( badness, iCommon ));
1403 // use iCommon with lowest badness
1404 iCommon = badness2iCommon.begin()->second;
1406 if ( iCommon >= nbNodes )
1407 iCommon = 0; // something wrong
1408 // fill connectivity of tetra
1409 int nbTet = nbNodes - 2;
1410 for ( int i = 0; i < nbTet; ++i )
1412 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1413 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1414 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1415 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1416 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1417 connectivity[ connSize++ ] = baryCenInd;
1421 connectivity[ connSize++ ] = -1;
1425 //================================================================================
1427 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1429 //================================================================================
1431 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1433 // find the tetrahedron including the three nodes of facet
1434 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1435 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1436 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1437 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1438 while ( volIt1->more() )
1440 const SMDS_MeshElement* v = volIt1->next();
1441 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1443 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1444 while ( volIt2->more() )
1445 if ( v != volIt2->next() )
1447 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1448 while ( volIt3->more() )
1449 if ( v == volIt3->next() )
1456 //=======================================================================
1457 //function : SplitVolumesIntoTetra
1458 //purpose : Split volumic elements into tetrahedra.
1459 //=======================================================================
1461 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1462 const int theMethodFlags)
1464 // std-like iterator on coordinates of nodes of mesh element
1465 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1466 NXyzIterator xyzEnd;
1468 SMDS_VolumeTool volTool;
1469 SMESH_MesherHelper helper( *GetMesh());
1471 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1472 SMESHDS_SubMesh* fSubMesh = subMesh;
1474 SMESH_SequenceOfElemPtr newNodes, newElems;
1476 TIDSortedElemSet::const_iterator elem = theElems.begin();
1477 for ( ; elem != theElems.end(); ++elem )
1479 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1480 if ( geomType <= SMDSEntity_Quad_Tetra )
1481 continue; // tetra or face or ...
1483 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1485 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1486 if ( splitMethod._nbTetra < 1 ) continue;
1488 // find submesh to add new tetras in
1489 if ( !subMesh || !subMesh->Contains( *elem ))
1491 int shapeID = FindShape( *elem );
1492 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1493 subMesh = GetMeshDS()->MeshElements( shapeID );
1496 if ( (*elem)->IsQuadratic() )
1499 // add quadratic links to the helper
1500 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1502 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1503 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1504 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1506 helper.SetIsQuadratic( true );
1511 helper.SetIsQuadratic( false );
1513 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1514 if ( splitMethod._baryNode )
1516 // make a node at barycenter
1518 gc = accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd, gc ) / nodes.size();
1519 SMDS_MeshNode* gcNode = helper.AddNode( gc.X(), gc.Y(), gc.Z() );
1520 nodes.push_back( gcNode );
1521 newNodes.Append( gcNode );
1525 helper.SetElementsOnShape( true );
1526 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1527 const int* tetConn = splitMethod._connectivity;
1528 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1529 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1530 nodes[ tetConn[1] ],
1531 nodes[ tetConn[2] ],
1532 nodes[ tetConn[3] ]));
1534 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1536 // Split faces on sides of the split volume
1538 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1539 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1541 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1542 if ( nbNodes < 4 ) continue;
1544 // find an existing face
1545 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1546 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1547 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1549 // among possible triangles create ones discribed by split method
1550 const int* nInd = volTool.GetFaceNodesIndices( iF );
1551 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1552 int iCom = 0; // common node of triangle faces to split into
1553 list< TTriangleFacet > facets;
1554 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1556 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1557 nInd[ iQ * ( (iCom+1)%nbNodes )],
1558 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1559 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1560 nInd[ iQ * ( (iCom+2)%nbNodes )],
1561 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1562 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1564 facets.push_back( t012 );
1565 facets.push_back( t023 );
1566 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1567 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1568 nInd[ iQ * ((iLast-1)%nbNodes )],
1569 nInd[ iQ * ((iLast )%nbNodes )]));
1573 // find submesh to add new faces in
1574 if ( !fSubMesh || !fSubMesh->Contains( face ))
1576 int shapeID = FindShape( face );
1577 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1580 helper.SetElementsOnShape( false );
1581 vector< const SMDS_MeshElement* > triangles;
1582 list< TTriangleFacet >::iterator facet = facets.begin();
1583 for ( ; facet != facets.end(); ++facet )
1585 if ( !volTool.IsFaceExternal( iF ))
1586 swap( facet->_n2, facet->_n3 );
1587 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1588 volNodes[ facet->_n2 ],
1589 volNodes[ facet->_n3 ]));
1590 if ( triangles.back() && fSubMesh )
1591 fSubMesh->AddElement( triangles.back());
1592 newElems.Append( triangles.back() );
1594 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1595 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1598 } // loop on volume faces to split them into triangles
1600 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1602 } // loop on volumes to split
1604 myLastCreatedNodes = newNodes;
1605 myLastCreatedElems = newElems;
1608 //=======================================================================
1609 //function : AddToSameGroups
1610 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1611 //=======================================================================
1613 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1614 const SMDS_MeshElement* elemInGroups,
1615 SMESHDS_Mesh * aMesh)
1617 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1618 if (!groups.empty()) {
1619 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1620 for ( ; grIt != groups.end(); grIt++ ) {
1621 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1622 if ( group && group->Contains( elemInGroups ))
1623 group->SMDSGroup().Add( elemToAdd );
1629 //=======================================================================
1630 //function : RemoveElemFromGroups
1631 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1632 //=======================================================================
1633 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1634 SMESHDS_Mesh * aMesh)
1636 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1637 if (!groups.empty())
1639 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1640 for (; GrIt != groups.end(); GrIt++)
1642 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1643 if (!grp || grp->IsEmpty()) continue;
1644 grp->SMDSGroup().Remove(removeelem);
1649 //================================================================================
1651 * \brief Replace elemToRm by elemToAdd in the all groups
1653 //================================================================================
1655 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1656 const SMDS_MeshElement* elemToAdd,
1657 SMESHDS_Mesh * aMesh)
1659 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1660 if (!groups.empty()) {
1661 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1662 for ( ; grIt != groups.end(); grIt++ ) {
1663 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1664 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1665 group->SMDSGroup().Add( elemToAdd );
1670 //================================================================================
1672 * \brief Replace elemToRm by elemToAdd in the all groups
1674 //================================================================================
1676 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1677 const vector<const SMDS_MeshElement*>& elemToAdd,
1678 SMESHDS_Mesh * aMesh)
1680 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1681 if (!groups.empty())
1683 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1684 for ( ; grIt != groups.end(); grIt++ ) {
1685 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1686 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1687 for ( int i = 0; i < elemToAdd.size(); ++i )
1688 group->SMDSGroup().Add( elemToAdd[ i ] );
1693 //=======================================================================
1694 //function : QuadToTri
1695 //purpose : Cut quadrangles into triangles.
1696 // theCrit is used to select a diagonal to cut
1697 //=======================================================================
1699 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1700 const bool the13Diag)
1702 myLastCreatedElems.Clear();
1703 myLastCreatedNodes.Clear();
1705 MESSAGE( "::QuadToTri()" );
1707 SMESHDS_Mesh * aMesh = GetMeshDS();
1709 Handle(Geom_Surface) surface;
1710 SMESH_MesherHelper helper( *GetMesh() );
1712 TIDSortedElemSet::iterator itElem;
1713 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1714 const SMDS_MeshElement* elem = *itElem;
1715 if ( !elem || elem->GetType() != SMDSAbs_Face )
1717 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1718 if(!isquad) continue;
1720 if(elem->NbNodes()==4) {
1721 // retrieve element nodes
1722 const SMDS_MeshNode* aNodes [4];
1723 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1725 while ( itN->more() )
1726 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1728 int aShapeId = FindShape( elem );
1729 const SMDS_MeshElement* newElem = 0;
1731 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1732 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1735 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1736 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1738 myLastCreatedElems.Append(newElem);
1739 // put a new triangle on the same shape and add to the same groups
1741 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1742 AddToSameGroups( newElem, elem, aMesh );
1745 // Quadratic quadrangle
1747 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1749 // get surface elem is on
1750 int aShapeId = FindShape( elem );
1751 if ( aShapeId != helper.GetSubShapeID() ) {
1755 shape = aMesh->IndexToShape( aShapeId );
1756 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1757 TopoDS_Face face = TopoDS::Face( shape );
1758 surface = BRep_Tool::Surface( face );
1759 if ( !surface.IsNull() )
1760 helper.SetSubShape( shape );
1764 const SMDS_MeshNode* aNodes [8];
1765 const SMDS_MeshNode* inFaceNode = 0;
1766 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1768 while ( itN->more() ) {
1769 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1770 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1771 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1773 inFaceNode = aNodes[ i-1 ];
1777 // find middle point for (0,1,2,3)
1778 // and create a node in this point;
1780 if ( surface.IsNull() ) {
1782 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1786 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1789 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1791 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1793 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1794 myLastCreatedNodes.Append(newN);
1796 // create a new element
1797 const SMDS_MeshElement* newElem = 0;
1798 const SMDS_MeshNode* N[6];
1806 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1807 aNodes[6], aNodes[7], newN );
1816 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1817 aNodes[7], aNodes[4], newN );
1819 myLastCreatedElems.Append(newElem);
1820 aMesh->ChangeElementNodes( elem, N, 6 );
1821 // put a new triangle on the same shape and add to the same groups
1823 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1824 AddToSameGroups( newElem, elem, aMesh );
1831 //=======================================================================
1832 //function : getAngle
1834 //=======================================================================
1836 double getAngle(const SMDS_MeshElement * tr1,
1837 const SMDS_MeshElement * tr2,
1838 const SMDS_MeshNode * n1,
1839 const SMDS_MeshNode * n2)
1841 double angle = 2*PI; // bad angle
1844 SMESH::Controls::TSequenceOfXYZ P1, P2;
1845 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1846 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1849 if(!tr1->IsQuadratic())
1850 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1852 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1853 if ( N1.SquareMagnitude() <= gp::Resolution() )
1855 if(!tr2->IsQuadratic())
1856 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1858 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1859 if ( N2.SquareMagnitude() <= gp::Resolution() )
1862 // find the first diagonal node n1 in the triangles:
1863 // take in account a diagonal link orientation
1864 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1865 for ( int t = 0; t < 2; t++ ) {
1866 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1867 int i = 0, iDiag = -1;
1868 while ( it->more()) {
1869 const SMDS_MeshElement *n = it->next();
1870 if ( n == n1 || n == n2 )
1874 if ( i - iDiag == 1 )
1875 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1883 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1886 angle = N1.Angle( N2 );
1891 // =================================================
1892 // class generating a unique ID for a pair of nodes
1893 // and able to return nodes by that ID
1894 // =================================================
1898 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1899 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1902 long GetLinkID (const SMDS_MeshNode * n1,
1903 const SMDS_MeshNode * n2) const
1905 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1908 bool GetNodes (const long theLinkID,
1909 const SMDS_MeshNode* & theNode1,
1910 const SMDS_MeshNode* & theNode2) const
1912 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1913 if ( !theNode1 ) return false;
1914 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1915 if ( !theNode2 ) return false;
1921 const SMESHDS_Mesh* myMesh;
1926 //=======================================================================
1927 //function : TriToQuad
1928 //purpose : Fuse neighbour triangles into quadrangles.
1929 // theCrit is used to select a neighbour to fuse with.
1930 // theMaxAngle is a max angle between element normals at which
1931 // fusion is still performed.
1932 //=======================================================================
1934 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1935 SMESH::Controls::NumericalFunctorPtr theCrit,
1936 const double theMaxAngle)
1938 myLastCreatedElems.Clear();
1939 myLastCreatedNodes.Clear();
1941 MESSAGE( "::TriToQuad()" );
1943 if ( !theCrit.get() )
1946 SMESHDS_Mesh * aMesh = GetMeshDS();
1948 // Prepare data for algo: build
1949 // 1. map of elements with their linkIDs
1950 // 2. map of linkIDs with their elements
1952 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1953 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1954 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1955 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1957 TIDSortedElemSet::iterator itElem;
1958 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1959 const SMDS_MeshElement* elem = *itElem;
1960 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1961 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1962 if(!IsTria) continue;
1964 // retrieve element nodes
1965 const SMDS_MeshNode* aNodes [4];
1966 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1969 aNodes[ i++ ] = cast2Node( itN->next() );
1970 aNodes[ 3 ] = aNodes[ 0 ];
1973 for ( i = 0; i < 3; i++ ) {
1974 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1975 // check if elements sharing a link can be fused
1976 itLE = mapLi_listEl.find( link );
1977 if ( itLE != mapLi_listEl.end() ) {
1978 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1980 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1981 //if ( FindShape( elem ) != FindShape( elem2 ))
1982 // continue; // do not fuse triangles laying on different shapes
1983 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1984 continue; // avoid making badly shaped quads
1985 (*itLE).second.push_back( elem );
1988 mapLi_listEl[ link ].push_back( elem );
1990 mapEl_setLi [ elem ].insert( link );
1993 // Clean the maps from the links shared by a sole element, ie
1994 // links to which only one element is bound in mapLi_listEl
1996 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1997 int nbElems = (*itLE).second.size();
1998 if ( nbElems < 2 ) {
1999 const SMDS_MeshElement* elem = (*itLE).second.front();
2000 SMESH_TLink link = (*itLE).first;
2001 mapEl_setLi[ elem ].erase( link );
2002 if ( mapEl_setLi[ elem ].empty() )
2003 mapEl_setLi.erase( elem );
2007 // Algo: fuse triangles into quadrangles
2009 while ( ! mapEl_setLi.empty() ) {
2010 // Look for the start element:
2011 // the element having the least nb of shared links
2012 const SMDS_MeshElement* startElem = 0;
2014 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2015 int nbLinks = (*itEL).second.size();
2016 if ( nbLinks < minNbLinks ) {
2017 startElem = (*itEL).first;
2018 minNbLinks = nbLinks;
2019 if ( minNbLinks == 1 )
2024 // search elements to fuse starting from startElem or links of elements
2025 // fused earlyer - startLinks
2026 list< SMESH_TLink > startLinks;
2027 while ( startElem || !startLinks.empty() ) {
2028 while ( !startElem && !startLinks.empty() ) {
2029 // Get an element to start, by a link
2030 SMESH_TLink linkId = startLinks.front();
2031 startLinks.pop_front();
2032 itLE = mapLi_listEl.find( linkId );
2033 if ( itLE != mapLi_listEl.end() ) {
2034 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2035 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2036 for ( ; itE != listElem.end() ; itE++ )
2037 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2039 mapLi_listEl.erase( itLE );
2044 // Get candidates to be fused
2045 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2046 const SMESH_TLink *link12, *link13;
2048 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2049 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2050 ASSERT( !setLi.empty() );
2051 set< SMESH_TLink >::iterator itLi;
2052 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2054 const SMESH_TLink & link = (*itLi);
2055 itLE = mapLi_listEl.find( link );
2056 if ( itLE == mapLi_listEl.end() )
2059 const SMDS_MeshElement* elem = (*itLE).second.front();
2061 elem = (*itLE).second.back();
2062 mapLi_listEl.erase( itLE );
2063 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2074 // add other links of elem to list of links to re-start from
2075 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2076 set< SMESH_TLink >::iterator it;
2077 for ( it = links.begin(); it != links.end(); it++ ) {
2078 const SMESH_TLink& link2 = (*it);
2079 if ( link2 != link )
2080 startLinks.push_back( link2 );
2084 // Get nodes of possible quadrangles
2085 const SMDS_MeshNode *n12 [4], *n13 [4];
2086 bool Ok12 = false, Ok13 = false;
2087 const SMDS_MeshNode *linkNode1, *linkNode2;
2089 linkNode1 = link12->first;
2090 linkNode2 = link12->second;
2091 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2095 linkNode1 = link13->first;
2096 linkNode2 = link13->second;
2097 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2101 // Choose a pair to fuse
2102 if ( Ok12 && Ok13 ) {
2103 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2104 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2105 double aBadRate12 = getBadRate( &quad12, theCrit );
2106 double aBadRate13 = getBadRate( &quad13, theCrit );
2107 if ( aBadRate13 < aBadRate12 )
2114 // and remove fused elems and removed links from the maps
2115 mapEl_setLi.erase( tr1 );
2117 mapEl_setLi.erase( tr2 );
2118 mapLi_listEl.erase( *link12 );
2119 if(tr1->NbNodes()==3) {
2120 if( tr1->GetID() < tr2->GetID() ) {
2121 aMesh->ChangeElementNodes( tr1, n12, 4 );
2122 myLastCreatedElems.Append(tr1);
2123 aMesh->RemoveElement( tr2 );
2126 aMesh->ChangeElementNodes( tr2, n12, 4 );
2127 myLastCreatedElems.Append(tr2);
2128 aMesh->RemoveElement( tr1);
2132 const SMDS_MeshNode* N1 [6];
2133 const SMDS_MeshNode* N2 [6];
2134 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2135 // now we receive following N1 and N2 (using numeration as above image)
2136 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2137 // i.e. first nodes from both arrays determ new diagonal
2138 const SMDS_MeshNode* aNodes[8];
2147 if( tr1->GetID() < tr2->GetID() ) {
2148 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2149 myLastCreatedElems.Append(tr1);
2150 GetMeshDS()->RemoveElement( tr2 );
2153 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2154 myLastCreatedElems.Append(tr2);
2155 GetMeshDS()->RemoveElement( tr1 );
2157 // remove middle node (9)
2158 GetMeshDS()->RemoveNode( N1[4] );
2162 mapEl_setLi.erase( tr3 );
2163 mapLi_listEl.erase( *link13 );
2164 if(tr1->NbNodes()==3) {
2165 if( tr1->GetID() < tr2->GetID() ) {
2166 aMesh->ChangeElementNodes( tr1, n13, 4 );
2167 myLastCreatedElems.Append(tr1);
2168 aMesh->RemoveElement( tr3 );
2171 aMesh->ChangeElementNodes( tr3, n13, 4 );
2172 myLastCreatedElems.Append(tr3);
2173 aMesh->RemoveElement( tr1 );
2177 const SMDS_MeshNode* N1 [6];
2178 const SMDS_MeshNode* N2 [6];
2179 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2180 // now we receive following N1 and N2 (using numeration as above image)
2181 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2182 // i.e. first nodes from both arrays determ new diagonal
2183 const SMDS_MeshNode* aNodes[8];
2192 if( tr1->GetID() < tr2->GetID() ) {
2193 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2194 myLastCreatedElems.Append(tr1);
2195 GetMeshDS()->RemoveElement( tr3 );
2198 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2199 myLastCreatedElems.Append(tr3);
2200 GetMeshDS()->RemoveElement( tr1 );
2202 // remove middle node (9)
2203 GetMeshDS()->RemoveNode( N1[4] );
2207 // Next element to fuse: the rejected one
2209 startElem = Ok12 ? tr3 : tr2;
2211 } // if ( startElem )
2212 } // while ( startElem || !startLinks.empty() )
2213 } // while ( ! mapEl_setLi.empty() )
2219 /*#define DUMPSO(txt) \
2220 // cout << txt << endl;
2221 //=============================================================================
2225 //=============================================================================
2226 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2230 int tmp = idNodes[ i1 ];
2231 idNodes[ i1 ] = idNodes[ i2 ];
2232 idNodes[ i2 ] = tmp;
2233 gp_Pnt Ptmp = P[ i1 ];
2236 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2239 //=======================================================================
2240 //function : SortQuadNodes
2241 //purpose : Set 4 nodes of a quadrangle face in a good order.
2242 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2244 //=======================================================================
2246 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2251 for ( i = 0; i < 4; i++ ) {
2252 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2254 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2257 gp_Vec V1(P[0], P[1]);
2258 gp_Vec V2(P[0], P[2]);
2259 gp_Vec V3(P[0], P[3]);
2261 gp_Vec Cross1 = V1 ^ V2;
2262 gp_Vec Cross2 = V2 ^ V3;
2265 if (Cross1.Dot(Cross2) < 0)
2270 if (Cross1.Dot(Cross2) < 0)
2274 swap ( i, i + 1, idNodes, P );
2276 // for ( int ii = 0; ii < 4; ii++ ) {
2277 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2278 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2284 //=======================================================================
2285 //function : SortHexaNodes
2286 //purpose : Set 8 nodes of a hexahedron in a good order.
2287 // Return success status
2288 //=======================================================================
2290 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2295 DUMPSO( "INPUT: ========================================");
2296 for ( i = 0; i < 8; i++ ) {
2297 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2298 if ( !n ) return false;
2299 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2300 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2302 DUMPSO( "========================================");
2305 set<int> faceNodes; // ids of bottom face nodes, to be found
2306 set<int> checkedId1; // ids of tried 2-nd nodes
2307 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2308 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2309 int iMin, iLoop1 = 0;
2311 // Loop to try the 2-nd nodes
2313 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2315 // Find not checked 2-nd node
2316 for ( i = 1; i < 8; i++ )
2317 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2318 int id1 = idNodes[i];
2319 swap ( 1, i, idNodes, P );
2320 checkedId1.insert ( id1 );
2324 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2325 // ie that all but meybe one (id3 which is on the same face) nodes
2326 // lay on the same side from the triangle plane.
2328 bool manyInPlane = false; // more than 4 nodes lay in plane
2330 while ( ++iLoop2 < 6 ) {
2332 // get 1-2-3 plane coeffs
2333 Standard_Real A, B, C, D;
2334 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2335 if ( N.SquareMagnitude() > gp::Resolution() )
2337 gp_Pln pln ( P[0], N );
2338 pln.Coefficients( A, B, C, D );
2340 // find the node (iMin) closest to pln
2341 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2343 for ( i = 3; i < 8; i++ ) {
2344 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2345 if ( fabs( dist[i] ) < minDist ) {
2346 minDist = fabs( dist[i] );
2349 if ( fabs( dist[i] ) <= tol )
2350 idInPln.insert( idNodes[i] );
2353 // there should not be more than 4 nodes in bottom plane
2354 if ( idInPln.size() > 1 )
2356 DUMPSO( "### idInPln.size() = " << idInPln.size());
2357 // idInPlane does not contain the first 3 nodes
2358 if ( manyInPlane || idInPln.size() == 5)
2359 return false; // all nodes in one plane
2362 // set the 1-st node to be not in plane
2363 for ( i = 3; i < 8; i++ ) {
2364 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2365 DUMPSO( "### Reset 0-th node");
2366 swap( 0, i, idNodes, P );
2371 // reset to re-check second nodes
2372 leastDist = DBL_MAX;
2376 break; // from iLoop2;
2379 // check that the other 4 nodes are on the same side
2380 bool sameSide = true;
2381 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2382 for ( i = 3; sameSide && i < 8; i++ ) {
2384 sameSide = ( isNeg == dist[i] <= 0.);
2387 // keep best solution
2388 if ( sameSide && minDist < leastDist ) {
2389 leastDist = minDist;
2391 faceNodes.insert( idNodes[ 1 ] );
2392 faceNodes.insert( idNodes[ 2 ] );
2393 faceNodes.insert( idNodes[ iMin ] );
2394 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2395 << " leastDist = " << leastDist);
2396 if ( leastDist <= DBL_MIN )
2401 // set next 3-d node to check
2402 int iNext = 2 + iLoop2;
2404 DUMPSO( "Try 2-nd");
2405 swap ( 2, iNext, idNodes, P );
2407 } // while ( iLoop2 < 6 )
2410 if ( faceNodes.empty() ) return false;
2412 // Put the faceNodes in proper places
2413 for ( i = 4; i < 8; i++ ) {
2414 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2415 // find a place to put
2417 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2419 DUMPSO( "Set faceNodes");
2420 swap ( iTo, i, idNodes, P );
2425 // Set nodes of the found bottom face in good order
2426 DUMPSO( " Found bottom face: ");
2427 i = SortQuadNodes( theMesh, idNodes );
2429 gp_Pnt Ptmp = P[ i ];
2434 // for ( int ii = 0; ii < 4; ii++ ) {
2435 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2436 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2439 // Gravity center of the top and bottom faces
2440 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2441 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2443 // Get direction from the bottom to the top face
2444 gp_Vec upDir ( aGCb, aGCt );
2445 Standard_Real upDirSize = upDir.Magnitude();
2446 if ( upDirSize <= gp::Resolution() ) return false;
2449 // Assure that the bottom face normal points up
2450 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2451 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2452 if ( Nb.Dot( upDir ) < 0 ) {
2453 DUMPSO( "Reverse bottom face");
2454 swap( 1, 3, idNodes, P );
2457 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2458 Standard_Real minDist = DBL_MAX;
2459 for ( i = 4; i < 8; i++ ) {
2460 // projection of P[i] to the plane defined by P[0] and upDir
2461 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2462 Standard_Real sqDist = P[0].SquareDistance( Pp );
2463 if ( sqDist < minDist ) {
2468 DUMPSO( "Set 4-th");
2469 swap ( 4, iMin, idNodes, P );
2471 // Set nodes of the top face in good order
2472 DUMPSO( "Sort top face");
2473 i = SortQuadNodes( theMesh, &idNodes[4] );
2476 gp_Pnt Ptmp = P[ i ];
2481 // Assure that direction of the top face normal is from the bottom face
2482 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2483 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2484 if ( Nt.Dot( upDir ) < 0 ) {
2485 DUMPSO( "Reverse top face");
2486 swap( 5, 7, idNodes, P );
2489 // DUMPSO( "OUTPUT: ========================================");
2490 // for ( i = 0; i < 8; i++ ) {
2491 // float *p = ugrid->GetPoint(idNodes[i]);
2492 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2498 //================================================================================
2500 * \brief Return nodes linked to the given one
2501 * \param theNode - the node
2502 * \param linkedNodes - the found nodes
2503 * \param type - the type of elements to check
2505 * Medium nodes are ignored
2507 //================================================================================
2509 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2510 TIDSortedElemSet & linkedNodes,
2511 SMDSAbs_ElementType type )
2513 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2514 while ( elemIt->more() )
2516 const SMDS_MeshElement* elem = elemIt->next();
2517 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2518 if ( elem->GetType() == SMDSAbs_Volume )
2520 SMDS_VolumeTool vol( elem );
2521 while ( nodeIt->more() ) {
2522 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2523 if ( theNode != n && vol.IsLinked( theNode, n ))
2524 linkedNodes.insert( n );
2529 for ( int i = 0; nodeIt->more(); ++i ) {
2530 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2531 if ( n == theNode ) {
2532 int iBefore = i - 1;
2534 if ( elem->IsQuadratic() ) {
2535 int nb = elem->NbNodes() / 2;
2536 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2537 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2539 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2540 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2547 //=======================================================================
2548 //function : laplacianSmooth
2549 //purpose : pulls theNode toward the center of surrounding nodes directly
2550 // connected to that node along an element edge
2551 //=======================================================================
2553 void laplacianSmooth(const SMDS_MeshNode* theNode,
2554 const Handle(Geom_Surface)& theSurface,
2555 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2557 // find surrounding nodes
2559 TIDSortedElemSet nodeSet;
2560 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2562 // compute new coodrs
2564 double coord[] = { 0., 0., 0. };
2565 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2566 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2567 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2568 if ( theSurface.IsNull() ) { // smooth in 3D
2569 coord[0] += node->X();
2570 coord[1] += node->Y();
2571 coord[2] += node->Z();
2573 else { // smooth in 2D
2574 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2575 gp_XY* uv = theUVMap[ node ];
2576 coord[0] += uv->X();
2577 coord[1] += uv->Y();
2580 int nbNodes = nodeSet.size();
2583 coord[0] /= nbNodes;
2584 coord[1] /= nbNodes;
2586 if ( !theSurface.IsNull() ) {
2587 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2588 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2589 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2595 coord[2] /= nbNodes;
2599 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2602 //=======================================================================
2603 //function : centroidalSmooth
2604 //purpose : pulls theNode toward the element-area-weighted centroid of the
2605 // surrounding elements
2606 //=======================================================================
2608 void centroidalSmooth(const SMDS_MeshNode* theNode,
2609 const Handle(Geom_Surface)& theSurface,
2610 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2612 gp_XYZ aNewXYZ(0.,0.,0.);
2613 SMESH::Controls::Area anAreaFunc;
2614 double totalArea = 0.;
2619 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2620 while ( elemIt->more() )
2622 const SMDS_MeshElement* elem = elemIt->next();
2625 gp_XYZ elemCenter(0.,0.,0.);
2626 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2627 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2628 int nn = elem->NbNodes();
2629 if(elem->IsQuadratic()) nn = nn/2;
2631 //while ( itN->more() ) {
2633 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2635 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2636 aNodePoints.push_back( aP );
2637 if ( !theSurface.IsNull() ) { // smooth in 2D
2638 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2639 gp_XY* uv = theUVMap[ aNode ];
2640 aP.SetCoord( uv->X(), uv->Y(), 0. );
2644 double elemArea = anAreaFunc.GetValue( aNodePoints );
2645 totalArea += elemArea;
2647 aNewXYZ += elemCenter * elemArea;
2649 aNewXYZ /= totalArea;
2650 if ( !theSurface.IsNull() ) {
2651 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2652 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2657 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2660 //=======================================================================
2661 //function : getClosestUV
2662 //purpose : return UV of closest projection
2663 //=======================================================================
2665 static bool getClosestUV (Extrema_GenExtPS& projector,
2666 const gp_Pnt& point,
2669 projector.Perform( point );
2670 if ( projector.IsDone() ) {
2671 double u, v, minVal = DBL_MAX;
2672 for ( int i = projector.NbExt(); i > 0; i-- )
2673 if ( projector.Value( i ) < minVal ) {
2674 minVal = projector.Value( i );
2675 projector.Point( i ).Parameter( u, v );
2677 result.SetCoord( u, v );
2683 //=======================================================================
2685 //purpose : Smooth theElements during theNbIterations or until a worst
2686 // element has aspect ratio <= theTgtAspectRatio.
2687 // Aspect Ratio varies in range [1.0, inf].
2688 // If theElements is empty, the whole mesh is smoothed.
2689 // theFixedNodes contains additionally fixed nodes. Nodes built
2690 // on edges and boundary nodes are always fixed.
2691 //=======================================================================
2693 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2694 set<const SMDS_MeshNode*> & theFixedNodes,
2695 const SmoothMethod theSmoothMethod,
2696 const int theNbIterations,
2697 double theTgtAspectRatio,
2700 myLastCreatedElems.Clear();
2701 myLastCreatedNodes.Clear();
2703 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2705 if ( theTgtAspectRatio < 1.0 )
2706 theTgtAspectRatio = 1.0;
2708 const double disttol = 1.e-16;
2710 SMESH::Controls::AspectRatio aQualityFunc;
2712 SMESHDS_Mesh* aMesh = GetMeshDS();
2714 if ( theElems.empty() ) {
2715 // add all faces to theElems
2716 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2717 while ( fIt->more() ) {
2718 const SMDS_MeshElement* face = fIt->next();
2719 theElems.insert( face );
2722 // get all face ids theElems are on
2723 set< int > faceIdSet;
2724 TIDSortedElemSet::iterator itElem;
2726 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2727 int fId = FindShape( *itElem );
2728 // check that corresponding submesh exists and a shape is face
2730 faceIdSet.find( fId ) == faceIdSet.end() &&
2731 aMesh->MeshElements( fId )) {
2732 TopoDS_Shape F = aMesh->IndexToShape( fId );
2733 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2734 faceIdSet.insert( fId );
2737 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2739 // ===============================================
2740 // smooth elements on each TopoDS_Face separately
2741 // ===============================================
2743 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2744 for ( ; fId != faceIdSet.rend(); ++fId ) {
2745 // get face surface and submesh
2746 Handle(Geom_Surface) surface;
2747 SMESHDS_SubMesh* faceSubMesh = 0;
2749 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2750 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2751 bool isUPeriodic = false, isVPeriodic = false;
2753 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2754 surface = BRep_Tool::Surface( face );
2755 faceSubMesh = aMesh->MeshElements( *fId );
2756 fToler2 = BRep_Tool::Tolerance( face );
2757 fToler2 *= fToler2 * 10.;
2758 isUPeriodic = surface->IsUPeriodic();
2760 vPeriod = surface->UPeriod();
2761 isVPeriodic = surface->IsVPeriodic();
2763 uPeriod = surface->VPeriod();
2764 surface->Bounds( u1, u2, v1, v2 );
2766 // ---------------------------------------------------------
2767 // for elements on a face, find movable and fixed nodes and
2768 // compute UV for them
2769 // ---------------------------------------------------------
2770 bool checkBoundaryNodes = false;
2771 bool isQuadratic = false;
2772 set<const SMDS_MeshNode*> setMovableNodes;
2773 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2774 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2775 list< const SMDS_MeshElement* > elemsOnFace;
2777 Extrema_GenExtPS projector;
2778 GeomAdaptor_Surface surfAdaptor;
2779 if ( !surface.IsNull() ) {
2780 surfAdaptor.Load( surface );
2781 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2783 int nbElemOnFace = 0;
2784 itElem = theElems.begin();
2785 // loop on not yet smoothed elements: look for elems on a face
2786 while ( itElem != theElems.end() ) {
2787 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2788 break; // all elements found
2790 const SMDS_MeshElement* elem = *itElem;
2791 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2792 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2796 elemsOnFace.push_back( elem );
2797 theElems.erase( itElem++ );
2801 isQuadratic = elem->IsQuadratic();
2803 // get movable nodes of elem
2804 const SMDS_MeshNode* node;
2805 SMDS_TypeOfPosition posType;
2806 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2807 int nn = 0, nbn = elem->NbNodes();
2808 if(elem->IsQuadratic())
2810 while ( nn++ < nbn ) {
2811 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2812 const SMDS_PositionPtr& pos = node->GetPosition();
2813 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2814 if (posType != SMDS_TOP_EDGE &&
2815 posType != SMDS_TOP_VERTEX &&
2816 theFixedNodes.find( node ) == theFixedNodes.end())
2818 // check if all faces around the node are on faceSubMesh
2819 // because a node on edge may be bound to face
2820 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2822 if ( faceSubMesh ) {
2823 while ( eIt->more() && all ) {
2824 const SMDS_MeshElement* e = eIt->next();
2825 all = faceSubMesh->Contains( e );
2829 setMovableNodes.insert( node );
2831 checkBoundaryNodes = true;
2833 if ( posType == SMDS_TOP_3DSPACE )
2834 checkBoundaryNodes = true;
2837 if ( surface.IsNull() )
2840 // get nodes to check UV
2841 list< const SMDS_MeshNode* > uvCheckNodes;
2842 itN = elem->nodesIterator();
2843 nn = 0; nbn = elem->NbNodes();
2844 if(elem->IsQuadratic())
2846 while ( nn++ < nbn ) {
2847 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2848 if ( uvMap.find( node ) == uvMap.end() )
2849 uvCheckNodes.push_back( node );
2850 // add nodes of elems sharing node
2851 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2852 // while ( eIt->more() ) {
2853 // const SMDS_MeshElement* e = eIt->next();
2854 // if ( e != elem ) {
2855 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2856 // while ( nIt->more() ) {
2857 // const SMDS_MeshNode* n =
2858 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2859 // if ( uvMap.find( n ) == uvMap.end() )
2860 // uvCheckNodes.push_back( n );
2866 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2867 for ( ; n != uvCheckNodes.end(); ++n ) {
2870 const SMDS_PositionPtr& pos = node->GetPosition();
2871 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2873 switch ( posType ) {
2874 case SMDS_TOP_FACE: {
2875 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2876 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2879 case SMDS_TOP_EDGE: {
2880 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2881 Handle(Geom2d_Curve) pcurve;
2882 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2883 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2884 if ( !pcurve.IsNull() ) {
2885 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2886 uv = pcurve->Value( u ).XY();
2890 case SMDS_TOP_VERTEX: {
2891 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2892 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2893 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2898 // check existing UV
2899 bool project = true;
2900 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2901 double dist1 = DBL_MAX, dist2 = 0;
2902 if ( posType != SMDS_TOP_3DSPACE ) {
2903 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2904 project = dist1 > fToler2;
2906 if ( project ) { // compute new UV
2908 if ( !getClosestUV( projector, pNode, newUV )) {
2909 MESSAGE("Node Projection Failed " << node);
2913 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2915 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2917 if ( posType != SMDS_TOP_3DSPACE )
2918 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2919 if ( dist2 < dist1 )
2923 // store UV in the map
2924 listUV.push_back( uv );
2925 uvMap.insert( make_pair( node, &listUV.back() ));
2927 } // loop on not yet smoothed elements
2929 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2930 checkBoundaryNodes = true;
2932 // fix nodes on mesh boundary
2934 if ( checkBoundaryNodes ) {
2935 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2936 map< NLink, int >::iterator link_nb;
2937 // put all elements links to linkNbMap
2938 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2939 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2940 const SMDS_MeshElement* elem = (*elemIt);
2941 int nbn = elem->NbNodes();
2942 if(elem->IsQuadratic())
2944 // loop on elem links: insert them in linkNbMap
2945 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2946 for ( int iN = 0; iN < nbn; ++iN ) {
2947 curNode = elem->GetNode( iN );
2949 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2950 else link = make_pair( prevNode , curNode );
2952 link_nb = linkNbMap.find( link );
2953 if ( link_nb == linkNbMap.end() )
2954 linkNbMap.insert( make_pair ( link, 1 ));
2959 // remove nodes that are in links encountered only once from setMovableNodes
2960 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2961 if ( link_nb->second == 1 ) {
2962 setMovableNodes.erase( link_nb->first.first );
2963 setMovableNodes.erase( link_nb->first.second );
2968 // -----------------------------------------------------
2969 // for nodes on seam edge, compute one more UV ( uvMap2 );
2970 // find movable nodes linked to nodes on seam and which
2971 // are to be smoothed using the second UV ( uvMap2 )
2972 // -----------------------------------------------------
2974 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2975 if ( !surface.IsNull() ) {
2976 TopExp_Explorer eExp( face, TopAbs_EDGE );
2977 for ( ; eExp.More(); eExp.Next() ) {
2978 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2979 if ( !BRep_Tool::IsClosed( edge, face ))
2981 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2982 if ( !sm ) continue;
2983 // find out which parameter varies for a node on seam
2986 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2987 if ( pcurve.IsNull() ) continue;
2988 uv1 = pcurve->Value( f );
2990 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2991 if ( pcurve.IsNull() ) continue;
2992 uv2 = pcurve->Value( f );
2993 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2995 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2996 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2998 // get nodes on seam and its vertices
2999 list< const SMDS_MeshNode* > seamNodes;
3000 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3001 while ( nSeamIt->more() ) {
3002 const SMDS_MeshNode* node = nSeamIt->next();
3003 if ( !isQuadratic || !IsMedium( node ))
3004 seamNodes.push_back( node );
3006 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3007 for ( ; vExp.More(); vExp.Next() ) {
3008 sm = aMesh->MeshElements( vExp.Current() );
3010 nSeamIt = sm->GetNodes();
3011 while ( nSeamIt->more() )
3012 seamNodes.push_back( nSeamIt->next() );
3015 // loop on nodes on seam
3016 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3017 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3018 const SMDS_MeshNode* nSeam = *noSeIt;
3019 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3020 if ( n_uv == uvMap.end() )
3023 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3024 // set the second UV
3025 listUV.push_back( *n_uv->second );
3026 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3027 if ( uvMap2.empty() )
3028 uvMap2 = uvMap; // copy the uvMap contents
3029 uvMap2[ nSeam ] = &listUV.back();
3031 // collect movable nodes linked to ones on seam in nodesNearSeam
3032 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3033 while ( eIt->more() ) {
3034 const SMDS_MeshElement* e = eIt->next();
3035 int nbUseMap1 = 0, nbUseMap2 = 0;
3036 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3037 int nn = 0, nbn = e->NbNodes();
3038 if(e->IsQuadratic()) nbn = nbn/2;
3039 while ( nn++ < nbn )
3041 const SMDS_MeshNode* n =
3042 static_cast<const SMDS_MeshNode*>( nIt->next() );
3044 setMovableNodes.find( n ) == setMovableNodes.end() )
3046 // add only nodes being closer to uv2 than to uv1
3047 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3048 0.5 * ( n->Y() + nSeam->Y() ),
3049 0.5 * ( n->Z() + nSeam->Z() ));
3051 getClosestUV( projector, pMid, uv );
3052 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3053 nodesNearSeam.insert( n );
3059 // for centroidalSmooth all element nodes must
3060 // be on one side of a seam
3061 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3062 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3064 while ( nn++ < nbn ) {
3065 const SMDS_MeshNode* n =
3066 static_cast<const SMDS_MeshNode*>( nIt->next() );
3067 setMovableNodes.erase( n );
3071 } // loop on nodes on seam
3072 } // loop on edge of a face
3073 } // if ( !face.IsNull() )
3075 if ( setMovableNodes.empty() ) {
3076 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3077 continue; // goto next face
3085 double maxRatio = -1., maxDisplacement = -1.;
3086 set<const SMDS_MeshNode*>::iterator nodeToMove;
3087 for ( it = 0; it < theNbIterations; it++ ) {
3088 maxDisplacement = 0.;
3089 nodeToMove = setMovableNodes.begin();
3090 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3091 const SMDS_MeshNode* node = (*nodeToMove);
3092 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3095 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3096 if ( theSmoothMethod == LAPLACIAN )
3097 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3099 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3101 // node displacement
3102 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3103 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3104 if ( aDispl > maxDisplacement )
3105 maxDisplacement = aDispl;
3107 // no node movement => exit
3108 //if ( maxDisplacement < 1.e-16 ) {
3109 if ( maxDisplacement < disttol ) {
3110 MESSAGE("-- no node movement --");
3114 // check elements quality
3116 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3117 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3118 const SMDS_MeshElement* elem = (*elemIt);
3119 if ( !elem || elem->GetType() != SMDSAbs_Face )
3121 SMESH::Controls::TSequenceOfXYZ aPoints;
3122 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3123 double aValue = aQualityFunc.GetValue( aPoints );
3124 if ( aValue > maxRatio )
3128 if ( maxRatio <= theTgtAspectRatio ) {
3129 MESSAGE("-- quality achived --");
3132 if (it+1 == theNbIterations) {
3133 MESSAGE("-- Iteration limit exceeded --");
3135 } // smoothing iterations
3137 MESSAGE(" Face id: " << *fId <<
3138 " Nb iterstions: " << it <<
3139 " Displacement: " << maxDisplacement <<
3140 " Aspect Ratio " << maxRatio);
3142 // ---------------------------------------
3143 // new nodes positions are computed,
3144 // record movement in DS and set new UV
3145 // ---------------------------------------
3146 nodeToMove = setMovableNodes.begin();
3147 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3148 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3149 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3150 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3151 if ( node_uv != uvMap.end() ) {
3152 gp_XY* uv = node_uv->second;
3154 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3158 // move medium nodes of quadratic elements
3161 SMESH_MesherHelper helper( *GetMesh() );
3162 if ( !face.IsNull() )
3163 helper.SetSubShape( face );
3164 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3165 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3166 const SMDS_QuadraticFaceOfNodes* QF =
3167 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3169 vector<const SMDS_MeshNode*> Ns;
3170 Ns.reserve(QF->NbNodes()+1);
3171 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3172 while ( anIter->more() )
3173 Ns.push_back( anIter->next() );
3174 Ns.push_back( Ns[0] );
3176 for(int i=0; i<QF->NbNodes(); i=i+2) {
3177 if ( !surface.IsNull() ) {
3178 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3179 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3180 gp_XY uv = ( uv1 + uv2 ) / 2.;
3181 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3182 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3185 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3186 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3187 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3189 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3190 fabs( Ns[i+1]->Y() - y ) > disttol ||
3191 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3192 // we have to move i+1 node
3193 aMesh->MoveNode( Ns[i+1], x, y, z );
3200 } // loop on face ids
3204 //=======================================================================
3205 //function : isReverse
3206 //purpose : Return true if normal of prevNodes is not co-directied with
3207 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3208 // iNotSame is where prevNodes and nextNodes are different
3209 //=======================================================================
3211 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3212 vector<const SMDS_MeshNode*> nextNodes,
3216 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3217 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3219 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3220 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3221 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3222 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3224 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3225 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3226 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3227 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3229 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3231 return (vA ^ vB) * vN < 0.0;
3234 //=======================================================================
3236 * \brief Create elements by sweeping an element
3237 * \param elem - element to sweep
3238 * \param newNodesItVec - nodes generated from each node of the element
3239 * \param newElems - generated elements
3240 * \param nbSteps - number of sweeping steps
3241 * \param srcElements - to append elem for each generated element
3243 //=======================================================================
3245 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3246 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3247 list<const SMDS_MeshElement*>& newElems,
3249 SMESH_SequenceOfElemPtr& srcElements)
3251 SMESHDS_Mesh* aMesh = GetMeshDS();
3253 // Loop on elem nodes:
3254 // find new nodes and detect same nodes indices
3255 int nbNodes = elem->NbNodes();
3256 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3257 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3258 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3259 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3261 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3262 vector<int> sames(nbNodes);
3263 vector<bool> issimple(nbNodes);
3265 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3266 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3267 const SMDS_MeshNode* node = nnIt->first;
3268 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3269 if ( listNewNodes.empty() ) {
3273 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3275 itNN[ iNode ] = listNewNodes.begin();
3276 prevNod[ iNode ] = node;
3277 nextNod[ iNode ] = listNewNodes.front();
3278 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3279 if ( prevNod[ iNode ] != nextNod [ iNode ])
3280 iNotSameNode = iNode;
3284 sames[nbSame++] = iNode;
3289 //cout<<" nbSame = "<<nbSame<<endl;
3290 if ( nbSame == nbNodes || nbSame > 2) {
3291 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3292 //INFOS( " Too many same nodes of element " << elem->GetID() );
3296 // if( elem->IsQuadratic() && nbSame>0 ) {
3297 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3301 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3302 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3304 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3305 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3306 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3310 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3311 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3312 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3313 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3315 // check element orientation
3317 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3318 //MESSAGE("Reversed elem " << elem );
3322 std::swap( iBeforeSame, iAfterSame );
3325 // make new elements
3326 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3328 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3329 if(issimple[iNode]) {
3330 nextNod[ iNode ] = *itNN[ iNode ];
3334 if( elem->GetType()==SMDSAbs_Node ) {
3335 // we have to use two nodes
3336 midlNod[ iNode ] = *itNN[ iNode ];
3338 nextNod[ iNode ] = *itNN[ iNode ];
3341 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3342 // we have to use each second node
3344 nextNod[ iNode ] = *itNN[ iNode ];
3348 // we have to use two nodes
3349 midlNod[ iNode ] = *itNN[ iNode ];
3351 nextNod[ iNode ] = *itNN[ iNode ];
3356 SMDS_MeshElement* aNewElem = 0;
3357 if(!elem->IsPoly()) {
3358 switch ( nbNodes ) {
3362 if ( nbSame == 0 ) {
3364 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3366 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3372 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3373 nextNod[ 1 ], nextNod[ 0 ] );
3375 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3376 nextNod[ iNotSameNode ] );
3380 case 3: { // TRIANGLE or quadratic edge
3381 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3383 if ( nbSame == 0 ) // --- pentahedron
3384 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3385 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3387 else if ( nbSame == 1 ) // --- pyramid
3388 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3389 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3390 nextNod[ iSameNode ]);
3392 else // 2 same nodes: --- tetrahedron
3393 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3394 nextNod[ iNotSameNode ]);
3396 else { // quadratic edge
3397 if(nbSame==0) { // quadratic quadrangle
3398 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3399 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3401 else if(nbSame==1) { // quadratic triangle
3403 return; // medium node on axis
3405 else if(sames[0]==0) {
3406 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3407 nextNod[2], midlNod[1], prevNod[2]);
3409 else { // sames[0]==1
3410 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3411 midlNod[0], nextNod[2], prevNod[2]);
3420 case 4: { // QUADRANGLE
3422 if ( nbSame == 0 ) // --- hexahedron
3423 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3424 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3426 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3427 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3428 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3429 nextNod[ iSameNode ]);
3430 newElems.push_back( aNewElem );
3431 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3432 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3433 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3435 else if ( nbSame == 2 ) { // pentahedron
3436 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3437 // iBeforeSame is same too
3438 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3439 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3440 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3442 // iAfterSame is same too
3443 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3444 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3445 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3449 case 6: { // quadratic triangle
3450 // create pentahedron with 15 nodes
3452 if(i0>0) { // reversed case
3453 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3454 nextNod[0], nextNod[2], nextNod[1],
3455 prevNod[5], prevNod[4], prevNod[3],
3456 nextNod[5], nextNod[4], nextNod[3],
3457 midlNod[0], midlNod[2], midlNod[1]);
3459 else { // not reversed case
3460 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3461 nextNod[0], nextNod[1], nextNod[2],
3462 prevNod[3], prevNod[4], prevNod[5],
3463 nextNod[3], nextNod[4], nextNod[5],
3464 midlNod[0], midlNod[1], midlNod[2]);
3467 else if(nbSame==1) {
3468 // 2d order pyramid of 13 nodes
3469 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3470 // int n12,int n23,int n34,int n41,
3471 // int n15,int n25,int n35,int n45, int ID);
3473 int n1,n4,n41,n15,n45;
3474 if(i0>0) { // reversed case
3475 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3476 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3482 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3483 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3488 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3489 nextNod[n4], prevNod[n4], prevNod[n5],
3490 midlNod[n1], nextNod[n41],
3491 midlNod[n4], prevNod[n41],
3492 prevNod[n15], nextNod[n15],
3493 nextNod[n45], prevNod[n45]);
3495 else if(nbSame==2) {
3496 // 2d order tetrahedron of 10 nodes
3497 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3498 // int n12,int n23,int n31,
3499 // int n14,int n24,int n34, int ID);
3500 int n1 = iNotSameNode;
3501 int n2,n3,n12,n23,n31;
3502 if(i0>0) { // reversed case
3503 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3504 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3510 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3511 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3516 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3517 prevNod[n12], prevNod[n23], prevNod[n31],
3518 midlNod[n1], nextNod[n12], nextNod[n31]);
3522 case 8: { // quadratic quadrangle
3524 // create hexahedron with 20 nodes
3525 if(i0>0) { // reversed case
3526 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3527 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3528 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3529 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3530 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3532 else { // not reversed case
3533 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3534 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3535 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3536 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3537 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3540 else if(nbSame==1) {
3541 // --- pyramid + pentahedron - can not be created since it is needed
3542 // additional middle node ot the center of face
3543 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3546 else if(nbSame==2) {
3547 // 2d order Pentahedron with 15 nodes
3548 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3549 // int n12,int n23,int n31,int n45,int n56,int n64,
3550 // int n14,int n25,int n36, int ID);
3552 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3553 // iBeforeSame is same too
3560 // iAfterSame is same too
3566 int n12,n45,n14,n25;
3567 if(i0>0) { //reversed case
3579 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3580 prevNod[n4], prevNod[n5], nextNod[n5],
3581 prevNod[n12], midlNod[n2], nextNod[n12],
3582 prevNod[n45], midlNod[n5], nextNod[n45],
3583 prevNod[n14], prevNod[n25], nextNod[n25]);
3588 // realized for extrusion only
3589 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3590 //vector<int> quantities (nbNodes + 2);
3592 //quantities[0] = nbNodes; // bottom of prism
3593 //for (int inode = 0; inode < nbNodes; inode++) {
3594 // polyedre_nodes[inode] = prevNod[inode];
3597 //quantities[1] = nbNodes; // top of prism
3598 //for (int inode = 0; inode < nbNodes; inode++) {
3599 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3602 //for (int iface = 0; iface < nbNodes; iface++) {
3603 // quantities[iface + 2] = 4;
3604 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3605 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3606 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3607 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3608 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3610 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3617 // realized for extrusion only
3618 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3619 vector<int> quantities (nbNodes + 2);
3621 quantities[0] = nbNodes; // bottom of prism
3622 for (int inode = 0; inode < nbNodes; inode++) {
3623 polyedre_nodes[inode] = prevNod[inode];
3626 quantities[1] = nbNodes; // top of prism
3627 for (int inode = 0; inode < nbNodes; inode++) {
3628 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3631 for (int iface = 0; iface < nbNodes; iface++) {
3632 quantities[iface + 2] = 4;
3633 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3634 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3635 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3636 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3637 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3639 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3643 newElems.push_back( aNewElem );
3644 myLastCreatedElems.Append(aNewElem);
3645 srcElements.Append( elem );
3648 // set new prev nodes
3649 for ( iNode = 0; iNode < nbNodes; iNode++ )
3650 prevNod[ iNode ] = nextNod[ iNode ];
3655 //=======================================================================
3657 * \brief Create 1D and 2D elements around swept elements
3658 * \param mapNewNodes - source nodes and ones generated from them
3659 * \param newElemsMap - source elements and ones generated from them
3660 * \param elemNewNodesMap - nodes generated from each node of each element
3661 * \param elemSet - all swept elements
3662 * \param nbSteps - number of sweeping steps
3663 * \param srcElements - to append elem for each generated element
3665 //=======================================================================
3667 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3668 TElemOfElemListMap & newElemsMap,
3669 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3670 TIDSortedElemSet& elemSet,
3672 SMESH_SequenceOfElemPtr& srcElements)
3674 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3675 SMESHDS_Mesh* aMesh = GetMeshDS();
3677 // Find nodes belonging to only one initial element - sweep them to get edges.
3679 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3680 for ( ; nList != mapNewNodes.end(); nList++ ) {
3681 const SMDS_MeshNode* node =
3682 static_cast<const SMDS_MeshNode*>( nList->first );
3683 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3684 int nbInitElems = 0;
3685 const SMDS_MeshElement* el = 0;
3686 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3687 while ( eIt->more() && nbInitElems < 2 ) {
3689 SMDSAbs_ElementType type = el->GetType();
3690 if ( type == SMDSAbs_Volume || type < highType ) continue;
3691 if ( type > highType ) {
3695 if ( elemSet.find(el) != elemSet.end() )
3698 if ( nbInitElems < 2 ) {
3699 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3700 if(!NotCreateEdge) {
3701 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3702 list<const SMDS_MeshElement*> newEdges;
3703 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3708 // Make a ceiling for each element ie an equal element of last new nodes.
3709 // Find free links of faces - make edges and sweep them into faces.
3711 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3712 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3713 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3714 const SMDS_MeshElement* elem = itElem->first;
3715 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3717 if ( elem->GetType() == SMDSAbs_Edge ) {
3718 // create a ceiling edge
3719 if (!elem->IsQuadratic()) {
3720 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3721 vecNewNodes[ 1 ]->second.back())) {
3722 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3723 vecNewNodes[ 1 ]->second.back()));
3724 srcElements.Append( myLastCreatedElems.Last() );
3728 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3729 vecNewNodes[ 1 ]->second.back(),
3730 vecNewNodes[ 2 ]->second.back())) {
3731 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3732 vecNewNodes[ 1 ]->second.back(),
3733 vecNewNodes[ 2 ]->second.back()));
3734 srcElements.Append( myLastCreatedElems.Last() );
3738 if ( elem->GetType() != SMDSAbs_Face )
3741 if(itElem->second.size()==0) continue;
3743 bool hasFreeLinks = false;
3745 TIDSortedElemSet avoidSet;
3746 avoidSet.insert( elem );
3748 set<const SMDS_MeshNode*> aFaceLastNodes;
3749 int iNode, nbNodes = vecNewNodes.size();
3750 if(!elem->IsQuadratic()) {
3751 // loop on the face nodes
3752 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3753 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3754 // look for free links of the face
3755 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3756 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3757 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3758 // check if a link is free
3759 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3760 hasFreeLinks = true;
3761 // make an edge and a ceiling for a new edge
3762 if ( !aMesh->FindEdge( n1, n2 )) {
3763 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3764 srcElements.Append( myLastCreatedElems.Last() );
3766 n1 = vecNewNodes[ iNode ]->second.back();
3767 n2 = vecNewNodes[ iNext ]->second.back();
3768 if ( !aMesh->FindEdge( n1, n2 )) {
3769 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3770 srcElements.Append( myLastCreatedElems.Last() );
3775 else { // elem is quadratic face
3776 int nbn = nbNodes/2;
3777 for ( iNode = 0; iNode < nbn; iNode++ ) {
3778 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3779 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3780 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3781 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3782 // check if a link is free
3783 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3784 hasFreeLinks = true;
3785 // make an edge and a ceiling for a new edge
3787 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3788 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3789 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3790 srcElements.Append( myLastCreatedElems.Last() );
3792 n1 = vecNewNodes[ iNode ]->second.back();
3793 n2 = vecNewNodes[ iNext ]->second.back();
3794 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3795 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3796 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3797 srcElements.Append( myLastCreatedElems.Last() );
3801 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3802 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3806 // sweep free links into faces
3808 if ( hasFreeLinks ) {
3809 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3810 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3812 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3813 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3814 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3815 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3817 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3818 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3820 while ( iVol++ < volNb ) v++;
3821 // find indices of free faces of a volume and their source edges
3822 list< int > freeInd;
3823 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3824 SMDS_VolumeTool vTool( *v );
3825 int iF, nbF = vTool.NbFaces();
3826 for ( iF = 0; iF < nbF; iF ++ ) {
3827 if (vTool.IsFreeFace( iF ) &&
3828 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3829 initNodeSet != faceNodeSet) // except an initial face
3831 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3833 freeInd.push_back( iF );
3834 // find source edge of a free face iF
3835 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3836 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3837 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3838 initNodeSet.begin(), initNodeSet.end(),
3839 commonNodes.begin());
3840 if ( (*v)->IsQuadratic() )
3841 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3843 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3845 if ( !srcEdges.back() )
3847 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3848 << iF << " of volume #" << vTool.ID() << endl;
3853 if ( freeInd.empty() )
3856 // create faces for all steps;
3857 // if such a face has been already created by sweep of edge,
3858 // assure that its orientation is OK
3859 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3861 vTool.SetExternalNormal();
3862 list< int >::iterator ind = freeInd.begin();
3863 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3864 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3866 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3867 int nbn = vTool.NbFaceNodes( *ind );
3869 case 3: { ///// triangle
3870 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3872 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3873 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3874 aMesh->ChangeElementNodes( f, nodes, nbn );
3877 case 4: { ///// quadrangle
3878 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3880 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3881 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3882 aMesh->ChangeElementNodes( f, nodes, nbn );
3886 if( (*v)->IsQuadratic() ) {
3887 if(nbn==6) { /////// quadratic triangle
3888 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3889 nodes[1], nodes[3], nodes[5] );
3891 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3892 nodes[1], nodes[3], nodes[5]));
3894 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3895 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3896 tmpnodes[0] = nodes[0];
3897 tmpnodes[1] = nodes[2];
3898 tmpnodes[2] = nodes[4];
3899 tmpnodes[3] = nodes[1];
3900 tmpnodes[4] = nodes[3];
3901 tmpnodes[5] = nodes[5];
3902 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3905 else { /////// quadratic quadrangle
3906 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3907 nodes[1], nodes[3], nodes[5], nodes[7] );
3909 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3910 nodes[1], nodes[3], nodes[5], nodes[7]));
3912 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3913 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3914 tmpnodes[0] = nodes[0];
3915 tmpnodes[1] = nodes[2];
3916 tmpnodes[2] = nodes[4];
3917 tmpnodes[3] = nodes[6];
3918 tmpnodes[4] = nodes[1];
3919 tmpnodes[5] = nodes[3];
3920 tmpnodes[6] = nodes[5];
3921 tmpnodes[7] = nodes[7];
3922 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3926 else { //////// polygon
3927 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3928 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3930 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3931 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3932 aMesh->ChangeElementNodes( f, nodes, nbn );
3935 while ( srcElements.Length() < myLastCreatedElems.Length() )
3936 srcElements.Append( *srcEdge );
3938 } // loop on free faces
3940 // go to the next volume
3942 while ( iVol++ < nbVolumesByStep ) v++;
3945 } // sweep free links into faces
3947 // Make a ceiling face with a normal external to a volume
3949 SMDS_VolumeTool lastVol( itElem->second.back() );
3951 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3953 lastVol.SetExternalNormal();
3954 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3955 int nbn = lastVol.NbFaceNodes( iF );
3958 if (!hasFreeLinks ||
3959 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3960 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3963 if (!hasFreeLinks ||
3964 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3965 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3968 if(itElem->second.back()->IsQuadratic()) {
3970 if (!hasFreeLinks ||
3971 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3972 nodes[1], nodes[3], nodes[5]) ) {
3973 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3974 nodes[1], nodes[3], nodes[5]));
3978 if (!hasFreeLinks ||
3979 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3980 nodes[1], nodes[3], nodes[5], nodes[7]) )
3981 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3982 nodes[1], nodes[3], nodes[5], nodes[7]));
3986 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3987 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3988 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3992 while ( srcElements.Length() < myLastCreatedElems.Length() )
3993 srcElements.Append( myLastCreatedElems.Last() );
3995 } // loop on swept elements
3998 //=======================================================================
3999 //function : RotationSweep
4001 //=======================================================================
4003 SMESH_MeshEditor::PGroupIDs
4004 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4005 const gp_Ax1& theAxis,
4006 const double theAngle,
4007 const int theNbSteps,
4008 const double theTol,
4009 const bool theMakeGroups,
4010 const bool theMakeWalls)
4012 myLastCreatedElems.Clear();
4013 myLastCreatedNodes.Clear();
4015 // source elements for each generated one
4016 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4018 MESSAGE( "RotationSweep()");
4020 aTrsf.SetRotation( theAxis, theAngle );
4022 aTrsf2.SetRotation( theAxis, theAngle/2. );
4024 gp_Lin aLine( theAxis );
4025 double aSqTol = theTol * theTol;
4027 SMESHDS_Mesh* aMesh = GetMeshDS();
4029 TNodeOfNodeListMap mapNewNodes;
4030 TElemOfVecOfNnlmiMap mapElemNewNodes;
4031 TElemOfElemListMap newElemsMap;
4034 TIDSortedElemSet::iterator itElem;
4035 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4036 const SMDS_MeshElement* elem = *itElem;
4037 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4039 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4040 newNodesItVec.reserve( elem->NbNodes() );
4042 // loop on elem nodes
4043 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4044 while ( itN->more() ) {
4045 // check if a node has been already sweeped
4046 const SMDS_MeshNode* node = cast2Node( itN->next() );
4048 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4050 aXYZ.Coord( coord[0], coord[1], coord[2] );
4051 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4053 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4054 if ( nIt == mapNewNodes.end() ) {
4055 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4056 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4059 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4061 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4062 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4063 const SMDS_MeshNode * newNode = node;
4064 for ( int i = 0; i < theNbSteps; i++ ) {
4066 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4068 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4069 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4070 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4071 myLastCreatedNodes.Append(newNode);
4072 srcNodes.Append( node );
4073 listNewNodes.push_back( newNode );
4074 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4075 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4078 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4080 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4081 myLastCreatedNodes.Append(newNode);
4082 srcNodes.Append( node );
4083 listNewNodes.push_back( newNode );
4086 listNewNodes.push_back( newNode );
4087 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4088 listNewNodes.push_back( newNode );
4095 // if current elem is quadratic and current node is not medium
4096 // we have to check - may be it is needed to insert additional nodes
4097 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4098 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4099 if(listNewNodes.size()==theNbSteps) {
4100 listNewNodes.clear();
4102 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4104 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4105 const SMDS_MeshNode * newNode = node;
4107 for(int i = 0; i<theNbSteps; i++) {
4108 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4109 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4110 cout<<" 3 AddNode: "<<newNode;
4111 myLastCreatedNodes.Append(newNode);
4112 listNewNodes.push_back( newNode );
4113 srcNodes.Append( node );
4114 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4115 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4116 cout<<" 4 AddNode: "<<newNode;
4117 myLastCreatedNodes.Append(newNode);
4118 srcNodes.Append( node );
4119 listNewNodes.push_back( newNode );
4123 listNewNodes.push_back( newNode );
4129 newNodesItVec.push_back( nIt );
4131 // make new elements
4132 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4136 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4138 PGroupIDs newGroupIDs;
4139 if ( theMakeGroups )
4140 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4146 //=======================================================================
4147 //function : CreateNode
4149 //=======================================================================
4150 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4153 const double tolnode,
4154 SMESH_SequenceOfNode& aNodes)
4156 myLastCreatedElems.Clear();
4157 myLastCreatedNodes.Clear();
4160 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4162 // try to search in sequence of existing nodes
4163 // if aNodes.Length()>0 we 'nave to use given sequence
4164 // else - use all nodes of mesh
4165 if(aNodes.Length()>0) {
4167 for(i=1; i<=aNodes.Length(); i++) {
4168 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4169 if(P1.Distance(P2)<tolnode)
4170 return aNodes.Value(i);
4174 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4175 while(itn->more()) {
4176 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4177 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4178 if(P1.Distance(P2)<tolnode)
4183 // create new node and return it
4184 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4185 myLastCreatedNodes.Append(NewNode);
4190 //=======================================================================
4191 //function : ExtrusionSweep
4193 //=======================================================================
4195 SMESH_MeshEditor::PGroupIDs
4196 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4197 const gp_Vec& theStep,
4198 const int theNbSteps,
4199 TElemOfElemListMap& newElemsMap,
4200 const bool theMakeGroups,
4202 const double theTolerance)
4204 ExtrusParam aParams;
4205 aParams.myDir = gp_Dir(theStep);
4206 aParams.myNodes.Clear();
4207 aParams.mySteps = new TColStd_HSequenceOfReal;
4209 for(i=1; i<=theNbSteps; i++)
4210 aParams.mySteps->Append(theStep.Magnitude());
4213 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4217 //=======================================================================
4218 //function : ExtrusionSweep
4220 //=======================================================================
4222 SMESH_MeshEditor::PGroupIDs
4223 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4224 ExtrusParam& theParams,
4225 TElemOfElemListMap& newElemsMap,
4226 const bool theMakeGroups,
4228 const double theTolerance)
4230 myLastCreatedElems.Clear();
4231 myLastCreatedNodes.Clear();
4233 // source elements for each generated one
4234 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4236 SMESHDS_Mesh* aMesh = GetMeshDS();
4238 int nbsteps = theParams.mySteps->Length();
4240 TNodeOfNodeListMap mapNewNodes;
4241 //TNodeOfNodeVecMap mapNewNodes;
4242 TElemOfVecOfNnlmiMap mapElemNewNodes;
4243 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4246 TIDSortedElemSet::iterator itElem;
4247 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4248 // check element type
4249 const SMDS_MeshElement* elem = *itElem;
4250 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4253 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4255 newNodesItVec.reserve( elem->NbNodes() );
4257 // loop on elem nodes
4258 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4259 while ( itN->more() )
4261 // check if a node has been already sweeped
4262 const SMDS_MeshNode* node = cast2Node( itN->next() );
4263 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4264 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4265 if ( nIt == mapNewNodes.end() ) {
4266 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4267 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4268 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4269 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4270 //vecNewNodes.reserve(nbsteps);
4273 double coord[] = { node->X(), node->Y(), node->Z() };
4274 //int nbsteps = theParams.mySteps->Length();
4275 for ( int i = 0; i < nbsteps; i++ ) {
4276 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4277 // create additional node
4278 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4279 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4280 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4281 if( theFlags & EXTRUSION_FLAG_SEW ) {
4282 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4283 theTolerance, theParams.myNodes);
4284 listNewNodes.push_back( newNode );
4287 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4288 myLastCreatedNodes.Append(newNode);
4289 srcNodes.Append( node );
4290 listNewNodes.push_back( newNode );
4293 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4294 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4295 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4296 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4297 if( theFlags & EXTRUSION_FLAG_SEW ) {
4298 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4299 theTolerance, theParams.myNodes);
4300 listNewNodes.push_back( newNode );
4301 //vecNewNodes[i]=newNode;
4304 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4305 myLastCreatedNodes.Append(newNode);
4306 srcNodes.Append( node );
4307 listNewNodes.push_back( newNode );
4308 //vecNewNodes[i]=newNode;
4313 // if current elem is quadratic and current node is not medium
4314 // we have to check - may be it is needed to insert additional nodes
4315 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4316 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4317 if(listNewNodes.size()==nbsteps) {
4318 listNewNodes.clear();
4319 double coord[] = { node->X(), node->Y(), node->Z() };
4320 for ( int i = 0; i < nbsteps; i++ ) {
4321 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4322 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4323 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4324 if( theFlags & EXTRUSION_FLAG_SEW ) {
4325 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4326 theTolerance, theParams.myNodes);
4327 listNewNodes.push_back( newNode );
4330 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4331 myLastCreatedNodes.Append(newNode);
4332 srcNodes.Append( node );
4333 listNewNodes.push_back( newNode );
4335 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4336 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4337 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4338 if( theFlags & EXTRUSION_FLAG_SEW ) {
4339 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4340 theTolerance, theParams.myNodes);
4341 listNewNodes.push_back( newNode );
4344 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4345 myLastCreatedNodes.Append(newNode);
4346 srcNodes.Append( node );
4347 listNewNodes.push_back( newNode );
4353 newNodesItVec.push_back( nIt );
4355 // make new elements
4356 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4359 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4360 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4362 PGroupIDs newGroupIDs;
4363 if ( theMakeGroups )
4364 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4370 //=======================================================================
4371 //class : SMESH_MeshEditor_PathPoint
4372 //purpose : auxiliary class
4373 //=======================================================================
4374 class SMESH_MeshEditor_PathPoint {
4376 SMESH_MeshEditor_PathPoint() {
4377 myPnt.SetCoord(99., 99., 99.);
4378 myTgt.SetCoord(1.,0.,0.);
4382 void SetPnt(const gp_Pnt& aP3D){
4385 void SetTangent(const gp_Dir& aTgt){
4388 void SetAngle(const double& aBeta){
4391 void SetParameter(const double& aPrm){
4394 const gp_Pnt& Pnt()const{
4397 const gp_Dir& Tangent()const{
4400 double Angle()const{
4403 double Parameter()const{
4415 //=======================================================================
4416 //function : ExtrusionAlongTrack
4418 //=======================================================================
4419 SMESH_MeshEditor::Extrusion_Error
4420 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4421 SMESH_subMesh* theTrack,
4422 const SMDS_MeshNode* theN1,
4423 const bool theHasAngles,
4424 list<double>& theAngles,
4425 const bool theLinearVariation,
4426 const bool theHasRefPoint,
4427 const gp_Pnt& theRefPoint,
4428 const bool theMakeGroups)
4430 myLastCreatedElems.Clear();
4431 myLastCreatedNodes.Clear();
4434 std::list<double> aPrms;
4435 TIDSortedElemSet::iterator itElem;
4438 TopoDS_Edge aTrackEdge;
4439 TopoDS_Vertex aV1, aV2;
4441 SMDS_ElemIteratorPtr aItE;
4442 SMDS_NodeIteratorPtr aItN;
4443 SMDSAbs_ElementType aTypeE;
4445 TNodeOfNodeListMap mapNewNodes;
4448 aNbE = theElements.size();
4451 return EXTR_NO_ELEMENTS;
4453 // 1.1 Track Pattern
4456 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4458 aItE = pSubMeshDS->GetElements();
4459 while ( aItE->more() ) {
4460 const SMDS_MeshElement* pE = aItE->next();
4461 aTypeE = pE->GetType();
4462 // Pattern must contain links only
4463 if ( aTypeE != SMDSAbs_Edge )
4464 return EXTR_PATH_NOT_EDGE;
4467 list<SMESH_MeshEditor_PathPoint> fullList;
4469 const TopoDS_Shape& aS = theTrack->GetSubShape();
4470 // Sub shape for the Pattern must be an Edge or Wire
4471 if( aS.ShapeType() == TopAbs_EDGE ) {
4472 aTrackEdge = TopoDS::Edge( aS );
4473 // the Edge must not be degenerated
4474 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4475 return EXTR_BAD_PATH_SHAPE;
4476 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4477 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4478 const SMDS_MeshNode* aN1 = aItN->next();
4479 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4480 const SMDS_MeshNode* aN2 = aItN->next();
4481 // starting node must be aN1 or aN2
4482 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4483 return EXTR_BAD_STARTING_NODE;
4484 aItN = pSubMeshDS->GetNodes();
4485 while ( aItN->more() ) {
4486 const SMDS_MeshNode* pNode = aItN->next();
4487 const SMDS_EdgePosition* pEPos =
4488 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4489 double aT = pEPos->GetUParameter();
4490 aPrms.push_back( aT );
4492 //Extrusion_Error err =
4493 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4495 else if( aS.ShapeType() == TopAbs_WIRE ) {
4496 list< SMESH_subMesh* > LSM;
4497 TopTools_SequenceOfShape Edges;
4498 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4499 while(itSM->more()) {
4500 SMESH_subMesh* SM = itSM->next();
4502 const TopoDS_Shape& aS = SM->GetSubShape();
4505 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4506 int startNid = theN1->GetID();
4507 TColStd_MapOfInteger UsedNums;
4508 int NbEdges = Edges.Length();
4510 for(; i<=NbEdges; i++) {
4512 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4513 for(; itLSM!=LSM.end(); itLSM++) {
4515 if(UsedNums.Contains(k)) continue;
4516 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4517 SMESH_subMesh* locTrack = *itLSM;
4518 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4519 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4520 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4521 const SMDS_MeshNode* aN1 = aItN->next();
4522 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4523 const SMDS_MeshNode* aN2 = aItN->next();
4524 // starting node must be aN1 or aN2
4525 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4526 // 2. Collect parameters on the track edge
4528 aItN = locMeshDS->GetNodes();
4529 while ( aItN->more() ) {
4530 const SMDS_MeshNode* pNode = aItN->next();
4531 const SMDS_EdgePosition* pEPos =
4532 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4533 double aT = pEPos->GetUParameter();
4534 aPrms.push_back( aT );
4536 list<SMESH_MeshEditor_PathPoint> LPP;
4537 //Extrusion_Error err =
4538 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4539 LLPPs.push_back(LPP);
4541 // update startN for search following egde
4542 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4543 else startNid = aN1->GetID();
4547 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4548 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4549 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4550 for(; itPP!=firstList.end(); itPP++) {
4551 fullList.push_back( *itPP );
4553 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4554 fullList.pop_back();
4556 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4557 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4558 itPP = currList.begin();
4559 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4560 gp_Dir D1 = PP1.Tangent();
4561 gp_Dir D2 = PP2.Tangent();
4562 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4563 (D1.Z()+D2.Z())/2 ) );
4564 PP1.SetTangent(Dnew);
4565 fullList.push_back(PP1);
4567 for(; itPP!=firstList.end(); itPP++) {
4568 fullList.push_back( *itPP );
4570 PP1 = fullList.back();
4571 fullList.pop_back();
4573 // if wire not closed
4574 fullList.push_back(PP1);
4578 return EXTR_BAD_PATH_SHAPE;
4581 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4582 theHasRefPoint, theRefPoint, theMakeGroups);
4586 //=======================================================================
4587 //function : ExtrusionAlongTrack
4589 //=======================================================================
4590 SMESH_MeshEditor::Extrusion_Error
4591 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4592 SMESH_Mesh* theTrack,
4593 const SMDS_MeshNode* theN1,
4594 const bool theHasAngles,
4595 list<double>& theAngles,
4596 const bool theLinearVariation,
4597 const bool theHasRefPoint,
4598 const gp_Pnt& theRefPoint,
4599 const bool theMakeGroups)
4601 myLastCreatedElems.Clear();
4602 myLastCreatedNodes.Clear();
4605 std::list<double> aPrms;
4606 TIDSortedElemSet::iterator itElem;
4609 TopoDS_Edge aTrackEdge;
4610 TopoDS_Vertex aV1, aV2;
4612 SMDS_ElemIteratorPtr aItE;
4613 SMDS_NodeIteratorPtr aItN;
4614 SMDSAbs_ElementType aTypeE;
4616 TNodeOfNodeListMap mapNewNodes;
4619 aNbE = theElements.size();
4622 return EXTR_NO_ELEMENTS;
4624 // 1.1 Track Pattern
4627 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4629 aItE = pMeshDS->elementsIterator();
4630 while ( aItE->more() ) {
4631 const SMDS_MeshElement* pE = aItE->next();
4632 aTypeE = pE->GetType();
4633 // Pattern must contain links only
4634 if ( aTypeE != SMDSAbs_Edge )
4635 return EXTR_PATH_NOT_EDGE;
4638 list<SMESH_MeshEditor_PathPoint> fullList;
4640 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4641 // Sub shape for the Pattern must be an Edge or Wire
4642 if( aS.ShapeType() == TopAbs_EDGE ) {
4643 aTrackEdge = TopoDS::Edge( aS );
4644 // the Edge must not be degenerated
4645 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4646 return EXTR_BAD_PATH_SHAPE;
4647 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4648 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4649 const SMDS_MeshNode* aN1 = aItN->next();
4650 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4651 const SMDS_MeshNode* aN2 = aItN->next();
4652 // starting node must be aN1 or aN2
4653 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4654 return EXTR_BAD_STARTING_NODE;
4655 aItN = pMeshDS->nodesIterator();
4656 while ( aItN->more() ) {
4657 const SMDS_MeshNode* pNode = aItN->next();
4658 if( pNode==aN1 || pNode==aN2 ) continue;
4659 const SMDS_EdgePosition* pEPos =
4660 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4661 double aT = pEPos->GetUParameter();
4662 aPrms.push_back( aT );
4664 //Extrusion_Error err =
4665 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4667 else if( aS.ShapeType() == TopAbs_WIRE ) {
4668 list< SMESH_subMesh* > LSM;
4669 TopTools_SequenceOfShape Edges;
4670 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4671 for(; eExp.More(); eExp.Next()) {
4672 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4673 if( BRep_Tool::Degenerated(E) ) continue;
4674 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4680 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4681 int startNid = theN1->GetID();
4682 TColStd_MapOfInteger UsedNums;
4683 int NbEdges = Edges.Length();
4685 for(; i<=NbEdges; i++) {
4687 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4688 for(; itLSM!=LSM.end(); itLSM++) {
4690 if(UsedNums.Contains(k)) continue;
4691 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4692 SMESH_subMesh* locTrack = *itLSM;
4693 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4694 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4695 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4696 const SMDS_MeshNode* aN1 = aItN->next();
4697 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4698 const SMDS_MeshNode* aN2 = aItN->next();
4699 // starting node must be aN1 or aN2
4700 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4701 // 2. Collect parameters on the track edge
4703 aItN = locMeshDS->GetNodes();
4704 while ( aItN->more() ) {
4705 const SMDS_MeshNode* pNode = aItN->next();
4706 const SMDS_EdgePosition* pEPos =
4707 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4708 double aT = pEPos->GetUParameter();
4709 aPrms.push_back( aT );
4711 list<SMESH_MeshEditor_PathPoint> LPP;
4712 //Extrusion_Error err =
4713 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4714 LLPPs.push_back(LPP);
4716 // update startN for search following egde
4717 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4718 else startNid = aN1->GetID();
4722 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4723 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4724 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4725 for(; itPP!=firstList.end(); itPP++) {
4726 fullList.push_back( *itPP );
4728 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4729 fullList.pop_back();
4731 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4732 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4733 itPP = currList.begin();
4734 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4735 gp_Pnt P1 = PP1.Pnt();
4736 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4737 gp_Pnt P2 = PP2.Pnt();
4738 gp_Dir D1 = PP1.Tangent();
4739 gp_Dir D2 = PP2.Tangent();
4740 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4741 (D1.Z()+D2.Z())/2 ) );
4742 PP1.SetTangent(Dnew);
4743 fullList.push_back(PP1);
4745 for(; itPP!=currList.end(); itPP++) {
4746 fullList.push_back( *itPP );
4748 PP1 = fullList.back();
4749 fullList.pop_back();
4751 // if wire not closed
4752 fullList.push_back(PP1);
4756 return EXTR_BAD_PATH_SHAPE;
4759 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4760 theHasRefPoint, theRefPoint, theMakeGroups);
4764 //=======================================================================
4765 //function : MakeEdgePathPoints
4766 //purpose : auxilary for ExtrusionAlongTrack
4767 //=======================================================================
4768 SMESH_MeshEditor::Extrusion_Error
4769 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4770 const TopoDS_Edge& aTrackEdge,
4772 list<SMESH_MeshEditor_PathPoint>& LPP)
4774 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4776 aTolVec2=aTolVec*aTolVec;
4778 TopoDS_Vertex aV1, aV2;
4779 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4780 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4781 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4782 // 2. Collect parameters on the track edge
4783 aPrms.push_front( aT1 );
4784 aPrms.push_back( aT2 );
4787 if( FirstIsStart ) {
4798 SMESH_MeshEditor_PathPoint aPP;
4799 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4800 std::list<double>::iterator aItD = aPrms.begin();
4801 for(; aItD != aPrms.end(); ++aItD) {
4805 aC3D->D1( aT, aP3D, aVec );
4806 aL2 = aVec.SquareMagnitude();
4807 if ( aL2 < aTolVec2 )
4808 return EXTR_CANT_GET_TANGENT;
4809 gp_Dir aTgt( aVec );
4811 aPP.SetTangent( aTgt );
4812 aPP.SetParameter( aT );
4819 //=======================================================================
4820 //function : MakeExtrElements
4821 //purpose : auxilary for ExtrusionAlongTrack
4822 //=======================================================================
4823 SMESH_MeshEditor::Extrusion_Error
4824 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4825 list<SMESH_MeshEditor_PathPoint>& fullList,
4826 const bool theHasAngles,
4827 list<double>& theAngles,
4828 const bool theLinearVariation,
4829 const bool theHasRefPoint,
4830 const gp_Pnt& theRefPoint,
4831 const bool theMakeGroups)
4833 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4834 int aNbTP = fullList.size();
4835 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4837 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4838 LinearAngleVariation(aNbTP-1, theAngles);
4840 vector<double> aAngles( aNbTP );
4842 for(; j<aNbTP; ++j) {
4845 if ( theHasAngles ) {
4847 std::list<double>::iterator aItD = theAngles.begin();
4848 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4850 aAngles[j] = anAngle;
4853 // fill vector of path points with angles
4854 //aPPs.resize(fullList.size());
4856 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4857 for(; itPP!=fullList.end(); itPP++) {
4859 SMESH_MeshEditor_PathPoint PP = *itPP;
4860 PP.SetAngle(aAngles[j]);
4864 TNodeOfNodeListMap mapNewNodes;
4865 TElemOfVecOfNnlmiMap mapElemNewNodes;
4866 TElemOfElemListMap newElemsMap;
4867 TIDSortedElemSet::iterator itElem;
4870 SMDSAbs_ElementType aTypeE;
4871 // source elements for each generated one
4872 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4874 // 3. Center of rotation aV0
4875 gp_Pnt aV0 = theRefPoint;
4877 if ( !theHasRefPoint ) {
4879 aGC.SetCoord( 0.,0.,0. );
4881 itElem = theElements.begin();
4882 for ( ; itElem != theElements.end(); itElem++ ) {
4883 const SMDS_MeshElement* elem = *itElem;
4885 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4886 while ( itN->more() ) {
4887 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4892 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4893 list<const SMDS_MeshNode*> aLNx;
4894 mapNewNodes[node] = aLNx;
4896 gp_XYZ aXYZ( aX, aY, aZ );
4904 } // if (!theHasRefPoint) {
4905 mapNewNodes.clear();
4907 // 4. Processing the elements
4908 SMESHDS_Mesh* aMesh = GetMeshDS();
4910 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4911 // check element type
4912 const SMDS_MeshElement* elem = *itElem;
4913 aTypeE = elem->GetType();
4914 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4917 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4918 newNodesItVec.reserve( elem->NbNodes() );
4920 // loop on elem nodes
4922 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4923 while ( itN->more() )
4926 // check if a node has been already processed
4927 const SMDS_MeshNode* node =
4928 static_cast<const SMDS_MeshNode*>( itN->next() );
4929 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4930 if ( nIt == mapNewNodes.end() ) {
4931 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4932 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4935 aX = node->X(); aY = node->Y(); aZ = node->Z();
4937 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4938 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4939 gp_Ax1 anAx1, anAxT1T0;
4940 gp_Dir aDT1x, aDT0x, aDT1T0;
4945 aPN0.SetCoord(aX, aY, aZ);
4947 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4949 aDT0x= aPP0.Tangent();
4950 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4952 for ( j = 1; j < aNbTP; ++j ) {
4953 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4955 aDT1x = aPP1.Tangent();
4956 aAngle1x = aPP1.Angle();
4958 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4960 gp_Vec aV01x( aP0x, aP1x );
4961 aTrsf.SetTranslation( aV01x );
4964 aV1x = aV0x.Transformed( aTrsf );
4965 aPN1 = aPN0.Transformed( aTrsf );
4967 // rotation 1 [ T1,T0 ]
4968 aAngleT1T0=-aDT1x.Angle( aDT0x );
4969 if (fabs(aAngleT1T0) > aTolAng) {
4971 anAxT1T0.SetLocation( aV1x );
4972 anAxT1T0.SetDirection( aDT1T0 );
4973 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4975 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4979 if ( theHasAngles ) {
4980 anAx1.SetLocation( aV1x );
4981 anAx1.SetDirection( aDT1x );
4982 aTrsfRot.SetRotation( anAx1, aAngle1x );
4984 aPN1 = aPN1.Transformed( aTrsfRot );
4988 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4989 // create additional node
4990 double x = ( aPN1.X() + aPN0.X() )/2.;
4991 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4992 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4993 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4994 myLastCreatedNodes.Append(newNode);
4995 srcNodes.Append( node );
4996 listNewNodes.push_back( newNode );
5001 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5002 myLastCreatedNodes.Append(newNode);
5003 srcNodes.Append( node );
5004 listNewNodes.push_back( newNode );
5014 // if current elem is quadratic and current node is not medium
5015 // we have to check - may be it is needed to insert additional nodes
5016 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5017 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5018 if(listNewNodes.size()==aNbTP-1) {
5019 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5020 gp_XYZ P(node->X(), node->Y(), node->Z());
5021 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5023 for(i=0; i<aNbTP-1; i++) {
5024 const SMDS_MeshNode* N = *it;
5025 double x = ( N->X() + P.X() )/2.;
5026 double y = ( N->Y() + P.Y() )/2.;
5027 double z = ( N->Z() + P.Z() )/2.;
5028 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5029 srcNodes.Append( node );
5030 myLastCreatedNodes.Append(newN);
5033 P = gp_XYZ(N->X(),N->Y(),N->Z());
5035 listNewNodes.clear();
5036 for(i=0; i<2*(aNbTP-1); i++) {
5037 listNewNodes.push_back(aNodes[i]);
5043 newNodesItVec.push_back( nIt );
5045 // make new elements
5046 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5047 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5048 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5051 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5053 if ( theMakeGroups )
5054 generateGroups( srcNodes, srcElems, "extruded");
5060 //=======================================================================
5061 //function : LinearAngleVariation
5062 //purpose : auxilary for ExtrusionAlongTrack
5063 //=======================================================================
5064 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5065 list<double>& Angles)
5067 int nbAngles = Angles.size();
5068 if( nbSteps > nbAngles ) {
5069 vector<double> theAngles(nbAngles);
5070 list<double>::iterator it = Angles.begin();
5072 for(; it!=Angles.end(); it++) {
5074 theAngles[i] = (*it);
5077 double rAn2St = double( nbAngles ) / double( nbSteps );
5078 double angPrev = 0, angle;
5079 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5080 double angCur = rAn2St * ( iSt+1 );
5081 double angCurFloor = floor( angCur );
5082 double angPrevFloor = floor( angPrev );
5083 if ( angPrevFloor == angCurFloor )
5084 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5086 int iP = int( angPrevFloor );
5087 double angPrevCeil = ceil(angPrev);
5088 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5090 int iC = int( angCurFloor );
5091 if ( iC < nbAngles )
5092 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5094 iP = int( angPrevCeil );
5096 angle += theAngles[ iC ];
5098 res.push_back(angle);
5103 for(; it!=res.end(); it++)
5104 Angles.push_back( *it );
5109 //=======================================================================
5110 //function : Transform
5112 //=======================================================================
5114 SMESH_MeshEditor::PGroupIDs
5115 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5116 const gp_Trsf& theTrsf,
5118 const bool theMakeGroups,
5119 SMESH_Mesh* theTargetMesh)
5121 myLastCreatedElems.Clear();
5122 myLastCreatedNodes.Clear();
5124 bool needReverse = false;
5125 string groupPostfix;
5126 switch ( theTrsf.Form() ) {
5131 groupPostfix = "mirrored";
5134 groupPostfix = "rotated";
5136 case gp_Translation:
5137 groupPostfix = "translated";
5140 groupPostfix = "scaled";
5143 needReverse = false;
5144 groupPostfix = "transformed";
5147 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5148 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5149 SMESHDS_Mesh* aMesh = GetMeshDS();
5152 // map old node to new one
5153 TNodeNodeMap nodeMap;
5155 // elements sharing moved nodes; those of them which have all
5156 // nodes mirrored but are not in theElems are to be reversed
5157 TIDSortedElemSet inverseElemSet;
5159 // source elements for each generated one
5160 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5163 TIDSortedElemSet::iterator itElem;
5164 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5165 const SMDS_MeshElement* elem = *itElem;
5169 // loop on elem nodes
5170 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5171 while ( itN->more() ) {
5173 // check if a node has been already transformed
5174 const SMDS_MeshNode* node = cast2Node( itN->next() );
5175 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5176 nodeMap.insert( make_pair ( node, node ));
5177 if ( !n2n_isnew.second )
5181 coord[0] = node->X();
5182 coord[1] = node->Y();
5183 coord[2] = node->Z();
5184 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5185 if ( theTargetMesh ) {
5186 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5187 n2n_isnew.first->second = newNode;
5188 myLastCreatedNodes.Append(newNode);
5189 srcNodes.Append( node );
5191 else if ( theCopy ) {
5192 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5193 n2n_isnew.first->second = newNode;
5194 myLastCreatedNodes.Append(newNode);
5195 srcNodes.Append( node );
5198 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5199 // node position on shape becomes invalid
5200 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5201 ( SMDS_SpacePosition::originSpacePosition() );
5204 // keep inverse elements
5205 if ( !theCopy && !theTargetMesh && needReverse ) {
5206 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5207 while ( invElemIt->more() ) {
5208 const SMDS_MeshElement* iel = invElemIt->next();
5209 inverseElemSet.insert( iel );
5215 // either create new elements or reverse mirrored ones
5216 if ( !theCopy && !needReverse && !theTargetMesh )
5219 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5220 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5221 theElems.insert( *invElemIt );
5223 // replicate or reverse elements
5226 REV_TETRA = 0, // = nbNodes - 4
5227 REV_PYRAMID = 1, // = nbNodes - 4
5228 REV_PENTA = 2, // = nbNodes - 4
5230 REV_HEXA = 4, // = nbNodes - 4
5234 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5235 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5236 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5237 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5238 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5239 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5242 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5244 const SMDS_MeshElement* elem = *itElem;
5245 if ( !elem || elem->GetType() == SMDSAbs_Node )
5248 int nbNodes = elem->NbNodes();
5249 int elemType = elem->GetType();
5251 if (elem->IsPoly()) {
5252 // Polygon or Polyhedral Volume
5253 switch ( elemType ) {
5256 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5258 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5259 while (itN->more()) {
5260 const SMDS_MeshNode* node =
5261 static_cast<const SMDS_MeshNode*>(itN->next());
5262 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5263 if (nodeMapIt == nodeMap.end())
5264 break; // not all nodes transformed
5266 // reverse mirrored faces and volumes
5267 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5269 poly_nodes[iNode] = (*nodeMapIt).second;
5273 if ( iNode != nbNodes )
5274 continue; // not all nodes transformed
5276 if ( theTargetMesh ) {
5277 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5278 srcElems.Append( elem );
5280 else if ( theCopy ) {
5281 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5282 srcElems.Append( elem );
5285 aMesh->ChangePolygonNodes(elem, poly_nodes);
5289 case SMDSAbs_Volume:
5291 // ATTENTION: Reversing is not yet done!!!
5292 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5293 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5295 MESSAGE("Warning: bad volumic element");
5299 vector<const SMDS_MeshNode*> poly_nodes;
5300 vector<int> quantities;
5302 bool allTransformed = true;
5303 int nbFaces = aPolyedre->NbFaces();
5304 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5305 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5306 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5307 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5308 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5309 if (nodeMapIt == nodeMap.end()) {
5310 allTransformed = false; // not all nodes transformed
5312 poly_nodes.push_back((*nodeMapIt).second);
5315 quantities.push_back(nbFaceNodes);
5317 if ( !allTransformed )
5318 continue; // not all nodes transformed
5320 if ( theTargetMesh ) {
5321 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5322 srcElems.Append( elem );
5324 else if ( theCopy ) {
5325 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5326 srcElems.Append( elem );
5329 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5339 int* i = index[ FORWARD ];
5340 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5341 if ( elemType == SMDSAbs_Face )
5342 i = index[ REV_FACE ];
5344 i = index[ nbNodes - 4 ];
5346 if(elem->IsQuadratic()) {
5347 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5350 if(nbNodes==3) { // quadratic edge
5351 static int anIds[] = {1,0,2};
5354 else if(nbNodes==6) { // quadratic triangle
5355 static int anIds[] = {0,2,1,5,4,3};
5358 else if(nbNodes==8) { // quadratic quadrangle
5359 static int anIds[] = {0,3,2,1,7,6,5,4};
5362 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5363 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5366 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5367 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5370 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5371 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5374 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5375 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5381 // find transformed nodes
5382 vector<const SMDS_MeshNode*> nodes(nbNodes);
5384 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5385 while ( itN->more() ) {
5386 const SMDS_MeshNode* node =
5387 static_cast<const SMDS_MeshNode*>( itN->next() );
5388 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5389 if ( nodeMapIt == nodeMap.end() )
5390 break; // not all nodes transformed
5391 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5393 if ( iNode != nbNodes )
5394 continue; // not all nodes transformed
5396 if ( theTargetMesh ) {
5397 if ( SMDS_MeshElement* copy =
5398 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5399 myLastCreatedElems.Append( copy );
5400 srcElems.Append( elem );
5403 else if ( theCopy ) {
5404 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5405 myLastCreatedElems.Append( copy );
5406 srcElems.Append( elem );
5410 // reverse element as it was reversed by transformation
5412 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5416 PGroupIDs newGroupIDs;
5418 if ( theMakeGroups && theCopy ||
5419 theMakeGroups && theTargetMesh )
5420 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5426 //=======================================================================
5429 //=======================================================================
5431 SMESH_MeshEditor::PGroupIDs
5432 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5433 const gp_Pnt& thePoint,
5434 const std::list<double>& theScaleFact,
5436 const bool theMakeGroups,
5437 SMESH_Mesh* theTargetMesh)
5439 myLastCreatedElems.Clear();
5440 myLastCreatedNodes.Clear();
5442 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5443 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5444 SMESHDS_Mesh* aMesh = GetMeshDS();
5446 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5447 std::list<double>::const_iterator itS = theScaleFact.begin();
5449 if(theScaleFact.size()==1) {
5453 if(theScaleFact.size()==2) {
5458 if(theScaleFact.size()>2) {
5465 // map old node to new one
5466 TNodeNodeMap nodeMap;
5468 // elements sharing moved nodes; those of them which have all
5469 // nodes mirrored but are not in theElems are to be reversed
5470 TIDSortedElemSet inverseElemSet;
5472 // source elements for each generated one
5473 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5476 TIDSortedElemSet::iterator itElem;
5477 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5478 const SMDS_MeshElement* elem = *itElem;
5482 // loop on elem nodes
5483 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5484 while ( itN->more() ) {
5486 // check if a node has been already transformed
5487 const SMDS_MeshNode* node = cast2Node( itN->next() );
5488 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5489 nodeMap.insert( make_pair ( node, node ));
5490 if ( !n2n_isnew.second )
5494 //coord[0] = node->X();
5495 //coord[1] = node->Y();
5496 //coord[2] = node->Z();
5497 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5498 double dx = (node->X() - thePoint.X()) * scaleX;
5499 double dy = (node->Y() - thePoint.Y()) * scaleY;
5500 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5501 if ( theTargetMesh ) {
5502 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5503 const SMDS_MeshNode * newNode =
5504 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5505 n2n_isnew.first->second = newNode;
5506 myLastCreatedNodes.Append(newNode);
5507 srcNodes.Append( node );
5509 else if ( theCopy ) {
5510 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5511 const SMDS_MeshNode * newNode =
5512 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5513 n2n_isnew.first->second = newNode;
5514 myLastCreatedNodes.Append(newNode);
5515 srcNodes.Append( node );
5518 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5519 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5520 // node position on shape becomes invalid
5521 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5522 ( SMDS_SpacePosition::originSpacePosition() );
5525 // keep inverse elements
5526 //if ( !theCopy && !theTargetMesh && needReverse ) {
5527 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5528 // while ( invElemIt->more() ) {
5529 // const SMDS_MeshElement* iel = invElemIt->next();
5530 // inverseElemSet.insert( iel );
5536 // either create new elements or reverse mirrored ones
5537 //if ( !theCopy && !needReverse && !theTargetMesh )
5538 if ( !theCopy && !theTargetMesh )
5541 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5542 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5543 theElems.insert( *invElemIt );
5545 // replicate or reverse elements
5548 REV_TETRA = 0, // = nbNodes - 4
5549 REV_PYRAMID = 1, // = nbNodes - 4
5550 REV_PENTA = 2, // = nbNodes - 4
5552 REV_HEXA = 4, // = nbNodes - 4
5556 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5557 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5558 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5559 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5560 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5561 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5564 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5566 const SMDS_MeshElement* elem = *itElem;
5567 if ( !elem || elem->GetType() == SMDSAbs_Node )
5570 int nbNodes = elem->NbNodes();
5571 int elemType = elem->GetType();
5573 if (elem->IsPoly()) {
5574 // Polygon or Polyhedral Volume
5575 switch ( elemType ) {
5578 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5580 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5581 while (itN->more()) {
5582 const SMDS_MeshNode* node =
5583 static_cast<const SMDS_MeshNode*>(itN->next());
5584 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5585 if (nodeMapIt == nodeMap.end())
5586 break; // not all nodes transformed
5587 //if (needReverse) {
5588 // // reverse mirrored faces and volumes
5589 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5591 poly_nodes[iNode] = (*nodeMapIt).second;
5595 if ( iNode != nbNodes )
5596 continue; // not all nodes transformed
5598 if ( theTargetMesh ) {
5599 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5600 srcElems.Append( elem );
5602 else if ( theCopy ) {
5603 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5604 srcElems.Append( elem );
5607 aMesh->ChangePolygonNodes(elem, poly_nodes);
5611 case SMDSAbs_Volume:
5613 // ATTENTION: Reversing is not yet done!!!
5614 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5615 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5617 MESSAGE("Warning: bad volumic element");
5621 vector<const SMDS_MeshNode*> poly_nodes;
5622 vector<int> quantities;
5624 bool allTransformed = true;
5625 int nbFaces = aPolyedre->NbFaces();
5626 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5627 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5628 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5629 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5630 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5631 if (nodeMapIt == nodeMap.end()) {
5632 allTransformed = false; // not all nodes transformed
5634 poly_nodes.push_back((*nodeMapIt).second);
5637 quantities.push_back(nbFaceNodes);
5639 if ( !allTransformed )
5640 continue; // not all nodes transformed
5642 if ( theTargetMesh ) {
5643 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5644 srcElems.Append( elem );
5646 else if ( theCopy ) {
5647 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5648 srcElems.Append( elem );
5651 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5661 int* i = index[ FORWARD ];
5662 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5663 // if ( elemType == SMDSAbs_Face )
5664 // i = index[ REV_FACE ];
5666 // i = index[ nbNodes - 4 ];
5668 if(elem->IsQuadratic()) {
5669 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5672 // if(nbNodes==3) { // quadratic edge
5673 // static int anIds[] = {1,0,2};
5676 // else if(nbNodes==6) { // quadratic triangle
5677 // static int anIds[] = {0,2,1,5,4,3};
5680 // else if(nbNodes==8) { // quadratic quadrangle
5681 // static int anIds[] = {0,3,2,1,7,6,5,4};
5684 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5685 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5688 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5689 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5692 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5693 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5696 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5697 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5703 // find transformed nodes
5704 vector<const SMDS_MeshNode*> nodes(nbNodes);
5706 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5707 while ( itN->more() ) {
5708 const SMDS_MeshNode* node =
5709 static_cast<const SMDS_MeshNode*>( itN->next() );
5710 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5711 if ( nodeMapIt == nodeMap.end() )
5712 break; // not all nodes transformed
5713 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5715 if ( iNode != nbNodes )
5716 continue; // not all nodes transformed
5718 if ( theTargetMesh ) {
5719 if ( SMDS_MeshElement* copy =
5720 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5721 myLastCreatedElems.Append( copy );
5722 srcElems.Append( elem );
5725 else if ( theCopy ) {
5726 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5727 myLastCreatedElems.Append( copy );
5728 srcElems.Append( elem );
5732 // reverse element as it was reversed by transformation
5734 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5738 PGroupIDs newGroupIDs;
5740 if ( theMakeGroups && theCopy ||
5741 theMakeGroups && theTargetMesh ) {
5742 string groupPostfix = "scaled";
5743 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5750 //=======================================================================
5752 * \brief Create groups of elements made during transformation
5753 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5754 * \param elemGens - elements making corresponding myLastCreatedElems
5755 * \param postfix - to append to names of new groups
5757 //=======================================================================
5759 SMESH_MeshEditor::PGroupIDs
5760 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5761 const SMESH_SequenceOfElemPtr& elemGens,
5762 const std::string& postfix,
5763 SMESH_Mesh* targetMesh)
5765 PGroupIDs newGroupIDs( new list<int> );
5766 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5768 // Sort existing groups by types and collect their names
5770 // to store an old group and a generated new one
5771 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5772 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5774 set< string > groupNames;
5776 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5777 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5778 while ( groupIt->more() ) {
5779 SMESH_Group * group = groupIt->next();
5780 if ( !group ) continue;
5781 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5782 if ( !groupDS || groupDS->IsEmpty() ) continue;
5783 groupNames.insert( group->GetName() );
5784 groupDS->SetStoreName( group->GetName() );
5785 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5790 // loop on nodes and elements
5791 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5793 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5794 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5795 if ( gens.Length() != elems.Length() )
5796 throw SALOME_Exception(LOCALIZED("invalid args"));
5798 // loop on created elements
5799 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5801 const SMDS_MeshElement* sourceElem = gens( iElem );
5802 if ( !sourceElem ) {
5803 MESSAGE("generateGroups(): NULL source element");
5806 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5807 if ( groupsOldNew.empty() ) {
5808 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5809 ++iElem; // skip all elements made by sourceElem
5812 // collect all elements made by sourceElem
5813 list< const SMDS_MeshElement* > resultElems;
5814 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5815 if ( resElem != sourceElem )
5816 resultElems.push_back( resElem );
5817 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5818 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5819 if ( resElem != sourceElem )
5820 resultElems.push_back( resElem );
5821 // do not generate element groups from node ones
5822 if ( sourceElem->GetType() == SMDSAbs_Node &&
5823 elems( iElem )->GetType() != SMDSAbs_Node )
5826 // add resultElems to groups made by ones the sourceElem belongs to
5827 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5828 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5830 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5831 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5833 SMDS_MeshGroup* & newGroup = gOldNew->second;
5834 if ( !newGroup )// create a new group
5837 string name = oldGroup->GetStoreName();
5838 if ( !targetMesh ) {
5842 while ( !groupNames.insert( name ).second ) // name exists
5848 TCollection_AsciiString nbStr(nb+1);
5849 name.resize( name.rfind('_')+1 );
5850 name += nbStr.ToCString();
5857 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5859 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5860 newGroup = & groupDS->SMDSGroup();
5861 newGroupIDs->push_back( id );
5864 // fill in a new group
5865 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5866 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5867 newGroup->Add( *resElemIt );
5870 } // loop on created elements
5871 }// loop on nodes and elements
5876 //================================================================================
5878 * \brief Return list of group of nodes close to each other within theTolerance
5879 * Search among theNodes or in the whole mesh if theNodes is empty using
5880 * an Octree algorithm
5882 //================================================================================
5884 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5885 const double theTolerance,
5886 TListOfListOfNodes & theGroupsOfNodes)
5888 myLastCreatedElems.Clear();
5889 myLastCreatedNodes.Clear();
5891 set<const SMDS_MeshNode*> nodes;
5892 if ( theNodes.empty() )
5893 { // get all nodes in the mesh
5894 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5895 while ( nIt->more() )
5896 nodes.insert( nodes.end(),nIt->next());
5901 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5905 //=======================================================================
5907 * \brief Implementation of search for the node closest to point
5909 //=======================================================================
5911 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5913 //---------------------------------------------------------------------
5915 * \brief Constructor
5917 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5919 myMesh = ( SMESHDS_Mesh* ) theMesh;
5921 set<const SMDS_MeshNode*> nodes;
5923 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5924 while ( nIt->more() )
5925 nodes.insert( nodes.end(), nIt->next() );
5927 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5929 // get max size of a leaf box
5930 SMESH_OctreeNode* tree = myOctreeNode;
5931 while ( !tree->isLeaf() )
5933 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5937 myHalfLeafSize = tree->maxSize() / 2.;
5940 //---------------------------------------------------------------------
5942 * \brief Move node and update myOctreeNode accordingly
5944 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5946 myOctreeNode->UpdateByMoveNode( node, toPnt );
5947 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5950 //---------------------------------------------------------------------
5952 * \brief Do it's job
5954 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5956 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5957 map<double, const SMDS_MeshNode*> dist2Nodes;
5958 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5959 if ( !dist2Nodes.empty() )
5960 return dist2Nodes.begin()->second;
5961 list<const SMDS_MeshNode*> nodes;
5962 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5964 double minSqDist = DBL_MAX;
5965 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5967 // sort leafs by their distance from thePnt
5968 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5969 TDistTreeMap treeMap;
5970 list< SMESH_OctreeNode* > treeList;
5971 list< SMESH_OctreeNode* >::iterator trIt;
5972 treeList.push_back( myOctreeNode );
5974 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5975 bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5976 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5978 SMESH_OctreeNode* tree = *trIt;
5979 if ( !tree->isLeaf() ) // put children to the queue
5981 if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5982 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5983 while ( cIt->more() )
5984 treeList.push_back( cIt->next() );
5986 else if ( tree->NbNodes() ) // put a tree to the treeMap
5988 const Bnd_B3d& box = tree->getBox();
5989 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5990 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5991 if ( !it_in.second ) // not unique distance to box center
5992 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5995 // find distance after which there is no sense to check tree's
5996 double sqLimit = DBL_MAX;
5997 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5998 if ( treeMap.size() > 5 ) {
5999 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6000 const Bnd_B3d& box = closestTree->getBox();
6001 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6002 sqLimit = limit * limit;
6004 // get all nodes from trees
6005 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6006 if ( sqDist_tree->first > sqLimit )
6008 SMESH_OctreeNode* tree = sqDist_tree->second;
6009 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6012 // find closest among nodes
6013 minSqDist = DBL_MAX;
6014 const SMDS_MeshNode* closestNode = 0;
6015 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6016 for ( ; nIt != nodes.end(); ++nIt ) {
6017 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6018 if ( minSqDist > sqDist ) {
6026 //---------------------------------------------------------------------
6030 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6032 //---------------------------------------------------------------------
6034 * \brief Return the node tree
6036 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6039 SMESH_OctreeNode* myOctreeNode;
6040 SMESHDS_Mesh* myMesh;
6041 double myHalfLeafSize; // max size of a leaf box
6044 //=======================================================================
6046 * \brief Return SMESH_NodeSearcher
6048 //=======================================================================
6050 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6052 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6055 // ========================================================================
6056 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6058 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6059 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6060 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6062 //=======================================================================
6064 * \brief Octal tree of bounding boxes of elements
6066 //=======================================================================
6068 class ElementBndBoxTree : public SMESH_Octree
6072 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
6073 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6074 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6075 ~ElementBndBoxTree();
6078 ElementBndBoxTree() {}
6079 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6080 void buildChildrenData();
6081 Bnd_B3d* buildRootBox();
6083 //!< Bounding box of element
6084 struct ElementBox : public Bnd_B3d
6086 const SMDS_MeshElement* _element;
6087 int _refCount; // an ElementBox can be included in several tree branches
6088 ElementBox(const SMDS_MeshElement* elem);
6090 vector< ElementBox* > _elements;
6093 //================================================================================
6095 * \brief ElementBndBoxTree creation
6097 //================================================================================
6099 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
6100 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6102 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6103 _elements.reserve( nbElems );
6105 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6106 while ( elemIt->more() )
6107 _elements.push_back( new ElementBox( elemIt->next() ));
6109 if ( _elements.size() > MaxNbElemsInLeaf )
6115 //================================================================================
6119 //================================================================================
6121 ElementBndBoxTree::~ElementBndBoxTree()
6123 for ( int i = 0; i < _elements.size(); ++i )
6124 if ( --_elements[i]->_refCount <= 0 )
6125 delete _elements[i];
6128 //================================================================================
6130 * \brief Return the maximal box
6132 //================================================================================
6134 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6136 Bnd_B3d* box = new Bnd_B3d;
6137 for ( int i = 0; i < _elements.size(); ++i )
6138 box->Add( *_elements[i] );
6142 //================================================================================
6144 * \brief Redistrubute element boxes among children
6146 //================================================================================
6148 void ElementBndBoxTree::buildChildrenData()
6150 for ( int i = 0; i < _elements.size(); ++i )
6152 for (int j = 0; j < 8; j++)
6154 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6156 _elements[i]->_refCount++;
6157 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6160 _elements[i]->_refCount--;
6164 for (int j = 0; j < 8; j++)
6166 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6167 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6168 child->myIsLeaf = true;
6170 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6171 child->_elements.resize( child->_elements.size() ); // compact
6175 //================================================================================
6177 * \brief Return elements which can include the point
6179 //================================================================================
6181 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6182 TIDSortedElemSet& foundElems)
6184 if ( level() && getBox().IsOut( point.XYZ() ))
6189 for ( int i = 0; i < _elements.size(); ++i )
6190 if ( !_elements[i]->IsOut( point.XYZ() ))
6191 foundElems.insert( _elements[i]->_element );
6195 for (int i = 0; i < 8; i++)
6196 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6200 //================================================================================
6202 * \brief Return elements which can be intersected by the line
6204 //================================================================================
6206 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6207 TIDSortedElemSet& foundElems)
6209 if ( level() && getBox().IsOut( line ))
6214 for ( int i = 0; i < _elements.size(); ++i )
6215 if ( !_elements[i]->IsOut( line ))
6216 foundElems.insert( _elements[i]->_element );
6220 for (int i = 0; i < 8; i++)
6221 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6225 //================================================================================
6227 * \brief Construct the element box
6229 //================================================================================
6231 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
6235 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6236 while ( nIt->more() )
6237 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6238 Enlarge( NodeRadius );
6243 //=======================================================================
6245 * \brief Implementation of search for the elements by point and
6246 * of classification of point in 2D mesh
6248 //=======================================================================
6250 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6252 SMESHDS_Mesh* _mesh;
6253 ElementBndBoxTree* _ebbTree;
6254 SMESH_NodeSearcherImpl* _nodeSearcher;
6255 SMDSAbs_ElementType _elementType;
6257 bool _outerFacesFound;
6258 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6260 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6261 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6262 ~SMESH_ElementSearcherImpl()
6264 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6265 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6267 virtual int FindElementsByPoint(const gp_Pnt& point,
6268 SMDSAbs_ElementType type,
6269 vector< const SMDS_MeshElement* >& foundElements);
6270 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6272 double getTolerance();
6273 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6274 const double tolerance, double & param);
6275 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6276 bool isOuterBoundary(const SMDS_MeshElement* face) const
6278 return _outerFaces.empty() || _outerFaces.count(face);
6280 struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
6282 const SMDS_MeshElement* _face;
6284 bool _coincides; //!< the line lays in face plane
6285 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6286 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6288 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6291 TIDSortedElemSet _faces;
6292 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6293 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6297 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6299 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6300 << ", _coincides="<<i._coincides << ")";
6303 //=======================================================================
6305 * \brief define tolerance for search
6307 //=======================================================================
6309 double SMESH_ElementSearcherImpl::getTolerance()
6311 if ( _tolerance < 0 )
6313 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6316 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6318 double boxSize = _nodeSearcher->getTree()->maxSize();
6319 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6321 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6323 double boxSize = _ebbTree->maxSize();
6324 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6326 if ( _tolerance == 0 )
6328 // define tolerance by size of a most complex element
6329 int complexType = SMDSAbs_Volume;
6330 while ( complexType > SMDSAbs_All &&
6331 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6333 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6336 if ( complexType == int( SMDSAbs_Node ))
6338 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6340 if ( meshInfo.NbNodes() > 2 )
6341 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6345 const SMDS_MeshElement* elem =
6346 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6347 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6348 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6349 while ( nodeIt->more() )
6351 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6352 elemSize = max( dist, elemSize );
6355 _tolerance = 1e-6 * elemSize;
6361 //================================================================================
6363 * \brief Find intersection of the line and an edge of face and return parameter on line
6365 //================================================================================
6367 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6368 const SMDS_MeshElement* face,
6375 GeomAPI_ExtremaCurveCurve anExtCC;
6376 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6378 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6379 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6381 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6382 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6383 anExtCC.Init( lineCurve, edge);
6384 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6386 Quantity_Parameter pl, pe;
6387 anExtCC.LowerDistanceParameters( pl, pe );
6389 if ( ++nbInts == 2 )
6393 if ( nbInts > 0 ) param /= nbInts;
6396 //================================================================================
6398 * \brief Find all faces belonging to the outer boundary of mesh
6400 //================================================================================
6402 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6404 if ( _outerFacesFound ) return;
6406 // Collect all outer faces by passing from one outer face to another via their links
6407 // and BTW find out if there are internal faces at all.
6409 // checked links and links where outer boundary meets internal one
6410 set< SMESH_TLink > visitedLinks, seamLinks;
6412 // links to treat with already visited faces sharing them
6413 list < TFaceLink > startLinks;
6415 // load startLinks with the first outerFace
6416 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6417 _outerFaces.insert( outerFace );
6419 TIDSortedElemSet emptySet;
6420 while ( !startLinks.empty() )
6422 const SMESH_TLink& link = startLinks.front()._link;
6423 TIDSortedElemSet& faces = startLinks.front()._faces;
6425 outerFace = *faces.begin();
6426 // find other faces sharing the link
6427 const SMDS_MeshElement* f;
6428 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6431 // select another outer face among the found
6432 const SMDS_MeshElement* outerFace2 = 0;
6433 if ( faces.size() == 2 )
6435 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6437 else if ( faces.size() > 2 )
6439 seamLinks.insert( link );
6441 // link direction within the outerFace
6442 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6443 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6444 int i1 = outerFace->GetNodeIndex( link.node1() );
6445 int i2 = outerFace->GetNodeIndex( link.node2() );
6446 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6447 if ( rev ) n1n2.Reverse();
6449 gp_XYZ ofNorm, fNorm;
6450 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6452 // direction from the link inside outerFace
6453 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6454 // sort all other faces by angle with the dirInOF
6455 map< double, const SMDS_MeshElement* > angle2Face;
6456 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6457 for ( ; face != faces.end(); ++face )
6459 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6461 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6462 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6463 if ( angle < 0 ) angle += 2*PI;
6464 angle2Face.insert( make_pair( angle, *face ));
6466 if ( !angle2Face.empty() )
6467 outerFace2 = angle2Face.begin()->second;
6470 // store the found outer face and add its links to continue seaching from
6473 _outerFaces.insert( outerFace );
6474 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6475 for ( int i = 0; i < nbNodes; ++i )
6477 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6478 if ( visitedLinks.insert( link2 ).second )
6479 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6482 startLinks.pop_front();
6484 _outerFacesFound = true;
6486 if ( !seamLinks.empty() )
6488 // There are internal boundaries touching the outher one,
6489 // find all faces of internal boundaries in order to find
6490 // faces of boundaries of holes, if any.
6495 _outerFaces.clear();
6499 //=======================================================================
6501 * \brief Find elements of given type where the given point is IN or ON.
6502 * Returns nb of found elements and elements them-selves.
6504 * 'ALL' type means elements of any type excluding nodes and 0D elements
6506 //=======================================================================
6508 int SMESH_ElementSearcherImpl::
6509 FindElementsByPoint(const gp_Pnt& point,
6510 SMDSAbs_ElementType type,
6511 vector< const SMDS_MeshElement* >& foundElements)
6513 foundElements.clear();
6515 double tolerance = getTolerance();
6517 // =================================================================================
6518 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6520 if ( !_nodeSearcher )
6521 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6523 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6524 if ( !closeNode ) return foundElements.size();
6526 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6527 return foundElements.size(); // to far from any node
6529 if ( type == SMDSAbs_Node )
6531 foundElements.push_back( closeNode );
6535 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6536 while ( elemIt->more() )
6537 foundElements.push_back( elemIt->next() );
6540 // =================================================================================
6541 else // elements more complex than 0D
6543 if ( !_ebbTree || _elementType != type )
6545 if ( _ebbTree ) delete _ebbTree;
6546 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6548 TIDSortedElemSet suspectElems;
6549 _ebbTree->getElementsNearPoint( point, suspectElems );
6550 TIDSortedElemSet::iterator elem = suspectElems.begin();
6551 for ( ; elem != suspectElems.end(); ++elem )
6552 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6553 foundElements.push_back( *elem );
6555 return foundElements.size();
6558 //================================================================================
6560 * \brief Classify the given point in the closed 2D mesh
6562 //================================================================================
6564 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6566 double tolerance = getTolerance();
6567 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6569 if ( _ebbTree ) delete _ebbTree;
6570 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6572 // Algo: analyse transition of a line starting at the point through mesh boundary;
6573 // try three lines parallel to axis of the coordinate system and perform rough
6574 // analysis. If solution is not clear perform thorough analysis.
6576 const int nbAxes = 3;
6577 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6578 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6579 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6580 multimap< int, int > nbInt2Axis; // to find the simplest case
6581 for ( int axis = 0; axis < nbAxes; ++axis )
6583 gp_Ax1 lineAxis( point, axisDir[axis]);
6584 gp_Lin line ( lineAxis );
6586 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6587 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6589 // Intersect faces with the line
6591 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6592 TIDSortedElemSet::iterator face = suspectFaces.begin();
6593 for ( ; face != suspectFaces.end(); ++face )
6597 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6598 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6600 // perform intersection
6601 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6602 if ( !intersection.IsDone() )
6604 if ( intersection.IsInQuadric() )
6606 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6608 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6610 gp_Pnt intersectionPoint = intersection.Point(1);
6611 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6612 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6615 // Analyse intersections roughly
6617 int nbInter = u2inters.size();
6621 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6622 if ( nbInter == 1 ) // not closed mesh
6623 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6625 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6628 if ( (f<0) == (l<0) )
6631 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6632 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6633 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6636 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6638 if ( _outerFacesFound ) break; // pass to thorough analysis
6640 } // three attempts - loop on CS axes
6642 // Analyse intersections thoroughly.
6643 // We make two loops maximum, on the first one we only exclude touching intersections,
6644 // on the second, if situation is still unclear, we gather and use information on
6645 // position of faces (internal or outer). If faces position is already gathered,
6646 // we make the second loop right away.
6648 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6650 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6651 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6653 int axis = nb_axis->second;
6654 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6656 gp_Ax1 lineAxis( point, axisDir[axis]);
6657 gp_Lin line ( lineAxis );
6659 // add tangent intersections to u2inters
6661 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6662 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6663 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6664 u2inters.insert(make_pair( param, *tgtInt ));
6665 tangentInters[ axis ].clear();
6667 // Count intersections before and after the point excluding touching ones.
6668 // If hasPositionInfo we count intersections of outer boundary only
6670 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6671 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6672 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6673 bool ok = ! u_int1->second._coincides;
6674 while ( ok && u_int1 != u2inters.end() )
6676 double u = u_int1->first;
6677 bool touchingInt = false;
6678 if ( ++u_int2 != u2inters.end() )
6680 // skip intersections at the same point (if the line passes through edge or node)
6682 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6688 // skip tangent intersections
6690 const SMDS_MeshElement* prevFace = u_int1->second._face;
6691 while ( ok && u_int2->second._coincides )
6693 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6699 ok = ( u_int2 != u2inters.end() );
6704 // skip intersections at the same point after tangent intersections
6707 double u2 = u_int2->first;
6709 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6715 // decide if we skipped a touching intersection
6716 if ( nbSamePnt + nbTgt > 0 )
6718 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6719 map< double, TInters >::iterator u_int = u_int1;
6720 for ( ; u_int != u_int2; ++u_int )
6722 if ( u_int->second._coincides ) continue;
6723 double dot = u_int->second._faceNorm * line.Direction();
6724 if ( dot > maxDot ) maxDot = dot;
6725 if ( dot < minDot ) minDot = dot;
6727 touchingInt = ( minDot*maxDot < 0 );
6732 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6743 u_int1 = u_int2; // to next intersection
6745 } // loop on intersections with one line
6749 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6752 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6755 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6756 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6758 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6761 if ( (f<0) == (l<0) )
6764 if ( hasPositionInfo )
6765 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6767 } // loop on intersections of the tree lines - thorough analysis
6769 if ( !hasPositionInfo )
6771 // gather info on faces position - is face in the outer boundary or not
6772 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6773 findOuterBoundary( u2inters.begin()->second._face );
6776 } // two attempts - with and w/o faces position info in the mesh
6778 return TopAbs_UNKNOWN;
6781 //=======================================================================
6783 * \brief Return SMESH_ElementSearcher
6785 //=======================================================================
6787 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6789 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6792 //=======================================================================
6794 * \brief Return true if the point is IN or ON of the element
6796 //=======================================================================
6798 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6800 if ( element->GetType() == SMDSAbs_Volume)
6802 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6805 // get ordered nodes
6807 vector< gp_XYZ > xyz;
6809 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6810 if ( element->IsQuadratic() )
6811 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6812 nodeIt = f->interlacedNodesElemIterator();
6813 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6814 nodeIt = e->interlacedNodesElemIterator();
6816 while ( nodeIt->more() )
6817 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6819 int i, nbNodes = element->NbNodes();
6821 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6823 // compute face normal
6824 gp_Vec faceNorm(0,0,0);
6825 xyz.push_back( xyz.front() );
6826 for ( i = 0; i < nbNodes; ++i )
6828 gp_Vec edge1( xyz[i+1], xyz[i]);
6829 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6830 faceNorm += edge1 ^ edge2;
6832 double normSize = faceNorm.Magnitude();
6833 if ( normSize <= tol )
6835 // degenerated face: point is out if it is out of all face edges
6836 for ( i = 0; i < nbNodes; ++i )
6838 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6839 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6840 SMDS_MeshEdge edge( &n1, &n2 );
6841 if ( !isOut( &edge, point, tol ))
6846 faceNorm /= normSize;
6848 // check if the point lays on face plane
6849 gp_Vec n2p( xyz[0], point );
6850 if ( fabs( n2p * faceNorm ) > tol )
6851 return true; // not on face plane
6853 // check if point is out of face boundary:
6854 // define it by closest transition of a ray point->infinity through face boundary
6855 // on the face plane.
6856 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6857 // to find intersections of the ray with the boundary.
6859 gp_Vec plnNorm = ray ^ faceNorm;
6860 normSize = plnNorm.Magnitude();
6861 if ( normSize <= tol ) return false; // point coincides with the first node
6862 plnNorm /= normSize;
6863 // for each node of the face, compute its signed distance to the plane
6864 vector<double> dist( nbNodes + 1);
6865 for ( i = 0; i < nbNodes; ++i )
6867 gp_Vec n2p( xyz[i], point );
6868 dist[i] = n2p * plnNorm;
6870 dist.back() = dist.front();
6871 // find the closest intersection
6873 double rClosest, distClosest = 1e100;;
6875 for ( i = 0; i < nbNodes; ++i )
6878 if ( fabs( dist[i]) < tol )
6880 else if ( fabs( dist[i+1]) < tol )
6882 else if ( dist[i] * dist[i+1] < 0 )
6883 r = dist[i] / ( dist[i] - dist[i+1] );
6885 continue; // no intersection
6886 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6887 gp_Vec p2int ( point, pInt);
6888 if ( p2int * ray > -tol ) // right half-space
6890 double intDist = p2int.SquareMagnitude();
6891 if ( intDist < distClosest )
6896 distClosest = intDist;
6901 return true; // no intesections - out
6903 // analyse transition
6904 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6905 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6906 gp_Vec p2int ( point, pClosest );
6907 bool out = (edgeNorm * p2int) < -tol;
6908 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6911 // ray pass through a face node; analyze transition through an adjacent edge
6912 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6913 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6914 gp_Vec edgeAdjacent( p1, p2 );
6915 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6916 bool out2 = (edgeNorm2 * p2int) < -tol;
6918 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6919 return covexCorner ? (out || out2) : (out && out2);
6921 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6923 // point is out of edge if it is NOT ON any straight part of edge
6924 // (we consider quadratic edge as being composed of two straight parts)
6925 for ( i = 1; i < nbNodes; ++i )
6927 gp_Vec edge( xyz[i-1], xyz[i]);
6928 gp_Vec n1p ( xyz[i-1], point);
6929 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6932 gp_Vec n2p( xyz[i], point );
6933 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6935 return false; // point is ON this part
6939 // Node or 0D element -------------------------------------------------------------------------
6941 gp_Vec n2p ( xyz[0], point );
6942 return n2p.Magnitude() <= tol;
6947 //=======================================================================
6948 //function : SimplifyFace
6950 //=======================================================================
6951 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6952 vector<const SMDS_MeshNode *>& poly_nodes,
6953 vector<int>& quantities) const
6955 int nbNodes = faceNodes.size();
6960 set<const SMDS_MeshNode*> nodeSet;
6962 // get simple seq of nodes
6963 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6964 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6965 int iSimple = 0, nbUnique = 0;
6967 simpleNodes[iSimple++] = faceNodes[0];
6969 for (int iCur = 1; iCur < nbNodes; iCur++) {
6970 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6971 simpleNodes[iSimple++] = faceNodes[iCur];
6972 if (nodeSet.insert( faceNodes[iCur] ).second)
6976 int nbSimple = iSimple;
6977 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6987 bool foundLoop = (nbSimple > nbUnique);
6990 set<const SMDS_MeshNode*> loopSet;
6991 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6992 const SMDS_MeshNode* n = simpleNodes[iSimple];
6993 if (!loopSet.insert( n ).second) {
6997 int iC = 0, curLast = iSimple;
6998 for (; iC < curLast; iC++) {
6999 if (simpleNodes[iC] == n) break;
7001 int loopLen = curLast - iC;
7003 // create sub-element
7005 quantities.push_back(loopLen);
7006 for (; iC < curLast; iC++) {
7007 poly_nodes.push_back(simpleNodes[iC]);
7010 // shift the rest nodes (place from the first loop position)
7011 for (iC = curLast + 1; iC < nbSimple; iC++) {
7012 simpleNodes[iC - loopLen] = simpleNodes[iC];
7014 nbSimple -= loopLen;
7017 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7018 } // while (foundLoop)
7022 quantities.push_back(iSimple);
7023 for (int i = 0; i < iSimple; i++)
7024 poly_nodes.push_back(simpleNodes[i]);
7030 //=======================================================================
7031 //function : MergeNodes
7032 //purpose : In each group, the cdr of nodes are substituted by the first one
7034 //=======================================================================
7036 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7038 myLastCreatedElems.Clear();
7039 myLastCreatedNodes.Clear();
7041 SMESHDS_Mesh* aMesh = GetMeshDS();
7043 TNodeNodeMap nodeNodeMap; // node to replace - new node
7044 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7045 list< int > rmElemIds, rmNodeIds;
7047 // Fill nodeNodeMap and elems
7049 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7050 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7051 list<const SMDS_MeshNode*>& nodes = *grIt;
7052 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7053 const SMDS_MeshNode* nToKeep = *nIt;
7054 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7055 const SMDS_MeshNode* nToRemove = *nIt;
7056 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7057 if ( nToRemove != nToKeep ) {
7058 rmNodeIds.push_back( nToRemove->GetID() );
7059 AddToSameGroups( nToKeep, nToRemove, aMesh );
7062 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7063 while ( invElemIt->more() ) {
7064 const SMDS_MeshElement* elem = invElemIt->next();
7069 // Change element nodes or remove an element
7071 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7072 for ( ; eIt != elems.end(); eIt++ ) {
7073 const SMDS_MeshElement* elem = *eIt;
7074 int nbNodes = elem->NbNodes();
7075 int aShapeId = FindShape( elem );
7077 set<const SMDS_MeshNode*> nodeSet;
7078 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7079 int iUnique = 0, iCur = 0, nbRepl = 0;
7080 vector<int> iRepl( nbNodes );
7082 // get new seq of nodes
7083 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7084 while ( itN->more() ) {
7085 const SMDS_MeshNode* n =
7086 static_cast<const SMDS_MeshNode*>( itN->next() );
7088 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7089 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7091 // BUG 0020185: begin
7093 bool stopRecur = false;
7094 set<const SMDS_MeshNode*> nodesRecur;
7095 nodesRecur.insert(n);
7096 while (!stopRecur) {
7097 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7098 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7099 n = (*nnIt_i).second;
7100 if (!nodesRecur.insert(n).second) {
7101 // error: recursive dependancy
7110 iRepl[ nbRepl++ ] = iCur;
7112 curNodes[ iCur ] = n;
7113 bool isUnique = nodeSet.insert( n ).second;
7115 uniqueNodes[ iUnique++ ] = n;
7119 // Analyse element topology after replacement
7122 int nbUniqueNodes = nodeSet.size();
7123 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7124 // Polygons and Polyhedral volumes
7125 if (elem->IsPoly()) {
7127 if (elem->GetType() == SMDSAbs_Face) {
7129 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7131 for (; inode < nbNodes; inode++) {
7132 face_nodes[inode] = curNodes[inode];
7135 vector<const SMDS_MeshNode *> polygons_nodes;
7136 vector<int> quantities;
7137 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7141 for (int iface = 0; iface < nbNew - 1; iface++) {
7142 int nbNodes = quantities[iface];
7143 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7144 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7145 poly_nodes[ii] = polygons_nodes[inode];
7147 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7148 myLastCreatedElems.Append(newElem);
7150 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7152 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7155 rmElemIds.push_back(elem->GetID());
7159 else if (elem->GetType() == SMDSAbs_Volume) {
7160 // Polyhedral volume
7161 if (nbUniqueNodes < 4) {
7162 rmElemIds.push_back(elem->GetID());
7165 // each face has to be analized in order to check volume validity
7166 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7167 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7169 int nbFaces = aPolyedre->NbFaces();
7171 vector<const SMDS_MeshNode *> poly_nodes;
7172 vector<int> quantities;
7174 for (int iface = 1; iface <= nbFaces; iface++) {
7175 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7176 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7178 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7179 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7180 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7181 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7182 faceNode = (*nnIt).second;
7184 faceNodes[inode - 1] = faceNode;
7187 SimplifyFace(faceNodes, poly_nodes, quantities);
7190 if (quantities.size() > 3) {
7191 // to be done: remove coincident faces
7194 if (quantities.size() > 3)
7195 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7197 rmElemIds.push_back(elem->GetID());
7201 rmElemIds.push_back(elem->GetID());
7212 switch ( nbNodes ) {
7213 case 2: ///////////////////////////////////// EDGE
7214 isOk = false; break;
7215 case 3: ///////////////////////////////////// TRIANGLE
7216 isOk = false; break;
7218 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7220 else { //////////////////////////////////// QUADRANGLE
7221 if ( nbUniqueNodes < 3 )
7223 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7224 isOk = false; // opposite nodes stick
7227 case 6: ///////////////////////////////////// PENTAHEDRON
7228 if ( nbUniqueNodes == 4 ) {
7229 // ---------------------------------> tetrahedron
7231 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7232 // all top nodes stick: reverse a bottom
7233 uniqueNodes[ 0 ] = curNodes [ 1 ];
7234 uniqueNodes[ 1 ] = curNodes [ 0 ];
7236 else if (nbRepl == 3 &&
7237 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7238 // all bottom nodes stick: set a top before
7239 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7240 uniqueNodes[ 0 ] = curNodes [ 3 ];
7241 uniqueNodes[ 1 ] = curNodes [ 4 ];
7242 uniqueNodes[ 2 ] = curNodes [ 5 ];
7244 else if (nbRepl == 4 &&
7245 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7246 // a lateral face turns into a line: reverse a bottom
7247 uniqueNodes[ 0 ] = curNodes [ 1 ];
7248 uniqueNodes[ 1 ] = curNodes [ 0 ];
7253 else if ( nbUniqueNodes == 5 ) {
7254 // PENTAHEDRON --------------------> 2 tetrahedrons
7255 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7256 // a bottom node sticks with a linked top one
7258 SMDS_MeshElement* newElem =
7259 aMesh->AddVolume(curNodes[ 3 ],
7262 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7263 myLastCreatedElems.Append(newElem);
7265 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7266 // 2. : reverse a bottom
7267 uniqueNodes[ 0 ] = curNodes [ 1 ];
7268 uniqueNodes[ 1 ] = curNodes [ 0 ];
7278 if(elem->IsQuadratic()) { // Quadratic quadrangle
7291 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7292 uniqueNodes[0] = curNodes[0];
7293 uniqueNodes[1] = curNodes[2];
7294 uniqueNodes[2] = curNodes[3];
7295 uniqueNodes[3] = curNodes[5];
7296 uniqueNodes[4] = curNodes[6];
7297 uniqueNodes[5] = curNodes[7];
7300 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7301 uniqueNodes[0] = curNodes[0];
7302 uniqueNodes[1] = curNodes[1];
7303 uniqueNodes[2] = curNodes[2];
7304 uniqueNodes[3] = curNodes[4];
7305 uniqueNodes[4] = curNodes[5];
7306 uniqueNodes[5] = curNodes[6];
7309 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7310 uniqueNodes[0] = curNodes[1];
7311 uniqueNodes[1] = curNodes[2];
7312 uniqueNodes[2] = curNodes[3];
7313 uniqueNodes[3] = curNodes[5];
7314 uniqueNodes[4] = curNodes[6];
7315 uniqueNodes[5] = curNodes[0];
7318 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7319 uniqueNodes[0] = curNodes[0];
7320 uniqueNodes[1] = curNodes[1];
7321 uniqueNodes[2] = curNodes[3];
7322 uniqueNodes[3] = curNodes[4];
7323 uniqueNodes[4] = curNodes[6];
7324 uniqueNodes[5] = curNodes[7];
7327 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7328 uniqueNodes[0] = curNodes[0];
7329 uniqueNodes[1] = curNodes[2];
7330 uniqueNodes[2] = curNodes[3];
7331 uniqueNodes[3] = curNodes[1];
7332 uniqueNodes[4] = curNodes[6];
7333 uniqueNodes[5] = curNodes[7];
7336 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7337 uniqueNodes[0] = curNodes[0];
7338 uniqueNodes[1] = curNodes[1];
7339 uniqueNodes[2] = curNodes[2];
7340 uniqueNodes[3] = curNodes[4];
7341 uniqueNodes[4] = curNodes[5];
7342 uniqueNodes[5] = curNodes[7];
7345 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7346 uniqueNodes[0] = curNodes[0];
7347 uniqueNodes[1] = curNodes[1];
7348 uniqueNodes[2] = curNodes[3];
7349 uniqueNodes[3] = curNodes[4];
7350 uniqueNodes[4] = curNodes[2];
7351 uniqueNodes[5] = curNodes[7];
7354 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7355 uniqueNodes[0] = curNodes[0];
7356 uniqueNodes[1] = curNodes[1];
7357 uniqueNodes[2] = curNodes[2];
7358 uniqueNodes[3] = curNodes[4];
7359 uniqueNodes[4] = curNodes[5];
7360 uniqueNodes[5] = curNodes[3];
7366 //////////////////////////////////// HEXAHEDRON
7368 SMDS_VolumeTool hexa (elem);
7369 hexa.SetExternalNormal();
7370 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7371 //////////////////////// ---> tetrahedron
7372 for ( int iFace = 0; iFace < 6; iFace++ ) {
7373 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7374 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7375 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7376 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7377 // one face turns into a point ...
7378 int iOppFace = hexa.GetOppFaceIndex( iFace );
7379 ind = hexa.GetFaceNodesIndices( iOppFace );
7381 iUnique = 2; // reverse a tetrahedron bottom
7382 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7383 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7385 else if ( iUnique >= 0 )
7386 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7388 if ( nbStick == 1 ) {
7389 // ... and the opposite one - into a triangle.
7391 ind = hexa.GetFaceNodesIndices( iFace );
7392 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7399 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7400 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7401 for ( int iFace = 0; iFace < 6; iFace++ ) {
7402 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7403 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7404 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7405 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7406 // one face turns into a point ...
7407 int iOppFace = hexa.GetOppFaceIndex( iFace );
7408 ind = hexa.GetFaceNodesIndices( iOppFace );
7410 iUnique = 2; // reverse a tetrahedron 1 bottom
7411 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7412 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7414 else if ( iUnique >= 0 )
7415 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7417 if ( nbStick == 0 ) {
7418 // ... and the opposite one is a quadrangle
7420 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7421 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7424 SMDS_MeshElement* newElem =
7425 aMesh->AddVolume(curNodes[ind[ 0 ]],
7428 curNodes[indTop[ 0 ]]);
7429 myLastCreatedElems.Append(newElem);
7431 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7438 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7439 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7440 // find indices of quad and tri faces
7441 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7442 for ( iFace = 0; iFace < 6; iFace++ ) {
7443 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7445 for ( iCur = 0; iCur < 4; iCur++ )
7446 nodeSet.insert( curNodes[ind[ iCur ]] );
7447 nbUniqueNodes = nodeSet.size();
7448 if ( nbUniqueNodes == 3 )
7449 iTriFace[ nbTri++ ] = iFace;
7450 else if ( nbUniqueNodes == 4 )
7451 iQuadFace[ nbQuad++ ] = iFace;
7453 if (nbQuad == 2 && nbTri == 4 &&
7454 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7455 // 2 opposite quadrangles stuck with a diagonal;
7456 // sample groups of merged indices: (0-4)(2-6)
7457 // --------------------------------------------> 2 tetrahedrons
7458 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7459 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7460 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7461 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7462 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7463 // stuck with 0-2 diagonal
7471 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7472 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7473 // stuck with 1-3 diagonal
7485 uniqueNodes[ 0 ] = curNodes [ i0 ];
7486 uniqueNodes[ 1 ] = curNodes [ i1d ];
7487 uniqueNodes[ 2 ] = curNodes [ i3d ];
7488 uniqueNodes[ 3 ] = curNodes [ i0t ];
7491 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7495 myLastCreatedElems.Append(newElem);
7497 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7500 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7501 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7502 // --------------------------------------------> prism
7503 // find 2 opposite triangles
7505 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7506 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7507 // find indices of kept and replaced nodes
7508 // and fill unique nodes of 2 opposite triangles
7509 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7510 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7511 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7512 // fill unique nodes
7515 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7516 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7517 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7519 // iCur of a linked node of the opposite face (make normals co-directed):
7520 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7521 // check that correspondent corners of triangles are linked
7522 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7525 uniqueNodes[ iUnique ] = n;
7526 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7535 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7541 } // switch ( nbNodes )
7543 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7546 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7547 // Change nodes of polyedre
7548 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7549 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7551 int nbFaces = aPolyedre->NbFaces();
7553 vector<const SMDS_MeshNode *> poly_nodes;
7554 vector<int> quantities (nbFaces);
7556 for (int iface = 1; iface <= nbFaces; iface++) {
7557 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7558 quantities[iface - 1] = nbFaceNodes;
7560 for (inode = 1; inode <= nbFaceNodes; inode++) {
7561 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7563 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7564 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7565 curNode = (*nnIt).second;
7567 poly_nodes.push_back(curNode);
7570 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7574 // Change regular element or polygon
7575 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7579 // Remove invalid regular element or invalid polygon
7580 rmElemIds.push_back( elem->GetID() );
7583 } // loop on elements
7585 // Remove equal nodes and bad elements
7587 Remove( rmNodeIds, true );
7588 Remove( rmElemIds, false );
7593 // ========================================================
7594 // class : SortableElement
7595 // purpose : allow sorting elements basing on their nodes
7596 // ========================================================
7597 class SortableElement : public set <const SMDS_MeshElement*>
7601 SortableElement( const SMDS_MeshElement* theElem )
7604 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7605 while ( nodeIt->more() )
7606 this->insert( nodeIt->next() );
7609 const SMDS_MeshElement* Get() const
7612 void Set(const SMDS_MeshElement* e) const
7617 mutable const SMDS_MeshElement* myElem;
7620 //=======================================================================
7621 //function : FindEqualElements
7622 //purpose : Return list of group of elements built on the same nodes.
7623 // Search among theElements or in the whole mesh if theElements is empty
7624 //=======================================================================
7625 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7626 TListOfListOfElementsID & theGroupsOfElementsID)
7628 myLastCreatedElems.Clear();
7629 myLastCreatedNodes.Clear();
7631 typedef set<const SMDS_MeshElement*> TElemsSet;
7632 typedef map< SortableElement, int > TMapOfNodeSet;
7633 typedef list<int> TGroupOfElems;
7636 if ( theElements.empty() )
7637 { // get all elements in the mesh
7638 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7639 while ( eIt->more() )
7640 elems.insert( elems.end(), eIt->next());
7643 elems = theElements;
7645 vector< TGroupOfElems > arrayOfGroups;
7646 TGroupOfElems groupOfElems;
7647 TMapOfNodeSet mapOfNodeSet;
7649 TElemsSet::iterator elemIt = elems.begin();
7650 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7651 const SMDS_MeshElement* curElem = *elemIt;
7652 SortableElement SE(curElem);
7655 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7656 if( !(pp.second) ) {
7657 TMapOfNodeSet::iterator& itSE = pp.first;
7658 ind = (*itSE).second;
7659 arrayOfGroups[ind].push_back(curElem->GetID());
7662 groupOfElems.clear();
7663 groupOfElems.push_back(curElem->GetID());
7664 arrayOfGroups.push_back(groupOfElems);
7669 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7670 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7671 groupOfElems = *groupIt;
7672 if ( groupOfElems.size() > 1 ) {
7673 groupOfElems.sort();
7674 theGroupsOfElementsID.push_back(groupOfElems);
7679 //=======================================================================
7680 //function : MergeElements
7681 //purpose : In each given group, substitute all elements by the first one.
7682 //=======================================================================
7684 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7686 myLastCreatedElems.Clear();
7687 myLastCreatedNodes.Clear();
7689 typedef list<int> TListOfIDs;
7690 TListOfIDs rmElemIds; // IDs of elems to remove
7692 SMESHDS_Mesh* aMesh = GetMeshDS();
7694 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7695 while ( groupsIt != theGroupsOfElementsID.end() ) {
7696 TListOfIDs& aGroupOfElemID = *groupsIt;
7697 aGroupOfElemID.sort();
7698 int elemIDToKeep = aGroupOfElemID.front();
7699 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7700 aGroupOfElemID.pop_front();
7701 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7702 while ( idIt != aGroupOfElemID.end() ) {
7703 int elemIDToRemove = *idIt;
7704 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7705 // add the kept element in groups of removed one (PAL15188)
7706 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7707 rmElemIds.push_back( elemIDToRemove );
7713 Remove( rmElemIds, false );
7716 //=======================================================================
7717 //function : MergeEqualElements
7718 //purpose : Remove all but one of elements built on the same nodes.
7719 //=======================================================================
7721 void SMESH_MeshEditor::MergeEqualElements()
7723 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7724 to merge equal elements in the whole mesh */
7725 TListOfListOfElementsID aGroupsOfElementsID;
7726 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7727 MergeElements(aGroupsOfElementsID);
7730 //=======================================================================
7731 //function : FindFaceInSet
7732 //purpose : Return a face having linked nodes n1 and n2 and which is
7733 // - not in avoidSet,
7734 // - in elemSet provided that !elemSet.empty()
7735 // i1 and i2 optionally returns indices of n1 and n2
7736 //=======================================================================
7738 const SMDS_MeshElement*
7739 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7740 const SMDS_MeshNode* n2,
7741 const TIDSortedElemSet& elemSet,
7742 const TIDSortedElemSet& avoidSet,
7748 const SMDS_MeshElement* face = 0;
7750 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7751 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7753 const SMDS_MeshElement* elem = invElemIt->next();
7754 if (avoidSet.count( elem ))
7756 if ( !elemSet.empty() && !elemSet.count( elem ))
7759 i1 = elem->GetNodeIndex( n1 );
7760 // find a n2 linked to n1
7761 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7762 for ( int di = -1; di < 2 && !face; di += 2 )
7764 i2 = (i1+di+nbN) % nbN;
7765 if ( elem->GetNode( i2 ) == n2 )
7768 if ( !face && elem->IsQuadratic())
7770 // analysis for quadratic elements using all nodes
7771 const SMDS_QuadraticFaceOfNodes* F =
7772 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7773 // use special nodes iterator
7774 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7775 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7776 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7778 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7779 if ( n1 == prevN && n2 == n )
7783 else if ( n2 == prevN && n1 == n )
7785 face = elem; swap( i1, i2 );
7791 if ( n1ind ) *n1ind = i1;
7792 if ( n2ind ) *n2ind = i2;
7796 //=======================================================================
7797 //function : findAdjacentFace
7799 //=======================================================================
7801 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7802 const SMDS_MeshNode* n2,
7803 const SMDS_MeshElement* elem)
7805 TIDSortedElemSet elemSet, avoidSet;
7807 avoidSet.insert ( elem );
7808 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7811 //=======================================================================
7812 //function : FindFreeBorder
7814 //=======================================================================
7816 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7818 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7819 const SMDS_MeshNode* theSecondNode,
7820 const SMDS_MeshNode* theLastNode,
7821 list< const SMDS_MeshNode* > & theNodes,
7822 list< const SMDS_MeshElement* >& theFaces)
7824 if ( !theFirstNode || !theSecondNode )
7826 // find border face between theFirstNode and theSecondNode
7827 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7831 theFaces.push_back( curElem );
7832 theNodes.push_back( theFirstNode );
7833 theNodes.push_back( theSecondNode );
7835 //vector<const SMDS_MeshNode*> nodes;
7836 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7837 TIDSortedElemSet foundElems;
7838 bool needTheLast = ( theLastNode != 0 );
7840 while ( nStart != theLastNode ) {
7841 if ( nStart == theFirstNode )
7842 return !needTheLast;
7844 // find all free border faces sharing form nStart
7846 list< const SMDS_MeshElement* > curElemList;
7847 list< const SMDS_MeshNode* > nStartList;
7848 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7849 while ( invElemIt->more() ) {
7850 const SMDS_MeshElement* e = invElemIt->next();
7851 if ( e == curElem || foundElems.insert( e ).second ) {
7853 int iNode = 0, nbNodes = e->NbNodes();
7854 //const SMDS_MeshNode* nodes[nbNodes+1];
7855 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7857 if(e->IsQuadratic()) {
7858 const SMDS_QuadraticFaceOfNodes* F =
7859 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7860 // use special nodes iterator
7861 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7862 while( anIter->more() ) {
7863 nodes[ iNode++ ] = anIter->next();
7867 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7868 while ( nIt->more() )
7869 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7871 nodes[ iNode ] = nodes[ 0 ];
7873 for ( iNode = 0; iNode < nbNodes; iNode++ )
7874 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7875 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7876 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7878 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7879 curElemList.push_back( e );
7883 // analyse the found
7885 int nbNewBorders = curElemList.size();
7886 if ( nbNewBorders == 0 ) {
7887 // no free border furthermore
7888 return !needTheLast;
7890 else if ( nbNewBorders == 1 ) {
7891 // one more element found
7893 nStart = nStartList.front();
7894 curElem = curElemList.front();
7895 theFaces.push_back( curElem );
7896 theNodes.push_back( nStart );
7899 // several continuations found
7900 list< const SMDS_MeshElement* >::iterator curElemIt;
7901 list< const SMDS_MeshNode* >::iterator nStartIt;
7902 // check if one of them reached the last node
7903 if ( needTheLast ) {
7904 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7905 curElemIt!= curElemList.end();
7906 curElemIt++, nStartIt++ )
7907 if ( *nStartIt == theLastNode ) {
7908 theFaces.push_back( *curElemIt );
7909 theNodes.push_back( *nStartIt );
7913 // find the best free border by the continuations
7914 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7915 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7916 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7917 curElemIt!= curElemList.end();
7918 curElemIt++, nStartIt++ )
7920 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7921 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7922 // find one more free border
7923 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7927 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7928 // choice: clear a worse one
7929 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7930 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7931 contNodes[ iWorse ].clear();
7932 contFaces[ iWorse ].clear();
7935 if ( contNodes[0].empty() && contNodes[1].empty() )
7938 // append the best free border
7939 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7940 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7941 theNodes.pop_back(); // remove nIgnore
7942 theNodes.pop_back(); // remove nStart
7943 theFaces.pop_back(); // remove curElem
7944 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7945 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7946 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7947 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7950 } // several continuations found
7951 } // while ( nStart != theLastNode )
7956 //=======================================================================
7957 //function : CheckFreeBorderNodes
7958 //purpose : Return true if the tree nodes are on a free border
7959 //=======================================================================
7961 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7962 const SMDS_MeshNode* theNode2,
7963 const SMDS_MeshNode* theNode3)
7965 list< const SMDS_MeshNode* > nodes;
7966 list< const SMDS_MeshElement* > faces;
7967 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7970 //=======================================================================
7971 //function : SewFreeBorder
7973 //=======================================================================
7975 SMESH_MeshEditor::Sew_Error
7976 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7977 const SMDS_MeshNode* theBordSecondNode,
7978 const SMDS_MeshNode* theBordLastNode,
7979 const SMDS_MeshNode* theSideFirstNode,
7980 const SMDS_MeshNode* theSideSecondNode,
7981 const SMDS_MeshNode* theSideThirdNode,
7982 const bool theSideIsFreeBorder,
7983 const bool toCreatePolygons,
7984 const bool toCreatePolyedrs)
7986 myLastCreatedElems.Clear();
7987 myLastCreatedNodes.Clear();
7989 MESSAGE("::SewFreeBorder()");
7990 Sew_Error aResult = SEW_OK;
7992 // ====================================
7993 // find side nodes and elements
7994 // ====================================
7996 list< const SMDS_MeshNode* > nSide[ 2 ];
7997 list< const SMDS_MeshElement* > eSide[ 2 ];
7998 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7999 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8003 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8004 nSide[0], eSide[0])) {
8005 MESSAGE(" Free Border 1 not found " );
8006 aResult = SEW_BORDER1_NOT_FOUND;
8008 if (theSideIsFreeBorder) {
8011 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8012 nSide[1], eSide[1])) {
8013 MESSAGE(" Free Border 2 not found " );
8014 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8017 if ( aResult != SEW_OK )
8020 if (!theSideIsFreeBorder) {
8024 // -------------------------------------------------------------------------
8026 // 1. If nodes to merge are not coincident, move nodes of the free border
8027 // from the coord sys defined by the direction from the first to last
8028 // nodes of the border to the correspondent sys of the side 2
8029 // 2. On the side 2, find the links most co-directed with the correspondent
8030 // links of the free border
8031 // -------------------------------------------------------------------------
8033 // 1. Since sewing may brake if there are volumes to split on the side 2,
8034 // we wont move nodes but just compute new coordinates for them
8035 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8036 TNodeXYZMap nBordXYZ;
8037 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8038 list< const SMDS_MeshNode* >::iterator nBordIt;
8040 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8041 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8042 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8043 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8044 double tol2 = 1.e-8;
8045 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8046 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8047 // Need node movement.
8049 // find X and Z axes to create trsf
8050 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8052 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8054 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8057 gp_Ax3 toBordAx( Pb1, Zb, X );
8058 gp_Ax3 fromSideAx( Ps1, Zs, X );
8059 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8061 gp_Trsf toBordSys, fromSide2Sys;
8062 toBordSys.SetTransformation( toBordAx );
8063 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8064 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8067 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8068 const SMDS_MeshNode* n = *nBordIt;
8069 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8070 toBordSys.Transforms( xyz );
8071 fromSide2Sys.Transforms( xyz );
8072 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8076 // just insert nodes XYZ in the nBordXYZ map
8077 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8078 const SMDS_MeshNode* n = *nBordIt;
8079 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8083 // 2. On the side 2, find the links most co-directed with the correspondent
8084 // links of the free border
8086 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8087 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8088 sideNodes.push_back( theSideFirstNode );
8090 bool hasVolumes = false;
8091 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8092 set<long> foundSideLinkIDs, checkedLinkIDs;
8093 SMDS_VolumeTool volume;
8094 //const SMDS_MeshNode* faceNodes[ 4 ];
8096 const SMDS_MeshNode* sideNode;
8097 const SMDS_MeshElement* sideElem;
8098 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8099 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8100 nBordIt = bordNodes.begin();
8102 // border node position and border link direction to compare with
8103 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8104 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8105 // choose next side node by link direction or by closeness to
8106 // the current border node:
8107 bool searchByDir = ( *nBordIt != theBordLastNode );
8109 // find the next node on the Side 2
8111 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8113 checkedLinkIDs.clear();
8114 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8116 // loop on inverse elements of current node (prevSideNode) on the Side 2
8117 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8118 while ( invElemIt->more() )
8120 const SMDS_MeshElement* elem = invElemIt->next();
8121 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8122 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8123 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8124 bool isVolume = volume.Set( elem );
8125 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8126 if ( isVolume ) // --volume
8128 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8129 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8130 if(elem->IsQuadratic()) {
8131 const SMDS_QuadraticFaceOfNodes* F =
8132 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
8133 // use special nodes iterator
8134 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8135 while( anIter->more() ) {
8136 nodes[ iNode ] = anIter->next();
8137 if ( nodes[ iNode++ ] == prevSideNode )
8138 iPrevNode = iNode - 1;
8142 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8143 while ( nIt->more() ) {
8144 nodes[ iNode ] = cast2Node( nIt->next() );
8145 if ( nodes[ iNode++ ] == prevSideNode )
8146 iPrevNode = iNode - 1;
8149 // there are 2 links to check
8154 // loop on links, to be precise, on the second node of links
8155 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8156 const SMDS_MeshNode* n = nodes[ iNode ];
8158 if ( !volume.IsLinked( n, prevSideNode ))
8162 if ( iNode ) // a node before prevSideNode
8163 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8164 else // a node after prevSideNode
8165 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8167 // check if this link was already used
8168 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8169 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8170 if (!isJustChecked &&
8171 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8173 // test a link geometrically
8174 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8175 bool linkIsBetter = false;
8176 double dot = 0.0, dist = 0.0;
8177 if ( searchByDir ) { // choose most co-directed link
8178 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8179 linkIsBetter = ( dot > maxDot );
8181 else { // choose link with the node closest to bordPos
8182 dist = ( nextXYZ - bordPos ).SquareModulus();
8183 linkIsBetter = ( dist < minDist );
8185 if ( linkIsBetter ) {
8194 } // loop on inverse elements of prevSideNode
8197 MESSAGE(" Cant find path by links of the Side 2 ");
8198 return SEW_BAD_SIDE_NODES;
8200 sideNodes.push_back( sideNode );
8201 sideElems.push_back( sideElem );
8202 foundSideLinkIDs.insert ( linkID );
8203 prevSideNode = sideNode;
8205 if ( *nBordIt == theBordLastNode )
8206 searchByDir = false;
8208 // find the next border link to compare with
8209 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8210 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8211 // move to next border node if sideNode is before forward border node (bordPos)
8212 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8213 prevBordNode = *nBordIt;
8215 bordPos = nBordXYZ[ *nBordIt ];
8216 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8217 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8221 while ( sideNode != theSideSecondNode );
8223 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8224 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8225 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8227 } // end nodes search on the side 2
8229 // ============================
8230 // sew the border to the side 2
8231 // ============================
8233 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8234 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8236 TListOfListOfNodes nodeGroupsToMerge;
8237 if ( nbNodes[0] == nbNodes[1] ||
8238 ( theSideIsFreeBorder && !theSideThirdNode)) {
8240 // all nodes are to be merged
8242 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8243 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8244 nIt[0]++, nIt[1]++ )
8246 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8247 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8248 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8253 // insert new nodes into the border and the side to get equal nb of segments
8255 // get normalized parameters of nodes on the borders
8256 //double param[ 2 ][ maxNbNodes ];
8258 param[0] = new double [ maxNbNodes ];
8259 param[1] = new double [ maxNbNodes ];
8261 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8262 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8263 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8264 const SMDS_MeshNode* nPrev = *nIt;
8265 double bordLength = 0;
8266 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8267 const SMDS_MeshNode* nCur = *nIt;
8268 gp_XYZ segment (nCur->X() - nPrev->X(),
8269 nCur->Y() - nPrev->Y(),
8270 nCur->Z() - nPrev->Z());
8271 double segmentLen = segment.Modulus();
8272 bordLength += segmentLen;
8273 param[ iBord ][ iNode ] = bordLength;
8276 // normalize within [0,1]
8277 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8278 param[ iBord ][ iNode ] /= bordLength;
8282 // loop on border segments
8283 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8284 int i[ 2 ] = { 0, 0 };
8285 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8286 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8288 TElemOfNodeListMap insertMap;
8289 TElemOfNodeListMap::iterator insertMapIt;
8291 // key: elem to insert nodes into
8292 // value: 2 nodes to insert between + nodes to be inserted
8294 bool next[ 2 ] = { false, false };
8296 // find min adjacent segment length after sewing
8297 double nextParam = 10., prevParam = 0;
8298 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8299 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8300 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8301 if ( i[ iBord ] > 0 )
8302 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8304 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8305 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8306 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8308 // choose to insert or to merge nodes
8309 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8310 if ( Abs( du ) <= minSegLen * 0.2 ) {
8313 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8314 const SMDS_MeshNode* n0 = *nIt[0];
8315 const SMDS_MeshNode* n1 = *nIt[1];
8316 nodeGroupsToMerge.back().push_back( n1 );
8317 nodeGroupsToMerge.back().push_back( n0 );
8318 // position of node of the border changes due to merge
8319 param[ 0 ][ i[0] ] += du;
8320 // move n1 for the sake of elem shape evaluation during insertion.
8321 // n1 will be removed by MergeNodes() anyway
8322 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8323 next[0] = next[1] = true;
8328 int intoBord = ( du < 0 ) ? 0 : 1;
8329 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8330 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8331 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8332 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8333 if ( intoBord == 1 ) {
8334 // move node of the border to be on a link of elem of the side
8335 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8336 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8337 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8338 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8339 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8341 insertMapIt = insertMap.find( elem );
8342 bool notFound = ( insertMapIt == insertMap.end() );
8343 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8345 // insert into another link of the same element:
8346 // 1. perform insertion into the other link of the elem
8347 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8348 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8349 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8350 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8351 // 2. perform insertion into the link of adjacent faces
8353 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8355 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8359 if (toCreatePolyedrs) {
8360 // perform insertion into the links of adjacent volumes
8361 UpdateVolumes(n12, n22, nodeList);
8363 // 3. find an element appeared on n1 and n2 after the insertion
8364 insertMap.erase( elem );
8365 elem = findAdjacentFace( n1, n2, 0 );
8367 if ( notFound || otherLink ) {
8368 // add element and nodes of the side into the insertMap
8369 insertMapIt = insertMap.insert
8370 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8371 (*insertMapIt).second.push_back( n1 );
8372 (*insertMapIt).second.push_back( n2 );
8374 // add node to be inserted into elem
8375 (*insertMapIt).second.push_back( nIns );
8376 next[ 1 - intoBord ] = true;
8379 // go to the next segment
8380 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8381 if ( next[ iBord ] ) {
8382 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8384 nPrev[ iBord ] = *nIt[ iBord ];
8385 nIt[ iBord ]++; i[ iBord ]++;
8389 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8391 // perform insertion of nodes into elements
8393 for (insertMapIt = insertMap.begin();
8394 insertMapIt != insertMap.end();
8397 const SMDS_MeshElement* elem = (*insertMapIt).first;
8398 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8399 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8400 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8402 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8404 if ( !theSideIsFreeBorder ) {
8405 // look for and insert nodes into the faces adjacent to elem
8407 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8409 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8414 if (toCreatePolyedrs) {
8415 // perform insertion into the links of adjacent volumes
8416 UpdateVolumes(n1, n2, nodeList);
8422 } // end: insert new nodes
8424 MergeNodes ( nodeGroupsToMerge );
8429 //=======================================================================
8430 //function : InsertNodesIntoLink
8431 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8432 // and theBetweenNode2 and split theElement
8433 //=======================================================================
8435 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8436 const SMDS_MeshNode* theBetweenNode1,
8437 const SMDS_MeshNode* theBetweenNode2,
8438 list<const SMDS_MeshNode*>& theNodesToInsert,
8439 const bool toCreatePoly)
8441 if ( theFace->GetType() != SMDSAbs_Face ) return;
8443 // find indices of 2 link nodes and of the rest nodes
8444 int iNode = 0, il1, il2, i3, i4;
8445 il1 = il2 = i3 = i4 = -1;
8446 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8447 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8449 if(theFace->IsQuadratic()) {
8450 const SMDS_QuadraticFaceOfNodes* F =
8451 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8452 // use special nodes iterator
8453 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8454 while( anIter->more() ) {
8455 const SMDS_MeshNode* n = anIter->next();
8456 if ( n == theBetweenNode1 )
8458 else if ( n == theBetweenNode2 )
8464 nodes[ iNode++ ] = n;
8468 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8469 while ( nodeIt->more() ) {
8470 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8471 if ( n == theBetweenNode1 )
8473 else if ( n == theBetweenNode2 )
8479 nodes[ iNode++ ] = n;
8482 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8485 // arrange link nodes to go one after another regarding the face orientation
8486 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8487 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8492 aNodesToInsert.reverse();
8494 // check that not link nodes of a quadrangles are in good order
8495 int nbFaceNodes = theFace->NbNodes();
8496 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8502 if (toCreatePoly || theFace->IsPoly()) {
8505 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8507 // add nodes of face up to first node of link
8510 if(theFace->IsQuadratic()) {
8511 const SMDS_QuadraticFaceOfNodes* F =
8512 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8513 // use special nodes iterator
8514 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8515 while( anIter->more() && !isFLN ) {
8516 const SMDS_MeshNode* n = anIter->next();
8517 poly_nodes[iNode++] = n;
8518 if (n == nodes[il1]) {
8522 // add nodes to insert
8523 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8524 for (; nIt != aNodesToInsert.end(); nIt++) {
8525 poly_nodes[iNode++] = *nIt;
8527 // add nodes of face starting from last node of link
8528 while ( anIter->more() ) {
8529 poly_nodes[iNode++] = anIter->next();
8533 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8534 while ( nodeIt->more() && !isFLN ) {
8535 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8536 poly_nodes[iNode++] = n;
8537 if (n == nodes[il1]) {
8541 // add nodes to insert
8542 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8543 for (; nIt != aNodesToInsert.end(); nIt++) {
8544 poly_nodes[iNode++] = *nIt;
8546 // add nodes of face starting from last node of link
8547 while ( nodeIt->more() ) {
8548 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8549 poly_nodes[iNode++] = n;
8553 // edit or replace the face
8554 SMESHDS_Mesh *aMesh = GetMeshDS();
8556 if (theFace->IsPoly()) {
8557 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8560 int aShapeId = FindShape( theFace );
8562 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8563 myLastCreatedElems.Append(newElem);
8564 if ( aShapeId && newElem )
8565 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8567 aMesh->RemoveElement(theFace);
8572 if( !theFace->IsQuadratic() ) {
8574 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8575 int nbLinkNodes = 2 + aNodesToInsert.size();
8576 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8577 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8578 linkNodes[ 0 ] = nodes[ il1 ];
8579 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8580 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8581 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8582 linkNodes[ iNode++ ] = *nIt;
8584 // decide how to split a quadrangle: compare possible variants
8585 // and choose which of splits to be a quadrangle
8586 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8587 if ( nbFaceNodes == 3 ) {
8588 iBestQuad = nbSplits;
8591 else if ( nbFaceNodes == 4 ) {
8592 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8593 double aBestRate = DBL_MAX;
8594 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8596 double aBadRate = 0;
8597 // evaluate elements quality
8598 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8599 if ( iSplit == iQuad ) {
8600 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8604 aBadRate += getBadRate( &quad, aCrit );
8607 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8609 nodes[ iSplit < iQuad ? i4 : i3 ]);
8610 aBadRate += getBadRate( &tria, aCrit );
8614 if ( aBadRate < aBestRate ) {
8616 aBestRate = aBadRate;
8621 // create new elements
8622 SMESHDS_Mesh *aMesh = GetMeshDS();
8623 int aShapeId = FindShape( theFace );
8626 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8627 SMDS_MeshElement* newElem = 0;
8628 if ( iSplit == iBestQuad )
8629 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8634 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8636 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8637 myLastCreatedElems.Append(newElem);
8638 if ( aShapeId && newElem )
8639 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8642 // change nodes of theFace
8643 const SMDS_MeshNode* newNodes[ 4 ];
8644 newNodes[ 0 ] = linkNodes[ i1 ];
8645 newNodes[ 1 ] = linkNodes[ i2 ];
8646 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8647 newNodes[ 3 ] = nodes[ i4 ];
8648 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8649 } // end if(!theFace->IsQuadratic())
8650 else { // theFace is quadratic
8651 // we have to split theFace on simple triangles and one simple quadrangle
8653 int nbshift = tmp*2;
8654 // shift nodes in nodes[] by nbshift
8656 for(i=0; i<nbshift; i++) {
8657 const SMDS_MeshNode* n = nodes[0];
8658 for(j=0; j<nbFaceNodes-1; j++) {
8659 nodes[j] = nodes[j+1];
8661 nodes[nbFaceNodes-1] = n;
8663 il1 = il1 - nbshift;
8664 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8665 // n0 n1 n2 n0 n1 n2
8666 // +-----+-----+ +-----+-----+
8675 // create new elements
8676 SMESHDS_Mesh *aMesh = GetMeshDS();
8677 int aShapeId = FindShape( theFace );
8680 if(nbFaceNodes==6) { // quadratic triangle
8681 SMDS_MeshElement* newElem =
8682 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8683 myLastCreatedElems.Append(newElem);
8684 if ( aShapeId && newElem )
8685 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8686 if(theFace->IsMediumNode(nodes[il1])) {
8687 // create quadrangle
8688 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8689 myLastCreatedElems.Append(newElem);
8690 if ( aShapeId && newElem )
8691 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8697 // create quadrangle
8698 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8699 myLastCreatedElems.Append(newElem);
8700 if ( aShapeId && newElem )
8701 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8707 else { // nbFaceNodes==8 - quadratic quadrangle
8708 SMDS_MeshElement* newElem =
8709 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8710 myLastCreatedElems.Append(newElem);
8711 if ( aShapeId && newElem )
8712 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8713 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8714 myLastCreatedElems.Append(newElem);
8715 if ( aShapeId && newElem )
8716 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8717 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8718 myLastCreatedElems.Append(newElem);
8719 if ( aShapeId && newElem )
8720 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8721 if(theFace->IsMediumNode(nodes[il1])) {
8722 // create quadrangle
8723 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8724 myLastCreatedElems.Append(newElem);
8725 if ( aShapeId && newElem )
8726 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8732 // create quadrangle
8733 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8734 myLastCreatedElems.Append(newElem);
8735 if ( aShapeId && newElem )
8736 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8742 // create needed triangles using n1,n2,n3 and inserted nodes
8743 int nbn = 2 + aNodesToInsert.size();
8744 //const SMDS_MeshNode* aNodes[nbn];
8745 vector<const SMDS_MeshNode*> aNodes(nbn);
8746 aNodes[0] = nodes[n1];
8747 aNodes[nbn-1] = nodes[n2];
8748 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8749 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8750 aNodes[iNode++] = *nIt;
8752 for(i=1; i<nbn; i++) {
8753 SMDS_MeshElement* newElem =
8754 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8755 myLastCreatedElems.Append(newElem);
8756 if ( aShapeId && newElem )
8757 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8759 // remove old quadratic face
8760 aMesh->RemoveElement(theFace);
8764 //=======================================================================
8765 //function : UpdateVolumes
8767 //=======================================================================
8768 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8769 const SMDS_MeshNode* theBetweenNode2,
8770 list<const SMDS_MeshNode*>& theNodesToInsert)
8772 myLastCreatedElems.Clear();
8773 myLastCreatedNodes.Clear();
8775 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8776 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8777 const SMDS_MeshElement* elem = invElemIt->next();
8779 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8780 SMDS_VolumeTool aVolume (elem);
8781 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8784 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8785 int iface, nbFaces = aVolume.NbFaces();
8786 vector<const SMDS_MeshNode *> poly_nodes;
8787 vector<int> quantities (nbFaces);
8789 for (iface = 0; iface < nbFaces; iface++) {
8790 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8791 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8792 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8794 for (int inode = 0; inode < nbFaceNodes; inode++) {
8795 poly_nodes.push_back(faceNodes[inode]);
8797 if (nbInserted == 0) {
8798 if (faceNodes[inode] == theBetweenNode1) {
8799 if (faceNodes[inode + 1] == theBetweenNode2) {
8800 nbInserted = theNodesToInsert.size();
8802 // add nodes to insert
8803 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8804 for (; nIt != theNodesToInsert.end(); nIt++) {
8805 poly_nodes.push_back(*nIt);
8809 else if (faceNodes[inode] == theBetweenNode2) {
8810 if (faceNodes[inode + 1] == theBetweenNode1) {
8811 nbInserted = theNodesToInsert.size();
8813 // add nodes to insert in reversed order
8814 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8816 for (; nIt != theNodesToInsert.begin(); nIt--) {
8817 poly_nodes.push_back(*nIt);
8819 poly_nodes.push_back(*nIt);
8826 quantities[iface] = nbFaceNodes + nbInserted;
8829 // Replace or update the volume
8830 SMESHDS_Mesh *aMesh = GetMeshDS();
8832 if (elem->IsPoly()) {
8833 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8837 int aShapeId = FindShape( elem );
8839 SMDS_MeshElement* newElem =
8840 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8841 myLastCreatedElems.Append(newElem);
8842 if (aShapeId && newElem)
8843 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8845 aMesh->RemoveElement(elem);
8850 //=======================================================================
8852 * \brief Convert elements contained in a submesh to quadratic
8853 * \retval int - nb of checked elements
8855 //=======================================================================
8857 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8858 SMESH_MesherHelper& theHelper,
8859 const bool theForce3d)
8862 if( !theSm ) return nbElem;
8864 const bool notFromGroups = false;
8865 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8866 while(ElemItr->more())
8869 const SMDS_MeshElement* elem = ElemItr->next();
8870 if( !elem || elem->IsQuadratic() ) continue;
8872 int id = elem->GetID();
8873 int nbNodes = elem->NbNodes();
8874 vector<const SMDS_MeshNode *> aNds (nbNodes);
8876 for(int i = 0; i < nbNodes; i++)
8878 aNds[i] = elem->GetNode(i);
8880 SMDSAbs_ElementType aType = elem->GetType();
8882 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8884 const SMDS_MeshElement* NewElem = 0;
8890 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8898 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8901 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8908 case SMDSAbs_Volume :
8913 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8916 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8919 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8922 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8923 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8933 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8935 theSm->AddElement( NewElem );
8940 //=======================================================================
8941 //function : ConvertToQuadratic
8943 //=======================================================================
8944 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8946 SMESHDS_Mesh* meshDS = GetMeshDS();
8948 SMESH_MesherHelper aHelper(*myMesh);
8949 aHelper.SetIsQuadratic( true );
8950 const bool notFromGroups = false;
8952 int nbCheckedElems = 0;
8953 if ( myMesh->HasShapeToMesh() )
8955 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8957 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8958 while ( smIt->more() ) {
8959 SMESH_subMesh* sm = smIt->next();
8960 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8961 aHelper.SetSubShape( sm->GetSubShape() );
8962 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8967 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8968 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8970 SMESHDS_SubMesh *smDS = 0;
8971 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8972 while(aEdgeItr->more())
8974 const SMDS_MeshEdge* edge = aEdgeItr->next();
8975 if(edge && !edge->IsQuadratic())
8977 int id = edge->GetID();
8978 const SMDS_MeshNode* n1 = edge->GetNode(0);
8979 const SMDS_MeshNode* n2 = edge->GetNode(1);
8981 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8983 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8984 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8987 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8988 while(aFaceItr->more())
8990 const SMDS_MeshFace* face = aFaceItr->next();
8991 if(!face || face->IsQuadratic() ) continue;
8993 int id = face->GetID();
8994 int nbNodes = face->NbNodes();
8995 vector<const SMDS_MeshNode *> aNds (nbNodes);
8997 for(int i = 0; i < nbNodes; i++)
8999 aNds[i] = face->GetNode(i);
9002 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
9004 SMDS_MeshFace * NewFace = 0;
9008 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
9011 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
9016 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9018 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9019 while(aVolumeItr->more())
9021 const SMDS_MeshVolume* volume = aVolumeItr->next();
9022 if(!volume || volume->IsQuadratic() ) continue;
9024 int id = volume->GetID();
9025 int nbNodes = volume->NbNodes();
9026 vector<const SMDS_MeshNode *> aNds (nbNodes);
9028 for(int i = 0; i < nbNodes; i++)
9030 aNds[i] = volume->GetNode(i);
9033 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
9035 SMDS_MeshVolume * NewVolume = 0;
9039 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9040 aNds[3], id, theForce3d );
9043 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9044 aNds[3], aNds[4], id, theForce3d);
9047 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
9048 aNds[3], aNds[4], aNds[5], id, theForce3d);
9051 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
9052 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
9057 ReplaceElemInGroups(volume, NewVolume, meshDS);
9060 if ( !theForce3d && !getenv("NO_FixQuadraticElements")) {
9061 aHelper.SetSubShape(0); // apply to the whole mesh
9062 aHelper.FixQuadraticElements();
9066 //=======================================================================
9068 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9069 * \retval int - nb of checked elements
9071 //=======================================================================
9073 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9074 SMDS_ElemIteratorPtr theItr,
9075 const int theShapeID)
9078 SMESHDS_Mesh* meshDS = GetMeshDS();
9079 const bool notFromGroups = false;
9081 while( theItr->more() )
9083 const SMDS_MeshElement* elem = theItr->next();
9085 if( elem && elem->IsQuadratic())
9087 int id = elem->GetID();
9088 int nbNodes = elem->NbNodes();
9089 vector<const SMDS_MeshNode *> aNds, mediumNodes;
9090 aNds.reserve( nbNodes );
9091 mediumNodes.reserve( nbNodes );
9093 for(int i = 0; i < nbNodes; i++)
9095 const SMDS_MeshNode* n = elem->GetNode(i);
9097 if( elem->IsMediumNode( n ) )
9098 mediumNodes.push_back( n );
9100 aNds.push_back( n );
9102 if( aNds.empty() ) continue;
9103 SMDSAbs_ElementType aType = elem->GetType();
9105 //remove old quadratic element
9106 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9108 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
9109 ReplaceElemInGroups(elem, NewElem, meshDS);
9110 if( theSm && NewElem )
9111 theSm->AddElement( NewElem );
9113 // remove medium nodes
9114 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9115 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9116 const SMDS_MeshNode* n = *nIt;
9117 if ( n->NbInverseElements() == 0 ) {
9118 if ( n->GetPosition()->GetShapeId() != theShapeID )
9119 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9120 ( n->GetPosition()->GetShapeId() ));
9122 meshDS->RemoveFreeNode( n, theSm );
9130 //=======================================================================
9131 //function : ConvertFromQuadratic
9133 //=======================================================================
9134 bool SMESH_MeshEditor::ConvertFromQuadratic()
9136 int nbCheckedElems = 0;
9137 if ( myMesh->HasShapeToMesh() )
9139 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9141 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9142 while ( smIt->more() ) {
9143 SMESH_subMesh* sm = smIt->next();
9144 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9145 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9151 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9152 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9154 SMESHDS_SubMesh *aSM = 0;
9155 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9161 //=======================================================================
9162 //function : SewSideElements
9164 //=======================================================================
9166 SMESH_MeshEditor::Sew_Error
9167 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9168 TIDSortedElemSet& theSide2,
9169 const SMDS_MeshNode* theFirstNode1,
9170 const SMDS_MeshNode* theFirstNode2,
9171 const SMDS_MeshNode* theSecondNode1,
9172 const SMDS_MeshNode* theSecondNode2)
9174 myLastCreatedElems.Clear();
9175 myLastCreatedNodes.Clear();
9177 MESSAGE ("::::SewSideElements()");
9178 if ( theSide1.size() != theSide2.size() )
9179 return SEW_DIFF_NB_OF_ELEMENTS;
9181 Sew_Error aResult = SEW_OK;
9183 // 1. Build set of faces representing each side
9184 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9185 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9187 // =======================================================================
9188 // 1. Build set of faces representing each side:
9189 // =======================================================================
9190 // a. build set of nodes belonging to faces
9191 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9192 // c. create temporary faces representing side of volumes if correspondent
9193 // face does not exist
9195 SMESHDS_Mesh* aMesh = GetMeshDS();
9196 SMDS_Mesh aTmpFacesMesh;
9197 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9198 set<const SMDS_MeshElement*> volSet1, volSet2;
9199 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9200 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9201 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9202 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9203 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9204 int iSide, iFace, iNode;
9206 for ( iSide = 0; iSide < 2; iSide++ ) {
9207 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9208 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9209 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9210 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9211 set<const SMDS_MeshElement*>::iterator vIt;
9212 TIDSortedElemSet::iterator eIt;
9213 set<const SMDS_MeshNode*>::iterator nIt;
9215 // check that given nodes belong to given elements
9216 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9217 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9218 int firstIndex = -1, secondIndex = -1;
9219 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9220 const SMDS_MeshElement* elem = *eIt;
9221 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9222 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9223 if ( firstIndex > -1 && secondIndex > -1 ) break;
9225 if ( firstIndex < 0 || secondIndex < 0 ) {
9226 // we can simply return until temporary faces created
9227 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9230 // -----------------------------------------------------------
9231 // 1a. Collect nodes of existing faces
9232 // and build set of face nodes in order to detect missing
9233 // faces corresponing to sides of volumes
9234 // -----------------------------------------------------------
9236 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9238 // loop on the given element of a side
9239 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9240 //const SMDS_MeshElement* elem = *eIt;
9241 const SMDS_MeshElement* elem = *eIt;
9242 if ( elem->GetType() == SMDSAbs_Face ) {
9243 faceSet->insert( elem );
9244 set <const SMDS_MeshNode*> faceNodeSet;
9245 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9246 while ( nodeIt->more() ) {
9247 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9248 nodeSet->insert( n );
9249 faceNodeSet.insert( n );
9251 setOfFaceNodeSet.insert( faceNodeSet );
9253 else if ( elem->GetType() == SMDSAbs_Volume )
9254 volSet->insert( elem );
9256 // ------------------------------------------------------------------------------
9257 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9258 // ------------------------------------------------------------------------------
9260 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9261 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9262 while ( fIt->more() ) { // loop on faces sharing a node
9263 const SMDS_MeshElement* f = fIt->next();
9264 if ( faceSet->find( f ) == faceSet->end() ) {
9265 // check if all nodes are in nodeSet and
9266 // complete setOfFaceNodeSet if they are
9267 set <const SMDS_MeshNode*> faceNodeSet;
9268 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9269 bool allInSet = true;
9270 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9271 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9272 if ( nodeSet->find( n ) == nodeSet->end() )
9275 faceNodeSet.insert( n );
9278 faceSet->insert( f );
9279 setOfFaceNodeSet.insert( faceNodeSet );
9285 // -------------------------------------------------------------------------
9286 // 1c. Create temporary faces representing sides of volumes if correspondent
9287 // face does not exist
9288 // -------------------------------------------------------------------------
9290 if ( !volSet->empty() ) {
9291 //int nodeSetSize = nodeSet->size();
9293 // loop on given volumes
9294 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9295 SMDS_VolumeTool vol (*vIt);
9296 // loop on volume faces: find free faces
9297 // --------------------------------------
9298 list<const SMDS_MeshElement* > freeFaceList;
9299 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9300 if ( !vol.IsFreeFace( iFace ))
9302 // check if there is already a face with same nodes in a face set
9303 const SMDS_MeshElement* aFreeFace = 0;
9304 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9305 int nbNodes = vol.NbFaceNodes( iFace );
9306 set <const SMDS_MeshNode*> faceNodeSet;
9307 vol.GetFaceNodes( iFace, faceNodeSet );
9308 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9310 // no such a face is given but it still can exist, check it
9311 if ( nbNodes == 3 ) {
9312 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9314 else if ( nbNodes == 4 ) {
9315 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9318 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9319 aFreeFace = aMesh->FindFace(poly_nodes);
9323 // create a temporary face
9324 if ( nbNodes == 3 ) {
9325 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9327 else if ( nbNodes == 4 ) {
9328 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9331 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9332 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9336 freeFaceList.push_back( aFreeFace );
9338 } // loop on faces of a volume
9340 // choose one of several free faces
9341 // --------------------------------------
9342 if ( freeFaceList.size() > 1 ) {
9343 // choose a face having max nb of nodes shared by other elems of a side
9344 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9345 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9346 while ( fIt != freeFaceList.end() ) { // loop on free faces
9347 int nbSharedNodes = 0;
9348 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9349 while ( nodeIt->more() ) { // loop on free face nodes
9350 const SMDS_MeshNode* n =
9351 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9352 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9353 while ( invElemIt->more() ) {
9354 const SMDS_MeshElement* e = invElemIt->next();
9355 if ( faceSet->find( e ) != faceSet->end() )
9357 if ( elemSet->find( e ) != elemSet->end() )
9361 if ( nbSharedNodes >= maxNbNodes ) {
9362 maxNbNodes = nbSharedNodes;
9366 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9368 if ( freeFaceList.size() > 1 )
9370 // could not choose one face, use another way
9371 // choose a face most close to the bary center of the opposite side
9372 gp_XYZ aBC( 0., 0., 0. );
9373 set <const SMDS_MeshNode*> addedNodes;
9374 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9375 eIt = elemSet2->begin();
9376 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9377 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9378 while ( nodeIt->more() ) { // loop on free face nodes
9379 const SMDS_MeshNode* n =
9380 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9381 if ( addedNodes.insert( n ).second )
9382 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9385 aBC /= addedNodes.size();
9386 double minDist = DBL_MAX;
9387 fIt = freeFaceList.begin();
9388 while ( fIt != freeFaceList.end() ) { // loop on free faces
9390 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9391 while ( nodeIt->more() ) { // loop on free face nodes
9392 const SMDS_MeshNode* n =
9393 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9394 gp_XYZ p( n->X(),n->Y(),n->Z() );
9395 dist += ( aBC - p ).SquareModulus();
9397 if ( dist < minDist ) {
9399 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9402 fIt = freeFaceList.erase( fIt++ );
9405 } // choose one of several free faces of a volume
9407 if ( freeFaceList.size() == 1 ) {
9408 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9409 faceSet->insert( aFreeFace );
9410 // complete a node set with nodes of a found free face
9411 // for ( iNode = 0; iNode < ; iNode++ )
9412 // nodeSet->insert( fNodes[ iNode ] );
9415 } // loop on volumes of a side
9417 // // complete a set of faces if new nodes in a nodeSet appeared
9418 // // ----------------------------------------------------------
9419 // if ( nodeSetSize != nodeSet->size() ) {
9420 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9421 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9422 // while ( fIt->more() ) { // loop on faces sharing a node
9423 // const SMDS_MeshElement* f = fIt->next();
9424 // if ( faceSet->find( f ) == faceSet->end() ) {
9425 // // check if all nodes are in nodeSet and
9426 // // complete setOfFaceNodeSet if they are
9427 // set <const SMDS_MeshNode*> faceNodeSet;
9428 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9429 // bool allInSet = true;
9430 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9431 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9432 // if ( nodeSet->find( n ) == nodeSet->end() )
9433 // allInSet = false;
9435 // faceNodeSet.insert( n );
9437 // if ( allInSet ) {
9438 // faceSet->insert( f );
9439 // setOfFaceNodeSet.insert( faceNodeSet );
9445 } // Create temporary faces, if there are volumes given
9448 if ( faceSet1.size() != faceSet2.size() ) {
9449 // delete temporary faces: they are in reverseElements of actual nodes
9450 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9451 while ( tmpFaceIt->more() )
9452 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9453 MESSAGE("Diff nb of faces");
9454 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9457 // ============================================================
9458 // 2. Find nodes to merge:
9459 // bind a node to remove to a node to put instead
9460 // ============================================================
9462 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9463 if ( theFirstNode1 != theFirstNode2 )
9464 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9465 if ( theSecondNode1 != theSecondNode2 )
9466 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9468 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9469 set< long > linkIdSet; // links to process
9470 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9472 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9473 list< NLink > linkList[2];
9474 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9475 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9476 // loop on links in linkList; find faces by links and append links
9477 // of the found faces to linkList
9478 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9479 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9480 NLink link[] = { *linkIt[0], *linkIt[1] };
9481 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9482 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9485 // by links, find faces in the face sets,
9486 // and find indices of link nodes in the found faces;
9487 // in a face set, there is only one or no face sharing a link
9488 // ---------------------------------------------------------------
9490 const SMDS_MeshElement* face[] = { 0, 0 };
9491 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9492 vector<const SMDS_MeshNode*> fnodes1(9);
9493 vector<const SMDS_MeshNode*> fnodes2(9);
9494 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9495 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9496 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9497 int iLinkNode[2][2];
9498 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9499 const SMDS_MeshNode* n1 = link[iSide].first;
9500 const SMDS_MeshNode* n2 = link[iSide].second;
9501 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9502 set< const SMDS_MeshElement* > fMap;
9503 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9504 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9505 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9506 while ( fIt->more() ) { // loop on faces sharing a node
9507 const SMDS_MeshElement* f = fIt->next();
9508 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9509 ! fMap.insert( f ).second ) // f encounters twice
9511 if ( face[ iSide ] ) {
9512 MESSAGE( "2 faces per link " );
9513 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9517 faceSet->erase( f );
9518 // get face nodes and find ones of a link
9523 fnodes1.resize(f->NbNodes()+1);
9524 notLinkNodes1.resize(f->NbNodes()-2);
9527 fnodes2.resize(f->NbNodes()+1);
9528 notLinkNodes2.resize(f->NbNodes()-2);
9531 if(!f->IsQuadratic()) {
9532 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9533 while ( nIt->more() ) {
9534 const SMDS_MeshNode* n =
9535 static_cast<const SMDS_MeshNode*>( nIt->next() );
9537 iLinkNode[ iSide ][ 0 ] = iNode;
9539 else if ( n == n2 ) {
9540 iLinkNode[ iSide ][ 1 ] = iNode;
9542 //else if ( notLinkNodes[ iSide ][ 0 ] )
9543 // notLinkNodes[ iSide ][ 1 ] = n;
9545 // notLinkNodes[ iSide ][ 0 ] = n;
9549 notLinkNodes1[nbl] = n;
9550 //notLinkNodes1.push_back(n);
9552 notLinkNodes2[nbl] = n;
9553 //notLinkNodes2.push_back(n);
9555 //faceNodes[ iSide ][ iNode++ ] = n;
9557 fnodes1[iNode++] = n;
9560 fnodes2[iNode++] = n;
9564 else { // f->IsQuadratic()
9565 const SMDS_QuadraticFaceOfNodes* F =
9566 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9567 // use special nodes iterator
9568 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9569 while ( anIter->more() ) {
9570 const SMDS_MeshNode* n =
9571 static_cast<const SMDS_MeshNode*>( anIter->next() );
9573 iLinkNode[ iSide ][ 0 ] = iNode;
9575 else if ( n == n2 ) {
9576 iLinkNode[ iSide ][ 1 ] = iNode;
9581 notLinkNodes1[nbl] = n;
9584 notLinkNodes2[nbl] = n;
9588 fnodes1[iNode++] = n;
9591 fnodes2[iNode++] = n;
9595 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9597 fnodes1[iNode] = fnodes1[0];
9600 fnodes2[iNode] = fnodes1[0];
9607 // check similarity of elements of the sides
9608 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9609 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9610 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9611 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9614 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9616 break; // do not return because it s necessary to remove tmp faces
9619 // set nodes to merge
9620 // -------------------
9622 if ( face[0] && face[1] ) {
9623 int nbNodes = face[0]->NbNodes();
9624 if ( nbNodes != face[1]->NbNodes() ) {
9625 MESSAGE("Diff nb of face nodes");
9626 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9627 break; // do not return because it s necessary to remove tmp faces
9629 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9630 if ( nbNodes == 3 ) {
9631 //nReplaceMap.insert( TNodeNodeMap::value_type
9632 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9633 nReplaceMap.insert( TNodeNodeMap::value_type
9634 ( notLinkNodes1[0], notLinkNodes2[0] ));
9637 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9638 // analyse link orientation in faces
9639 int i1 = iLinkNode[ iSide ][ 0 ];
9640 int i2 = iLinkNode[ iSide ][ 1 ];
9641 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9642 // if notLinkNodes are the first and the last ones, then
9643 // their order does not correspond to the link orientation
9644 if (( i1 == 1 && i2 == 2 ) ||
9645 ( i1 == 2 && i2 == 1 ))
9646 reverse[ iSide ] = !reverse[ iSide ];
9648 if ( reverse[0] == reverse[1] ) {
9649 //nReplaceMap.insert( TNodeNodeMap::value_type
9650 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9651 //nReplaceMap.insert( TNodeNodeMap::value_type
9652 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9653 for(int nn=0; nn<nbNodes-2; nn++) {
9654 nReplaceMap.insert( TNodeNodeMap::value_type
9655 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9659 //nReplaceMap.insert( TNodeNodeMap::value_type
9660 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9661 //nReplaceMap.insert( TNodeNodeMap::value_type
9662 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9663 for(int nn=0; nn<nbNodes-2; nn++) {
9664 nReplaceMap.insert( TNodeNodeMap::value_type
9665 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9670 // add other links of the faces to linkList
9671 // -----------------------------------------
9673 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9674 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9675 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9676 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9677 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9678 if ( !iter_isnew.second ) { // already in a set: no need to process
9679 linkIdSet.erase( iter_isnew.first );
9681 else // new in set == encountered for the first time: add
9683 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9684 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9685 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9686 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9687 linkList[0].push_back ( NLink( n1, n2 ));
9688 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9692 } // loop on link lists
9694 if ( aResult == SEW_OK &&
9695 ( linkIt[0] != linkList[0].end() ||
9696 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9697 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9698 " " << (faceSetPtr[1]->empty()));
9699 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9702 // ====================================================================
9703 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9704 // ====================================================================
9706 // delete temporary faces: they are in reverseElements of actual nodes
9707 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9708 while ( tmpFaceIt->more() )
9709 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9711 if ( aResult != SEW_OK)
9714 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9715 // loop on nodes replacement map
9716 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9717 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9718 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9719 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9720 nodeIDsToRemove.push_back( nToRemove->GetID() );
9721 // loop on elements sharing nToRemove
9722 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9723 while ( invElemIt->more() ) {
9724 const SMDS_MeshElement* e = invElemIt->next();
9725 // get a new suite of nodes: make replacement
9726 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9727 vector< const SMDS_MeshNode*> nodes( nbNodes );
9728 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9729 while ( nIt->more() ) {
9730 const SMDS_MeshNode* n =
9731 static_cast<const SMDS_MeshNode*>( nIt->next() );
9732 nnIt = nReplaceMap.find( n );
9733 if ( nnIt != nReplaceMap.end() ) {
9739 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9740 // elemIDsToRemove.push_back( e->GetID() );
9743 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9747 Remove( nodeIDsToRemove, true );
9752 //================================================================================
9754 * \brief Find corresponding nodes in two sets of faces
9755 * \param theSide1 - first face set
9756 * \param theSide2 - second first face
9757 * \param theFirstNode1 - a boundary node of set 1
9758 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9759 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9760 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9761 * \param nReplaceMap - output map of corresponding nodes
9762 * \retval bool - is a success or not
9764 //================================================================================
9767 //#define DEBUG_MATCHING_NODES
9770 SMESH_MeshEditor::Sew_Error
9771 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9772 set<const SMDS_MeshElement*>& theSide2,
9773 const SMDS_MeshNode* theFirstNode1,
9774 const SMDS_MeshNode* theFirstNode2,
9775 const SMDS_MeshNode* theSecondNode1,
9776 const SMDS_MeshNode* theSecondNode2,
9777 TNodeNodeMap & nReplaceMap)
9779 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9781 nReplaceMap.clear();
9782 if ( theFirstNode1 != theFirstNode2 )
9783 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9784 if ( theSecondNode1 != theSecondNode2 )
9785 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9787 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9788 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9790 list< NLink > linkList[2];
9791 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9792 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9794 // loop on links in linkList; find faces by links and append links
9795 // of the found faces to linkList
9796 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9797 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9798 NLink link[] = { *linkIt[0], *linkIt[1] };
9799 if ( linkSet.find( link[0] ) == linkSet.end() )
9802 // by links, find faces in the face sets,
9803 // and find indices of link nodes in the found faces;
9804 // in a face set, there is only one or no face sharing a link
9805 // ---------------------------------------------------------------
9807 const SMDS_MeshElement* face[] = { 0, 0 };
9808 list<const SMDS_MeshNode*> notLinkNodes[2];
9809 //bool reverse[] = { false, false }; // order of notLinkNodes
9811 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9813 const SMDS_MeshNode* n1 = link[iSide].first;
9814 const SMDS_MeshNode* n2 = link[iSide].second;
9815 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9816 set< const SMDS_MeshElement* > facesOfNode1;
9817 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9819 // during a loop of the first node, we find all faces around n1,
9820 // during a loop of the second node, we find one face sharing both n1 and n2
9821 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9822 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9823 while ( fIt->more() ) { // loop on faces sharing a node
9824 const SMDS_MeshElement* f = fIt->next();
9825 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9826 ! facesOfNode1.insert( f ).second ) // f encounters twice
9828 if ( face[ iSide ] ) {
9829 MESSAGE( "2 faces per link " );
9830 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9833 faceSet->erase( f );
9835 // get not link nodes
9836 int nbN = f->NbNodes();
9837 if ( f->IsQuadratic() )
9839 nbNodes[ iSide ] = nbN;
9840 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9841 int i1 = f->GetNodeIndex( n1 );
9842 int i2 = f->GetNodeIndex( n2 );
9843 int iEnd = nbN, iBeg = -1, iDelta = 1;
9844 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9846 std::swap( iEnd, iBeg ); iDelta = -1;
9851 if ( i == iEnd ) i = iBeg + iDelta;
9852 if ( i == i1 ) break;
9853 nodes.push_back ( f->GetNode( i ) );
9859 // check similarity of elements of the sides
9860 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9861 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9862 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9863 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9866 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9870 // set nodes to merge
9871 // -------------------
9873 if ( face[0] && face[1] ) {
9874 if ( nbNodes[0] != nbNodes[1] ) {
9875 MESSAGE("Diff nb of face nodes");
9876 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9878 #ifdef DEBUG_MATCHING_NODES
9879 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9880 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9881 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9883 int nbN = nbNodes[0];
9885 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9886 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9887 for ( int i = 0 ; i < nbN - 2; ++i ) {
9888 #ifdef DEBUG_MATCHING_NODES
9889 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9891 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9895 // add other links of the face 1 to linkList
9896 // -----------------------------------------
9898 const SMDS_MeshElement* f0 = face[0];
9899 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9900 for ( int i = 0; i < nbN; i++ )
9902 const SMDS_MeshNode* n2 = f0->GetNode( i );
9903 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9904 linkSet.insert( SMESH_TLink( n1, n2 ));
9905 if ( !iter_isnew.second ) { // already in a set: no need to process
9906 linkSet.erase( iter_isnew.first );
9908 else // new in set == encountered for the first time: add
9910 #ifdef DEBUG_MATCHING_NODES
9911 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9912 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9914 linkList[0].push_back ( NLink( n1, n2 ));
9915 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9920 } // loop on link lists
9925 //================================================================================
9927 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9928 \param theElems - the list of elements (edges or faces) to be replicated
9929 The nodes for duplication could be found from these elements
9930 \param theNodesNot - list of nodes to NOT replicate
9931 \param theAffectedElems - the list of elements (cells and edges) to which the
9932 replicated nodes should be associated to.
9933 \return TRUE if operation has been completed successfully, FALSE otherwise
9935 //================================================================================
9937 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9938 const TIDSortedElemSet& theNodesNot,
9939 const TIDSortedElemSet& theAffectedElems )
9941 myLastCreatedElems.Clear();
9942 myLastCreatedNodes.Clear();
9944 if ( theElems.size() == 0 )
9947 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9952 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9953 // duplicate elements and nodes
9954 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9955 // replce nodes by duplications
9956 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9960 //================================================================================
9962 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9963 \param theMeshDS - mesh instance
9964 \param theElems - the elements replicated or modified (nodes should be changed)
9965 \param theNodesNot - nodes to NOT replicate
9966 \param theNodeNodeMap - relation of old node to new created node
9967 \param theIsDoubleElem - flag os to replicate element or modify
9968 \return TRUE if operation has been completed successfully, FALSE otherwise
9970 //================================================================================
9972 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9973 const TIDSortedElemSet& theElems,
9974 const TIDSortedElemSet& theNodesNot,
9975 std::map< const SMDS_MeshNode*,
9976 const SMDS_MeshNode* >& theNodeNodeMap,
9977 const bool theIsDoubleElem )
9979 // iterate on through element and duplicate them (by nodes duplication)
9981 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9982 for ( ; elemItr != theElems.end(); ++elemItr )
9984 const SMDS_MeshElement* anElem = *elemItr;
9988 bool isDuplicate = false;
9989 // duplicate nodes to duplicate element
9990 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9991 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9993 while ( anIter->more() )
9996 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9997 SMDS_MeshNode* aNewNode = aCurrNode;
9998 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9999 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10000 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10003 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10004 theNodeNodeMap[ aCurrNode ] = aNewNode;
10005 myLastCreatedNodes.Append( aNewNode );
10007 isDuplicate |= (aCurrNode != aNewNode);
10008 newNodes[ ind++ ] = aNewNode;
10010 if ( !isDuplicate )
10013 if ( theIsDoubleElem )
10014 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
10016 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10023 //================================================================================
10025 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10026 \param theNodes - identifiers of nodes to be doubled
10027 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10028 nodes. If list of element identifiers is empty then nodes are doubled but
10029 they not assigned to elements
10030 \return TRUE if operation has been completed successfully, FALSE otherwise
10032 //================================================================================
10034 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10035 const std::list< int >& theListOfModifiedElems )
10037 myLastCreatedElems.Clear();
10038 myLastCreatedNodes.Clear();
10040 if ( theListOfNodes.size() == 0 )
10043 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10047 // iterate through nodes and duplicate them
10049 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10051 std::list< int >::const_iterator aNodeIter;
10052 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10054 int aCurr = *aNodeIter;
10055 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10061 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10064 anOldNodeToNewNode[ aNode ] = aNewNode;
10065 myLastCreatedNodes.Append( aNewNode );
10069 // Create map of new nodes for modified elements
10071 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10073 std::list< int >::const_iterator anElemIter;
10074 for ( anElemIter = theListOfModifiedElems.begin();
10075 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10077 int aCurr = *anElemIter;
10078 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10082 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10084 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10086 while ( anIter->more() )
10088 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10089 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10091 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10092 aNodeArr[ ind++ ] = aNewNode;
10095 aNodeArr[ ind++ ] = aCurrNode;
10097 anElemToNodes[ anElem ] = aNodeArr;
10100 // Change nodes of elements
10102 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10103 anElemToNodesIter = anElemToNodes.begin();
10104 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10106 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10107 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10109 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10117 //================================================================================
10119 \brief Check if element located inside shape
10120 \return TRUE if IN or ON shape, FALSE otherwise
10122 //================================================================================
10124 template<class Classifier>
10125 bool isInside(const SMDS_MeshElement* theElem,
10126 Classifier& theClassifier,
10127 const double theTol)
10129 gp_XYZ centerXYZ (0, 0, 0);
10130 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10131 while (aNodeItr->more())
10132 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10134 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10135 theClassifier.Perform(aPnt, theTol);
10136 TopAbs_State aState = theClassifier.State();
10137 return (aState == TopAbs_IN || aState == TopAbs_ON );
10140 //================================================================================
10142 * \brief Classifier of the 3D point on the TopoDS_Face
10143 * with interaface suitable for isInside()
10145 //================================================================================
10147 struct _FaceClassifier
10149 Extrema_ExtPS _extremum;
10150 BRepAdaptor_Surface _surface;
10151 TopAbs_State _state;
10153 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10155 _extremum.Initialize( _surface,
10156 _surface.FirstUParameter(), _surface.LastUParameter(),
10157 _surface.FirstVParameter(), _surface.LastVParameter(),
10158 _surface.Tolerance(), _surface.Tolerance() );
10160 void Perform(const gp_Pnt& aPnt, double theTol)
10162 _state = TopAbs_OUT;
10163 _extremum.Perform(aPnt);
10164 if ( _extremum.IsDone() )
10165 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10166 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10168 TopAbs_State State() const
10175 //================================================================================
10177 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10178 \param theElems - group of of elements (edges or faces) to be replicated
10179 \param theNodesNot - group of nodes not to replicate
10180 \param theShape - shape to detect affected elements (element which geometric center
10181 located on or inside shape).
10182 The replicated nodes should be associated to affected elements.
10183 \return TRUE if operation has been completed successfully, FALSE otherwise
10185 //================================================================================
10187 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10188 const TIDSortedElemSet& theNodesNot,
10189 const TopoDS_Shape& theShape )
10191 if ( theShape.IsNull() )
10194 const double aTol = Precision::Confusion();
10195 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10196 auto_ptr<_FaceClassifier> aFaceClassifier;
10197 if ( theShape.ShapeType() == TopAbs_SOLID )
10199 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10200 bsc3d->PerformInfinitePoint(aTol);
10202 else if (theShape.ShapeType() == TopAbs_FACE )
10204 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10207 // iterates on indicated elements and get elements by back references from their nodes
10208 TIDSortedElemSet anAffected;
10209 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10210 for ( ; elemItr != theElems.end(); ++elemItr )
10212 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10216 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10217 while ( nodeItr->more() )
10219 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10220 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10222 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10223 while ( backElemItr->more() )
10225 const SMDS_MeshElement* curElem = backElemItr->next();
10226 if ( curElem && theElems.find(curElem) == theElems.end() &&
10228 isInside( curElem, *bsc3d, aTol ) :
10229 isInside( curElem, *aFaceClassifier, aTol )))
10230 anAffected.insert( curElem );
10234 return DoubleNodes( theElems, theNodesNot, anAffected );
10237 //================================================================================
10239 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
10240 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10241 * \return TRUE if operation has been completed successfully, FALSE otherwise
10243 //================================================================================
10245 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10247 // iterates on volume elements and detect all free faces on them
10248 SMESHDS_Mesh* aMesh = GetMeshDS();
10251 //bool res = false;
10252 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10253 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10256 const SMDS_MeshVolume* volume = vIt->next();
10257 SMDS_VolumeTool vTool( volume );
10258 vTool.SetExternalNormal();
10259 const bool isPoly = volume->IsPoly();
10260 const bool isQuad = volume->IsQuadratic();
10261 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10263 if (!vTool.IsFreeFace(iface))
10266 vector<const SMDS_MeshNode *> nodes;
10267 int nbFaceNodes = vTool.NbFaceNodes(iface);
10268 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10270 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10271 nodes.push_back(faceNodes[inode]);
10273 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10274 nodes.push_back(faceNodes[inode]);
10276 // add new face based on volume nodes
10277 if (aMesh->FindFace( nodes ) ) {
10279 continue; // face already exsist
10281 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
10285 return ( nbFree==(nbExisted+nbCreated) );