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"
38 #include "SMDS_SetIterator.hxx"
40 #include "SMESHDS_Group.hxx"
41 #include "SMESHDS_Mesh.hxx"
43 #include "SMESH_Algo.hxx"
44 #include "SMESH_ControlsDef.hxx"
45 #include "SMESH_Group.hxx"
46 #include "SMESH_MesherHelper.hxx"
47 #include "SMESH_OctreeNode.hxx"
48 #include "SMESH_subMesh.hxx"
50 #include "utilities.h"
52 #include <BRepAdaptor_Surface.hxx>
53 #include <BRepClass3d_SolidClassifier.hxx>
54 #include <BRep_Tool.hxx>
56 #include <Extrema_GenExtPS.hxx>
57 #include <Extrema_POnCurv.hxx>
58 #include <Extrema_POnSurf.hxx>
59 #include <GC_MakeSegment.hxx>
60 #include <Geom2d_Curve.hxx>
61 #include <GeomAPI_ExtremaCurveCurve.hxx>
62 #include <GeomAdaptor_Surface.hxx>
63 #include <Geom_Curve.hxx>
64 #include <Geom_Line.hxx>
65 #include <Geom_Surface.hxx>
66 #include <IntAna_IntConicQuad.hxx>
67 #include <IntAna_Quadric.hxx>
68 #include <Precision.hxx>
69 #include <TColStd_ListOfInteger.hxx>
70 #include <TopAbs_State.hxx>
72 #include <TopExp_Explorer.hxx>
73 #include <TopTools_ListIteratorOfListOfShape.hxx>
74 #include <TopTools_ListOfShape.hxx>
75 #include <TopTools_SequenceOfShape.hxx>
77 #include <TopoDS_Face.hxx>
83 #include <gp_Trsf.hxx>
95 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
98 using namespace SMESH::Controls;
100 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
101 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
103 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
105 //=======================================================================
106 //function : SMESH_MeshEditor
108 //=======================================================================
110 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
111 :myMesh( theMesh ) // theMesh may be NULL
115 //=======================================================================
119 //=======================================================================
122 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
123 const SMDSAbs_ElementType type,
127 SMDS_MeshElement* e = 0;
128 int nbnode = node.size();
129 SMESHDS_Mesh* mesh = GetMeshDS();
135 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
136 else e = mesh->AddFace (node[0], node[1], node[2] );
137 else if (nbnode == 4)
138 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
139 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
140 else if (nbnode == 6)
141 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
142 node[4], node[5], ID);
143 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
145 else if (nbnode == 8)
146 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
147 node[4], node[5], node[6], node[7], ID);
148 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
149 node[4], node[5], node[6], node[7] );
151 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
152 else e = mesh->AddPolygonalFace (node );
159 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
160 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
161 else if (nbnode == 5)
162 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
164 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
166 else if (nbnode == 6)
167 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
168 node[4], node[5], ID);
169 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
171 else if (nbnode == 8)
172 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173 node[4], node[5], node[6], node[7], ID);
174 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
175 node[4], node[5], node[6], node[7] );
176 else if (nbnode == 10)
177 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178 node[4], node[5], node[6], node[7],
179 node[8], node[9], ID);
180 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
181 node[4], node[5], node[6], node[7],
183 else if (nbnode == 13)
184 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7],
186 node[8], node[9], node[10],node[11],
188 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7],
190 node[8], node[9], node[10],node[11],
192 else if (nbnode == 15)
193 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7],
195 node[8], node[9], node[10],node[11],
196 node[12],node[13],node[14],ID);
197 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
198 node[4], node[5], node[6], node[7],
199 node[8], node[9], node[10],node[11],
200 node[12],node[13],node[14] );
201 else if (nbnode == 20)
202 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
205 node[12],node[13],node[14],node[15],
206 node[16],node[17],node[18],node[19],ID);
207 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
208 node[4], node[5], node[6], node[7],
209 node[8], node[9], node[10],node[11],
210 node[12],node[13],node[14],node[15],
211 node[16],node[17],node[18],node[19] );
217 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
218 else e = mesh->AddEdge (node[0], node[1] );
219 else if ( nbnode == 3 )
220 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
221 else e = mesh->AddEdge (node[0], node[1], node[2] );
224 case SMDSAbs_0DElement:
226 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
227 else e = mesh->Add0DElement (node[0] );
231 if ( ID ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
232 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
237 if ( e ) myLastCreatedElems.Append( e );
241 //=======================================================================
245 //=======================================================================
247 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
248 const SMDSAbs_ElementType type,
252 vector<const SMDS_MeshNode*> nodes;
253 nodes.reserve( nodeIDs.size() );
254 vector<int>::const_iterator id = nodeIDs.begin();
255 while ( id != nodeIDs.end() ) {
256 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
257 nodes.push_back( node );
261 return AddElement( nodes, type, isPoly, ID );
264 //=======================================================================
266 //purpose : Remove a node or an element.
267 // Modify a compute state of sub-meshes which become empty
268 //=======================================================================
270 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
273 myLastCreatedElems.Clear();
274 myLastCreatedNodes.Clear();
276 SMESHDS_Mesh* aMesh = GetMeshDS();
277 set< SMESH_subMesh *> smmap;
280 list<int>::const_iterator it = theIDs.begin();
281 for ( ; it != theIDs.end(); it++ ) {
282 const SMDS_MeshElement * elem;
284 elem = aMesh->FindNode( *it );
286 elem = aMesh->FindElement( *it );
290 // Notify VERTEX sub-meshes about modification
292 const SMDS_MeshNode* node = cast2Node( elem );
293 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
294 if ( int aShapeID = node->GetPosition()->GetShapeId() )
295 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
298 // Find sub-meshes to notify about modification
299 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
300 // while ( nodeIt->more() ) {
301 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
302 // const SMDS_PositionPtr& aPosition = node->GetPosition();
303 // if ( aPosition.get() ) {
304 // if ( int aShapeID = aPosition->GetShapeId() ) {
305 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
306 // smmap.insert( sm );
313 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
315 aMesh->RemoveElement( elem );
319 // Notify sub-meshes about modification
320 if ( !smmap.empty() ) {
321 set< SMESH_subMesh *>::iterator smIt;
322 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
323 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
326 // // Check if the whole mesh becomes empty
327 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
328 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
333 //=======================================================================
334 //function : FindShape
335 //purpose : Return an index of the shape theElem is on
336 // or zero if a shape not found
337 //=======================================================================
339 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
341 myLastCreatedElems.Clear();
342 myLastCreatedNodes.Clear();
344 SMESHDS_Mesh * aMesh = GetMeshDS();
345 if ( aMesh->ShapeToMesh().IsNull() )
348 if ( theElem->GetType() == SMDSAbs_Node ) {
349 const SMDS_PositionPtr& aPosition =
350 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
351 if ( aPosition.get() )
352 return aPosition->GetShapeId();
357 TopoDS_Shape aShape; // the shape a node is on
358 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
359 while ( nodeIt->more() ) {
360 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
361 const SMDS_PositionPtr& aPosition = node->GetPosition();
362 if ( aPosition.get() ) {
363 int aShapeID = aPosition->GetShapeId();
364 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
366 if ( sm->Contains( theElem ))
368 if ( aShape.IsNull() )
369 aShape = aMesh->IndexToShape( aShapeID );
372 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
377 // None of nodes is on a proper shape,
378 // find the shape among ancestors of aShape on which a node is
379 if ( aShape.IsNull() ) {
380 //MESSAGE ("::FindShape() - NONE node is on shape")
383 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
384 for ( ; ancIt.More(); ancIt.Next() ) {
385 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
386 if ( sm && sm->Contains( theElem ))
387 return aMesh->ShapeToIndex( ancIt.Value() );
390 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
394 //=======================================================================
395 //function : IsMedium
397 //=======================================================================
399 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
400 const SMDSAbs_ElementType typeToCheck)
402 bool isMedium = false;
403 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
404 while (it->more() && !isMedium ) {
405 const SMDS_MeshElement* elem = it->next();
406 isMedium = elem->IsMediumNode(node);
411 //=======================================================================
412 //function : ShiftNodesQuadTria
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 void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
419 const SMDS_MeshNode* nd1 = aNodes[0];
420 aNodes[0] = aNodes[1];
421 aNodes[1] = aNodes[2];
423 const SMDS_MeshNode* nd2 = aNodes[3];
424 aNodes[3] = aNodes[4];
425 aNodes[4] = aNodes[5];
429 //=======================================================================
430 //function : GetNodesFromTwoTria
432 // Shift nodes in the array corresponded to quadratic triangle
433 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
434 //=======================================================================
435 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
436 const SMDS_MeshElement * theTria2,
437 const SMDS_MeshNode* N1[],
438 const SMDS_MeshNode* N2[])
440 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
443 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
446 if(it->more()) return false;
447 it = theTria2->nodesIterator();
450 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
453 if(it->more()) return false;
455 int sames[3] = {-1,-1,-1};
467 if(nbsames!=2) return false;
469 ShiftNodesQuadTria(N1);
471 ShiftNodesQuadTria(N1);
474 i = sames[0] + sames[1] + sames[2];
476 ShiftNodesQuadTria(N2);
478 // now we receive following N1 and N2 (using numeration as above image)
479 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
480 // i.e. first nodes from both arrays determ new diagonal
484 //=======================================================================
485 //function : InverseDiag
486 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
487 // but having other common link.
488 // Return False if args are improper
489 //=======================================================================
491 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
492 const SMDS_MeshElement * theTria2 )
494 myLastCreatedElems.Clear();
495 myLastCreatedNodes.Clear();
497 if (!theTria1 || !theTria2)
500 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
501 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
504 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
505 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
509 // put nodes in array and find out indices of the same ones
510 const SMDS_MeshNode* aNodes [6];
511 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
513 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
514 while ( it->more() ) {
515 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
517 if ( i > 2 ) // theTria2
518 // find same node of theTria1
519 for ( int j = 0; j < 3; j++ )
520 if ( aNodes[ i ] == aNodes[ j ]) {
529 return false; // theTria1 is not a triangle
530 it = theTria2->nodesIterator();
532 if ( i == 6 && it->more() )
533 return false; // theTria2 is not a triangle
536 // find indices of 1,2 and of A,B in theTria1
537 int iA = 0, iB = 0, i1 = 0, i2 = 0;
538 for ( i = 0; i < 6; i++ ) {
539 if ( sameInd [ i ] == 0 )
546 // nodes 1 and 2 should not be the same
547 if ( aNodes[ i1 ] == aNodes[ i2 ] )
551 aNodes[ iA ] = aNodes[ i2 ];
553 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
555 //MESSAGE( theTria1 << theTria2 );
557 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
558 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
560 //MESSAGE( theTria1 << theTria2 );
564 } // end if(F1 && F2)
566 // check case of quadratic faces
567 const SMDS_QuadraticFaceOfNodes* QF1 =
568 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
569 if(!QF1) return false;
570 const SMDS_QuadraticFaceOfNodes* QF2 =
571 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
572 if(!QF2) return false;
575 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
576 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
584 const SMDS_MeshNode* N1 [6];
585 const SMDS_MeshNode* N2 [6];
586 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
588 // now we receive following N1 and N2 (using numeration as above image)
589 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
590 // i.e. first nodes from both arrays determ new diagonal
592 const SMDS_MeshNode* N1new [6];
593 const SMDS_MeshNode* N2new [6];
606 // replaces nodes in faces
607 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
608 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
613 //=======================================================================
614 //function : findTriangles
615 //purpose : find triangles sharing theNode1-theNode2 link
616 //=======================================================================
618 static bool findTriangles(const SMDS_MeshNode * theNode1,
619 const SMDS_MeshNode * theNode2,
620 const SMDS_MeshElement*& theTria1,
621 const SMDS_MeshElement*& theTria2)
623 if ( !theNode1 || !theNode2 ) return false;
625 theTria1 = theTria2 = 0;
627 set< const SMDS_MeshElement* > emap;
628 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
630 const SMDS_MeshElement* elem = it->next();
631 if ( elem->NbNodes() == 3 )
634 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
636 const SMDS_MeshElement* elem = it->next();
637 if ( emap.find( elem ) != emap.end() )
639 // theTria1 must be element with minimum ID
640 if( theTria1->GetID() < elem->GetID() ) {
653 return ( theTria1 && theTria2 );
656 //=======================================================================
657 //function : InverseDiag
658 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
659 // with ones built on the same 4 nodes but having other common link.
660 // Return false if proper faces not found
661 //=======================================================================
663 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
664 const SMDS_MeshNode * theNode2)
666 myLastCreatedElems.Clear();
667 myLastCreatedNodes.Clear();
669 MESSAGE( "::InverseDiag()" );
671 const SMDS_MeshElement *tr1, *tr2;
672 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
675 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
676 //if (!F1) return false;
677 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
678 //if (!F2) return false;
681 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
682 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
686 // put nodes in array
687 // and find indices of 1,2 and of A in tr1 and of B in tr2
688 int i, iA1 = 0, i1 = 0;
689 const SMDS_MeshNode* aNodes1 [3];
690 SMDS_ElemIteratorPtr it;
691 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
692 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
693 if ( aNodes1[ i ] == theNode1 )
694 iA1 = i; // node A in tr1
695 else if ( aNodes1[ i ] != theNode2 )
699 const SMDS_MeshNode* aNodes2 [3];
700 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
701 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
702 if ( aNodes2[ i ] == theNode2 )
703 iB2 = i; // node B in tr2
704 else if ( aNodes2[ i ] != theNode1 )
708 // nodes 1 and 2 should not be the same
709 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
713 aNodes1[ iA1 ] = aNodes2[ i2 ];
715 aNodes2[ iB2 ] = aNodes1[ i1 ];
717 //MESSAGE( tr1 << tr2 );
719 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
720 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
722 //MESSAGE( tr1 << tr2 );
727 // check case of quadratic faces
728 const SMDS_QuadraticFaceOfNodes* QF1 =
729 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
730 if(!QF1) return false;
731 const SMDS_QuadraticFaceOfNodes* QF2 =
732 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
733 if(!QF2) return false;
734 return InverseDiag(tr1,tr2);
737 //=======================================================================
738 //function : getQuadrangleNodes
739 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
740 // fusion of triangles tr1 and tr2 having shared link on
741 // theNode1 and theNode2
742 //=======================================================================
744 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
745 const SMDS_MeshNode * theNode1,
746 const SMDS_MeshNode * theNode2,
747 const SMDS_MeshElement * tr1,
748 const SMDS_MeshElement * tr2 )
750 if( tr1->NbNodes() != tr2->NbNodes() )
752 // find the 4-th node to insert into tr1
753 const SMDS_MeshNode* n4 = 0;
754 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
756 while ( !n4 && i<3 ) {
757 const SMDS_MeshNode * n = cast2Node( it->next() );
759 bool isDiag = ( n == theNode1 || n == theNode2 );
763 // Make an array of nodes to be in a quadrangle
764 int iNode = 0, iFirstDiag = -1;
765 it = tr1->nodesIterator();
768 const SMDS_MeshNode * n = cast2Node( it->next() );
770 bool isDiag = ( n == theNode1 || n == theNode2 );
772 if ( iFirstDiag < 0 )
774 else if ( iNode - iFirstDiag == 1 )
775 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
777 else if ( n == n4 ) {
778 return false; // tr1 and tr2 should not have all the same nodes
780 theQuadNodes[ iNode++ ] = n;
782 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
783 theQuadNodes[ iNode ] = n4;
788 //=======================================================================
789 //function : DeleteDiag
790 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
791 // with a quadrangle built on the same 4 nodes.
792 // Return false if proper faces not found
793 //=======================================================================
795 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
796 const SMDS_MeshNode * theNode2)
798 myLastCreatedElems.Clear();
799 myLastCreatedNodes.Clear();
801 MESSAGE( "::DeleteDiag()" );
803 const SMDS_MeshElement *tr1, *tr2;
804 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
807 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
808 //if (!F1) return false;
809 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
810 //if (!F2) return false;
813 const SMDS_MeshNode* aNodes [ 4 ];
814 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
817 //MESSAGE( endl << tr1 << tr2 );
819 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
820 myLastCreatedElems.Append(tr1);
821 GetMeshDS()->RemoveElement( tr2 );
823 //MESSAGE( endl << tr1 );
828 // check case of quadratic faces
829 const SMDS_QuadraticFaceOfNodes* QF1 =
830 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
831 if(!QF1) return false;
832 const SMDS_QuadraticFaceOfNodes* QF2 =
833 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
834 if(!QF2) return false;
837 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
838 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
846 const SMDS_MeshNode* N1 [6];
847 const SMDS_MeshNode* N2 [6];
848 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
850 // now we receive following N1 and N2 (using numeration as above image)
851 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
852 // i.e. first nodes from both arrays determ new diagonal
854 const SMDS_MeshNode* aNodes[8];
864 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
865 myLastCreatedElems.Append(tr1);
866 GetMeshDS()->RemoveElement( tr2 );
868 // remove middle node (9)
869 GetMeshDS()->RemoveNode( N1[4] );
874 //=======================================================================
875 //function : Reorient
876 //purpose : Reverse theElement orientation
877 //=======================================================================
879 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
881 myLastCreatedElems.Clear();
882 myLastCreatedNodes.Clear();
886 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
887 if ( !it || !it->more() )
890 switch ( theElem->GetType() ) {
894 if(!theElem->IsQuadratic()) {
895 int i = theElem->NbNodes();
896 vector<const SMDS_MeshNode*> aNodes( i );
898 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
899 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
902 // quadratic elements
903 if(theElem->GetType()==SMDSAbs_Edge) {
904 vector<const SMDS_MeshNode*> aNodes(3);
905 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
906 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
907 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
908 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
911 int nbn = theElem->NbNodes();
912 vector<const SMDS_MeshNode*> aNodes(nbn);
913 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
915 for(; i<nbn/2; i++) {
916 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
918 for(i=0; i<nbn/2; i++) {
919 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
921 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
925 case SMDSAbs_Volume: {
926 if (theElem->IsPoly()) {
927 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
928 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
930 MESSAGE("Warning: bad volumic element");
934 int nbFaces = aPolyedre->NbFaces();
935 vector<const SMDS_MeshNode *> poly_nodes;
936 vector<int> quantities (nbFaces);
938 // reverse each face of the polyedre
939 for (int iface = 1; iface <= nbFaces; iface++) {
940 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
941 quantities[iface - 1] = nbFaceNodes;
943 for (inode = nbFaceNodes; inode >= 1; inode--) {
944 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
945 poly_nodes.push_back(curNode);
949 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
953 SMDS_VolumeTool vTool;
954 if ( !vTool.Set( theElem ))
957 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
966 //=======================================================================
967 //function : getBadRate
969 //=======================================================================
971 static double getBadRate (const SMDS_MeshElement* theElem,
972 SMESH::Controls::NumericalFunctorPtr& theCrit)
974 SMESH::Controls::TSequenceOfXYZ P;
975 if ( !theElem || !theCrit->GetPoints( theElem, P ))
977 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
978 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
981 //=======================================================================
982 //function : QuadToTri
983 //purpose : Cut quadrangles into triangles.
984 // theCrit is used to select a diagonal to cut
985 //=======================================================================
987 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
988 SMESH::Controls::NumericalFunctorPtr theCrit)
990 myLastCreatedElems.Clear();
991 myLastCreatedNodes.Clear();
993 MESSAGE( "::QuadToTri()" );
995 if ( !theCrit.get() )
998 SMESHDS_Mesh * aMesh = GetMeshDS();
1000 Handle(Geom_Surface) surface;
1001 SMESH_MesherHelper helper( *GetMesh() );
1003 TIDSortedElemSet::iterator itElem;
1004 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1005 const SMDS_MeshElement* elem = *itElem;
1006 if ( !elem || elem->GetType() != SMDSAbs_Face )
1008 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1011 // retrieve element nodes
1012 const SMDS_MeshNode* aNodes [8];
1013 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1015 while ( itN->more() )
1016 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1018 // compare two sets of possible triangles
1019 double aBadRate1, aBadRate2; // to what extent a set is bad
1020 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1021 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1022 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1024 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1025 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1026 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1028 int aShapeId = FindShape( elem );
1029 const SMDS_MeshElement* newElem = 0;
1031 if( !elem->IsQuadratic() ) {
1033 // split liner quadrangle
1035 if ( aBadRate1 <= aBadRate2 ) {
1036 // tr1 + tr2 is better
1037 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1038 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1041 // tr3 + tr4 is better
1042 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1043 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1048 // split quadratic quadrangle
1050 // get surface elem is on
1051 if ( aShapeId != helper.GetSubShapeID() ) {
1055 shape = aMesh->IndexToShape( aShapeId );
1056 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1057 TopoDS_Face face = TopoDS::Face( shape );
1058 surface = BRep_Tool::Surface( face );
1059 if ( !surface.IsNull() )
1060 helper.SetSubShape( shape );
1064 const SMDS_MeshNode* aNodes [8];
1065 const SMDS_MeshNode* inFaceNode = 0;
1066 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1068 while ( itN->more() ) {
1069 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1070 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1071 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1073 inFaceNode = aNodes[ i-1 ];
1076 // find middle point for (0,1,2,3)
1077 // and create a node in this point;
1079 if ( surface.IsNull() ) {
1081 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1085 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1088 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1090 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1092 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1093 myLastCreatedNodes.Append(newN);
1095 // create a new element
1096 const SMDS_MeshNode* N[6];
1097 if ( aBadRate1 <= aBadRate2 ) {
1104 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1105 aNodes[6], aNodes[7], newN );
1114 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1115 aNodes[7], aNodes[4], newN );
1117 aMesh->ChangeElementNodes( elem, N, 6 );
1121 // care of a new element
1123 myLastCreatedElems.Append(newElem);
1124 AddToSameGroups( newElem, elem, aMesh );
1126 // put a new triangle on the same shape
1128 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1133 //=======================================================================
1134 //function : BestSplit
1135 //purpose : Find better diagonal for cutting.
1136 //=======================================================================
1138 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1139 SMESH::Controls::NumericalFunctorPtr theCrit)
1141 myLastCreatedElems.Clear();
1142 myLastCreatedNodes.Clear();
1147 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1150 if( theQuad->NbNodes()==4 ||
1151 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1153 // retrieve element nodes
1154 const SMDS_MeshNode* aNodes [4];
1155 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1157 //while (itN->more())
1159 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1161 // compare two sets of possible triangles
1162 double aBadRate1, aBadRate2; // to what extent a set is bad
1163 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1164 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1165 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1167 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1168 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1169 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1171 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1172 return 1; // diagonal 1-3
1174 return 2; // diagonal 2-4
1181 // Methods of splitting volumes into tetra
1183 const int theHexTo5_1[5*4+1] =
1185 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1187 const int theHexTo5_2[5*4+1] =
1189 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1191 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1193 const int theHexTo6_1[6*4+1] =
1195 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
1197 const int theHexTo6_2[6*4+1] =
1199 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
1201 const int theHexTo6_3[6*4+1] =
1203 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
1205 const int theHexTo6_4[6*4+1] =
1207 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
1209 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1211 const int thePyraTo2_1[2*4+1] =
1213 0, 1, 2, 4, 0, 2, 3, 4, -1
1215 const int thePyraTo2_2[2*4+1] =
1217 1, 2, 3, 4, 1, 3, 0, 4, -1
1219 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1221 const int thePentaTo3_1[3*4+1] =
1223 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1225 const int thePentaTo3_2[3*4+1] =
1227 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1229 const int thePentaTo3_3[3*4+1] =
1231 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1233 const int thePentaTo3_4[3*4+1] =
1235 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1237 const int thePentaTo3_5[3*4+1] =
1239 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1241 const int thePentaTo3_6[3*4+1] =
1243 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1245 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1246 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1248 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1251 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1252 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1253 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1258 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1259 bool _baryNode; //!< additional node is to be created at cell barycenter
1260 bool _ownConn; //!< to delete _connectivity in destructor
1261 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1263 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1264 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1265 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1266 bool hasFacet( const TTriangleFacet& facet ) const
1268 const int* tetConn = _connectivity;
1269 for ( ; tetConn[0] >= 0; tetConn += 4 )
1270 if (( facet.contains( tetConn[0] ) +
1271 facet.contains( tetConn[1] ) +
1272 facet.contains( tetConn[2] ) +
1273 facet.contains( tetConn[3] )) == 3 )
1279 //=======================================================================
1281 * \brief return TSplitMethod for the given element
1283 //=======================================================================
1285 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1287 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1289 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1290 // an edge and a face barycenter; tertaherdons are based on triangles and
1291 // a volume barycenter
1292 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1294 // Find out how adjacent volumes are split
1296 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1297 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1298 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1300 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1301 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1302 if ( nbNodes < 4 ) continue;
1304 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1305 const int* nInd = vol.GetFaceNodesIndices( iF );
1308 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1309 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1310 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1311 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1315 int iCom = 0; // common node of triangle faces to split into
1316 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1318 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1319 nInd[ iQ * ( (iCom+1)%nbNodes )],
1320 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1321 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1322 nInd[ iQ * ( (iCom+2)%nbNodes )],
1323 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1324 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1326 triaSplits.push_back( t012 );
1327 triaSplits.push_back( t023 );
1332 if ( !triaSplits.empty() )
1333 hasAdjacentSplits = true;
1336 // Among variants of split method select one compliant with adjacent volumes
1338 TSplitMethod method;
1339 if ( !vol.Element()->IsPoly() && !is24TetMode )
1341 int nbVariants = 2, nbTet = 0;
1342 const int** connVariants = 0;
1343 switch ( vol.Element()->GetEntityType() )
1345 case SMDSEntity_Hexa:
1346 case SMDSEntity_Quad_Hexa:
1347 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1348 connVariants = theHexTo5, nbTet = 5;
1350 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1352 case SMDSEntity_Pyramid:
1353 case SMDSEntity_Quad_Pyramid:
1354 connVariants = thePyraTo2; nbTet = 2;
1356 case SMDSEntity_Penta:
1357 case SMDSEntity_Quad_Penta:
1358 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1363 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1365 // check method compliancy with adjacent tetras,
1366 // all found splits must be among facets of tetras described by this method
1367 method = TSplitMethod( nbTet, connVariants[variant] );
1368 if ( hasAdjacentSplits && method._nbTetra > 0 )
1370 bool facetCreated = true;
1371 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1373 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1374 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1375 facetCreated = method.hasFacet( *facet );
1377 if ( !facetCreated )
1378 method = TSplitMethod(0); // incompatible method
1382 if ( method._nbTetra < 1 )
1384 // No standard method is applicable, use a generic solution:
1385 // each facet of a volume is split into triangles and
1386 // each of triangles and a volume barycenter form a tetrahedron.
1388 int* connectivity = new int[ maxTetConnSize + 1 ];
1389 method._connectivity = connectivity;
1390 method._ownConn = true;
1391 method._baryNode = true;
1394 int baryCenInd = vol.NbNodes();
1395 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1397 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1398 const int* nInd = vol.GetFaceNodesIndices( iF );
1399 // find common node of triangle facets of tetra to create
1400 int iCommon = 0; // index in linear numeration
1401 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1402 if ( !triaSplits.empty() )
1405 const TTriangleFacet* facet = &triaSplits.front();
1406 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1407 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1408 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1411 else if ( nbNodes > 3 && !is24TetMode )
1413 // find the best method of splitting into triangles by aspect ratio
1414 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1415 map< double, int > badness2iCommon;
1416 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1417 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1418 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1419 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1421 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1422 nodes[ iQ*((iLast-1)%nbNodes)],
1423 nodes[ iQ*((iLast )%nbNodes)]);
1424 double badness = getBadRate( &tria, aspectRatio );
1425 badness2iCommon.insert( make_pair( badness, iCommon ));
1427 // use iCommon with lowest badness
1428 iCommon = badness2iCommon.begin()->second;
1430 if ( iCommon >= nbNodes )
1431 iCommon = 0; // something wrong
1433 // fill connectivity of tetrahedra based on a current face
1434 int nbTet = nbNodes - 2;
1435 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1437 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1438 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1440 for ( int i = 0; i < nbTet; ++i )
1442 int i1 = i, i2 = (i+1) % nbNodes;
1443 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1444 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1445 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1446 connectivity[ connSize++ ] = faceBaryCenInd;
1447 connectivity[ connSize++ ] = baryCenInd;
1452 for ( int i = 0; i < nbTet; ++i )
1454 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1455 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1456 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1457 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1458 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1459 connectivity[ connSize++ ] = baryCenInd;
1462 method._nbTetra += nbTet;
1464 connectivity[ connSize++ ] = -1;
1468 //================================================================================
1470 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1472 //================================================================================
1474 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1476 // find the tetrahedron including the three nodes of facet
1477 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1478 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1479 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1480 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1481 while ( volIt1->more() )
1483 const SMDS_MeshElement* v = volIt1->next();
1484 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1486 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1487 while ( volIt2->more() )
1488 if ( v != volIt2->next() )
1490 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1491 while ( volIt3->more() )
1492 if ( v == volIt3->next() )
1498 //=======================================================================
1500 * \brief A key of a face of volume
1502 //=======================================================================
1504 struct TVolumeFaceKey: pair< int, pair< int, int> >
1506 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1508 TIDSortedNodeSet sortedNodes;
1509 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1510 int nbNodes = vol.NbFaceNodes( iF );
1511 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1512 for ( int i = 0; i < nbNodes; i += iQ )
1513 sortedNodes.insert( fNodes[i] );
1514 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1515 first = (*(n++))->GetID();
1516 second.first = (*(n++))->GetID();
1517 second.second = (*(n++))->GetID();
1522 //=======================================================================
1523 //function : SplitVolumesIntoTetra
1524 //purpose : Split volumic elements into tetrahedra.
1525 //=======================================================================
1527 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1528 const int theMethodFlags)
1530 // std-like iterator on coordinates of nodes of mesh element
1531 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1532 NXyzIterator xyzEnd;
1534 SMDS_VolumeTool volTool;
1535 SMESH_MesherHelper helper( *GetMesh());
1537 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1538 SMESHDS_SubMesh* fSubMesh = subMesh;
1540 SMESH_SequenceOfElemPtr newNodes, newElems;
1542 // map face of volume to it's baricenrtic node
1543 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1546 TIDSortedElemSet::const_iterator elem = theElems.begin();
1547 for ( ; elem != theElems.end(); ++elem )
1549 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1550 if ( geomType <= SMDSEntity_Quad_Tetra )
1551 continue; // tetra or face or ...
1553 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1555 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1556 if ( splitMethod._nbTetra < 1 ) continue;
1558 // find submesh to add new tetras to
1559 if ( !subMesh || !subMesh->Contains( *elem ))
1561 int shapeID = FindShape( *elem );
1562 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1563 subMesh = GetMeshDS()->MeshElements( shapeID );
1566 if ( (*elem)->IsQuadratic() )
1569 // add quadratic links to the helper
1570 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1572 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1573 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1574 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1576 helper.SetIsQuadratic( true );
1581 helper.SetIsQuadratic( false );
1583 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1584 if ( splitMethod._baryNode )
1586 // make a node at barycenter
1587 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1588 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1589 nodes.push_back( gcNode );
1590 newNodes.Append( gcNode );
1592 if ( !splitMethod._faceBaryNode.empty() )
1594 // make or find baricentric nodes of faces
1595 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1596 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1598 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1599 volFace2BaryNode.insert
1600 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1603 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1604 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1606 nodes.push_back( iF_n->second = f_n->second );
1611 helper.SetElementsOnShape( true );
1612 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1613 const int* tetConn = splitMethod._connectivity;
1614 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1615 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1616 nodes[ tetConn[1] ],
1617 nodes[ tetConn[2] ],
1618 nodes[ tetConn[3] ]));
1620 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1622 // Split faces on sides of the split volume
1624 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1625 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1627 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1628 if ( nbNodes < 4 ) continue;
1630 // find an existing face
1631 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1632 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1633 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1636 helper.SetElementsOnShape( false );
1637 vector< const SMDS_MeshElement* > triangles;
1639 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1640 if ( iF_n != splitMethod._faceBaryNode.end() )
1642 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1644 const SMDS_MeshNode* n1 = fNodes[iN];
1645 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1646 const SMDS_MeshNode *n3 = iF_n->second;
1647 if ( !volTool.IsFaceExternal( iF ))
1649 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1654 // among possible triangles create ones discribed by split method
1655 const int* nInd = volTool.GetFaceNodesIndices( iF );
1656 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1657 int iCom = 0; // common node of triangle faces to split into
1658 list< TTriangleFacet > facets;
1659 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1661 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1662 nInd[ iQ * ( (iCom+1)%nbNodes )],
1663 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1664 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1665 nInd[ iQ * ( (iCom+2)%nbNodes )],
1666 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1667 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1669 facets.push_back( t012 );
1670 facets.push_back( t023 );
1671 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1672 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1673 nInd[ iQ * ((iLast-1)%nbNodes )],
1674 nInd[ iQ * ((iLast )%nbNodes )]));
1678 list< TTriangleFacet >::iterator facet = facets.begin();
1679 for ( ; facet != facets.end(); ++facet )
1681 if ( !volTool.IsFaceExternal( iF ))
1682 swap( facet->_n2, facet->_n3 );
1683 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1684 volNodes[ facet->_n2 ],
1685 volNodes[ facet->_n3 ]));
1688 // find submesh to add new triangles in
1689 if ( !fSubMesh || !fSubMesh->Contains( face ))
1691 int shapeID = FindShape( face );
1692 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1694 for ( int i = 0; i < triangles.size(); ++i )
1696 if ( !triangles.back() ) continue;
1698 fSubMesh->AddElement( triangles.back());
1699 newElems.Append( triangles.back() );
1701 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1702 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1705 } // loop on volume faces to split them into triangles
1707 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1709 } // loop on volumes to split
1711 myLastCreatedNodes = newNodes;
1712 myLastCreatedElems = newElems;
1715 //=======================================================================
1716 //function : AddToSameGroups
1717 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1718 //=======================================================================
1720 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1721 const SMDS_MeshElement* elemInGroups,
1722 SMESHDS_Mesh * aMesh)
1724 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1725 if (!groups.empty()) {
1726 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1727 for ( ; grIt != groups.end(); grIt++ ) {
1728 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1729 if ( group && group->Contains( elemInGroups ))
1730 group->SMDSGroup().Add( elemToAdd );
1736 //=======================================================================
1737 //function : RemoveElemFromGroups
1738 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1739 //=======================================================================
1740 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1741 SMESHDS_Mesh * aMesh)
1743 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1744 if (!groups.empty())
1746 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1747 for (; GrIt != groups.end(); GrIt++)
1749 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1750 if (!grp || grp->IsEmpty()) continue;
1751 grp->SMDSGroup().Remove(removeelem);
1756 //================================================================================
1758 * \brief Replace elemToRm by elemToAdd in the all groups
1760 //================================================================================
1762 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1763 const SMDS_MeshElement* elemToAdd,
1764 SMESHDS_Mesh * aMesh)
1766 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1767 if (!groups.empty()) {
1768 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1769 for ( ; grIt != groups.end(); grIt++ ) {
1770 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1771 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1772 group->SMDSGroup().Add( elemToAdd );
1777 //================================================================================
1779 * \brief Replace elemToRm by elemToAdd in the all groups
1781 //================================================================================
1783 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1784 const vector<const SMDS_MeshElement*>& elemToAdd,
1785 SMESHDS_Mesh * aMesh)
1787 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1788 if (!groups.empty())
1790 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1791 for ( ; grIt != groups.end(); grIt++ ) {
1792 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1793 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1794 for ( int i = 0; i < elemToAdd.size(); ++i )
1795 group->SMDSGroup().Add( elemToAdd[ i ] );
1800 //=======================================================================
1801 //function : QuadToTri
1802 //purpose : Cut quadrangles into triangles.
1803 // theCrit is used to select a diagonal to cut
1804 //=======================================================================
1806 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1807 const bool the13Diag)
1809 myLastCreatedElems.Clear();
1810 myLastCreatedNodes.Clear();
1812 MESSAGE( "::QuadToTri()" );
1814 SMESHDS_Mesh * aMesh = GetMeshDS();
1816 Handle(Geom_Surface) surface;
1817 SMESH_MesherHelper helper( *GetMesh() );
1819 TIDSortedElemSet::iterator itElem;
1820 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1821 const SMDS_MeshElement* elem = *itElem;
1822 if ( !elem || elem->GetType() != SMDSAbs_Face )
1824 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1825 if(!isquad) continue;
1827 if(elem->NbNodes()==4) {
1828 // retrieve element nodes
1829 const SMDS_MeshNode* aNodes [4];
1830 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1832 while ( itN->more() )
1833 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1835 int aShapeId = FindShape( elem );
1836 const SMDS_MeshElement* newElem = 0;
1838 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1839 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1842 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1843 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1845 myLastCreatedElems.Append(newElem);
1846 // put a new triangle on the same shape and add to the same groups
1848 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1849 AddToSameGroups( newElem, elem, aMesh );
1852 // Quadratic quadrangle
1854 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1856 // get surface elem is on
1857 int aShapeId = FindShape( elem );
1858 if ( aShapeId != helper.GetSubShapeID() ) {
1862 shape = aMesh->IndexToShape( aShapeId );
1863 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1864 TopoDS_Face face = TopoDS::Face( shape );
1865 surface = BRep_Tool::Surface( face );
1866 if ( !surface.IsNull() )
1867 helper.SetSubShape( shape );
1871 const SMDS_MeshNode* aNodes [8];
1872 const SMDS_MeshNode* inFaceNode = 0;
1873 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1875 while ( itN->more() ) {
1876 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1877 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1878 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1880 inFaceNode = aNodes[ i-1 ];
1884 // find middle point for (0,1,2,3)
1885 // and create a node in this point;
1887 if ( surface.IsNull() ) {
1889 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1893 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1896 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1898 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1900 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1901 myLastCreatedNodes.Append(newN);
1903 // create a new element
1904 const SMDS_MeshElement* newElem = 0;
1905 const SMDS_MeshNode* N[6];
1913 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1914 aNodes[6], aNodes[7], newN );
1923 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1924 aNodes[7], aNodes[4], newN );
1926 myLastCreatedElems.Append(newElem);
1927 aMesh->ChangeElementNodes( elem, N, 6 );
1928 // put a new triangle on the same shape and add to the same groups
1930 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1931 AddToSameGroups( newElem, elem, aMesh );
1938 //=======================================================================
1939 //function : getAngle
1941 //=======================================================================
1943 double getAngle(const SMDS_MeshElement * tr1,
1944 const SMDS_MeshElement * tr2,
1945 const SMDS_MeshNode * n1,
1946 const SMDS_MeshNode * n2)
1948 double angle = 2*PI; // bad angle
1951 SMESH::Controls::TSequenceOfXYZ P1, P2;
1952 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1953 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1956 if(!tr1->IsQuadratic())
1957 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1959 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1960 if ( N1.SquareMagnitude() <= gp::Resolution() )
1962 if(!tr2->IsQuadratic())
1963 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1965 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1966 if ( N2.SquareMagnitude() <= gp::Resolution() )
1969 // find the first diagonal node n1 in the triangles:
1970 // take in account a diagonal link orientation
1971 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1972 for ( int t = 0; t < 2; t++ ) {
1973 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1974 int i = 0, iDiag = -1;
1975 while ( it->more()) {
1976 const SMDS_MeshElement *n = it->next();
1977 if ( n == n1 || n == n2 )
1981 if ( i - iDiag == 1 )
1982 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1990 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1993 angle = N1.Angle( N2 );
1998 // =================================================
1999 // class generating a unique ID for a pair of nodes
2000 // and able to return nodes by that ID
2001 // =================================================
2005 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2006 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2009 long GetLinkID (const SMDS_MeshNode * n1,
2010 const SMDS_MeshNode * n2) const
2012 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2015 bool GetNodes (const long theLinkID,
2016 const SMDS_MeshNode* & theNode1,
2017 const SMDS_MeshNode* & theNode2) const
2019 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2020 if ( !theNode1 ) return false;
2021 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2022 if ( !theNode2 ) return false;
2028 const SMESHDS_Mesh* myMesh;
2033 //=======================================================================
2034 //function : TriToQuad
2035 //purpose : Fuse neighbour triangles into quadrangles.
2036 // theCrit is used to select a neighbour to fuse with.
2037 // theMaxAngle is a max angle between element normals at which
2038 // fusion is still performed.
2039 //=======================================================================
2041 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2042 SMESH::Controls::NumericalFunctorPtr theCrit,
2043 const double theMaxAngle)
2045 myLastCreatedElems.Clear();
2046 myLastCreatedNodes.Clear();
2048 MESSAGE( "::TriToQuad()" );
2050 if ( !theCrit.get() )
2053 SMESHDS_Mesh * aMesh = GetMeshDS();
2055 // Prepare data for algo: build
2056 // 1. map of elements with their linkIDs
2057 // 2. map of linkIDs with their elements
2059 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2060 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2061 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2062 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2064 TIDSortedElemSet::iterator itElem;
2065 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2066 const SMDS_MeshElement* elem = *itElem;
2067 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2068 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2069 if(!IsTria) continue;
2071 // retrieve element nodes
2072 const SMDS_MeshNode* aNodes [4];
2073 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2076 aNodes[ i++ ] = cast2Node( itN->next() );
2077 aNodes[ 3 ] = aNodes[ 0 ];
2080 for ( i = 0; i < 3; i++ ) {
2081 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2082 // check if elements sharing a link can be fused
2083 itLE = mapLi_listEl.find( link );
2084 if ( itLE != mapLi_listEl.end() ) {
2085 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2087 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2088 //if ( FindShape( elem ) != FindShape( elem2 ))
2089 // continue; // do not fuse triangles laying on different shapes
2090 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2091 continue; // avoid making badly shaped quads
2092 (*itLE).second.push_back( elem );
2095 mapLi_listEl[ link ].push_back( elem );
2097 mapEl_setLi [ elem ].insert( link );
2100 // Clean the maps from the links shared by a sole element, ie
2101 // links to which only one element is bound in mapLi_listEl
2103 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2104 int nbElems = (*itLE).second.size();
2105 if ( nbElems < 2 ) {
2106 const SMDS_MeshElement* elem = (*itLE).second.front();
2107 SMESH_TLink link = (*itLE).first;
2108 mapEl_setLi[ elem ].erase( link );
2109 if ( mapEl_setLi[ elem ].empty() )
2110 mapEl_setLi.erase( elem );
2114 // Algo: fuse triangles into quadrangles
2116 while ( ! mapEl_setLi.empty() ) {
2117 // Look for the start element:
2118 // the element having the least nb of shared links
2119 const SMDS_MeshElement* startElem = 0;
2121 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2122 int nbLinks = (*itEL).second.size();
2123 if ( nbLinks < minNbLinks ) {
2124 startElem = (*itEL).first;
2125 minNbLinks = nbLinks;
2126 if ( minNbLinks == 1 )
2131 // search elements to fuse starting from startElem or links of elements
2132 // fused earlyer - startLinks
2133 list< SMESH_TLink > startLinks;
2134 while ( startElem || !startLinks.empty() ) {
2135 while ( !startElem && !startLinks.empty() ) {
2136 // Get an element to start, by a link
2137 SMESH_TLink linkId = startLinks.front();
2138 startLinks.pop_front();
2139 itLE = mapLi_listEl.find( linkId );
2140 if ( itLE != mapLi_listEl.end() ) {
2141 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2142 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2143 for ( ; itE != listElem.end() ; itE++ )
2144 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2146 mapLi_listEl.erase( itLE );
2151 // Get candidates to be fused
2152 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2153 const SMESH_TLink *link12, *link13;
2155 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2156 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2157 ASSERT( !setLi.empty() );
2158 set< SMESH_TLink >::iterator itLi;
2159 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2161 const SMESH_TLink & link = (*itLi);
2162 itLE = mapLi_listEl.find( link );
2163 if ( itLE == mapLi_listEl.end() )
2166 const SMDS_MeshElement* elem = (*itLE).second.front();
2168 elem = (*itLE).second.back();
2169 mapLi_listEl.erase( itLE );
2170 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2181 // add other links of elem to list of links to re-start from
2182 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2183 set< SMESH_TLink >::iterator it;
2184 for ( it = links.begin(); it != links.end(); it++ ) {
2185 const SMESH_TLink& link2 = (*it);
2186 if ( link2 != link )
2187 startLinks.push_back( link2 );
2191 // Get nodes of possible quadrangles
2192 const SMDS_MeshNode *n12 [4], *n13 [4];
2193 bool Ok12 = false, Ok13 = false;
2194 const SMDS_MeshNode *linkNode1, *linkNode2;
2196 linkNode1 = link12->first;
2197 linkNode2 = link12->second;
2198 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2202 linkNode1 = link13->first;
2203 linkNode2 = link13->second;
2204 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2208 // Choose a pair to fuse
2209 if ( Ok12 && Ok13 ) {
2210 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2211 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2212 double aBadRate12 = getBadRate( &quad12, theCrit );
2213 double aBadRate13 = getBadRate( &quad13, theCrit );
2214 if ( aBadRate13 < aBadRate12 )
2221 // and remove fused elems and removed links from the maps
2222 mapEl_setLi.erase( tr1 );
2224 mapEl_setLi.erase( tr2 );
2225 mapLi_listEl.erase( *link12 );
2226 if(tr1->NbNodes()==3) {
2227 if( tr1->GetID() < tr2->GetID() ) {
2228 aMesh->ChangeElementNodes( tr1, n12, 4 );
2229 myLastCreatedElems.Append(tr1);
2230 aMesh->RemoveElement( tr2 );
2233 aMesh->ChangeElementNodes( tr2, n12, 4 );
2234 myLastCreatedElems.Append(tr2);
2235 aMesh->RemoveElement( tr1);
2239 const SMDS_MeshNode* N1 [6];
2240 const SMDS_MeshNode* N2 [6];
2241 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2242 // now we receive following N1 and N2 (using numeration as above image)
2243 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2244 // i.e. first nodes from both arrays determ new diagonal
2245 const SMDS_MeshNode* aNodes[8];
2254 if( tr1->GetID() < tr2->GetID() ) {
2255 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2256 myLastCreatedElems.Append(tr1);
2257 GetMeshDS()->RemoveElement( tr2 );
2260 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
2261 myLastCreatedElems.Append(tr2);
2262 GetMeshDS()->RemoveElement( tr1 );
2264 // remove middle node (9)
2265 GetMeshDS()->RemoveNode( N1[4] );
2269 mapEl_setLi.erase( tr3 );
2270 mapLi_listEl.erase( *link13 );
2271 if(tr1->NbNodes()==3) {
2272 if( tr1->GetID() < tr2->GetID() ) {
2273 aMesh->ChangeElementNodes( tr1, n13, 4 );
2274 myLastCreatedElems.Append(tr1);
2275 aMesh->RemoveElement( tr3 );
2278 aMesh->ChangeElementNodes( tr3, n13, 4 );
2279 myLastCreatedElems.Append(tr3);
2280 aMesh->RemoveElement( tr1 );
2284 const SMDS_MeshNode* N1 [6];
2285 const SMDS_MeshNode* N2 [6];
2286 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2287 // now we receive following N1 and N2 (using numeration as above image)
2288 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2289 // i.e. first nodes from both arrays determ new diagonal
2290 const SMDS_MeshNode* aNodes[8];
2299 if( tr1->GetID() < tr2->GetID() ) {
2300 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
2301 myLastCreatedElems.Append(tr1);
2302 GetMeshDS()->RemoveElement( tr3 );
2305 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
2306 myLastCreatedElems.Append(tr3);
2307 GetMeshDS()->RemoveElement( tr1 );
2309 // remove middle node (9)
2310 GetMeshDS()->RemoveNode( N1[4] );
2314 // Next element to fuse: the rejected one
2316 startElem = Ok12 ? tr3 : tr2;
2318 } // if ( startElem )
2319 } // while ( startElem || !startLinks.empty() )
2320 } // while ( ! mapEl_setLi.empty() )
2326 /*#define DUMPSO(txt) \
2327 // cout << txt << endl;
2328 //=============================================================================
2332 //=============================================================================
2333 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2337 int tmp = idNodes[ i1 ];
2338 idNodes[ i1 ] = idNodes[ i2 ];
2339 idNodes[ i2 ] = tmp;
2340 gp_Pnt Ptmp = P[ i1 ];
2343 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2346 //=======================================================================
2347 //function : SortQuadNodes
2348 //purpose : Set 4 nodes of a quadrangle face in a good order.
2349 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2351 //=======================================================================
2353 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2358 for ( i = 0; i < 4; i++ ) {
2359 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2361 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2364 gp_Vec V1(P[0], P[1]);
2365 gp_Vec V2(P[0], P[2]);
2366 gp_Vec V3(P[0], P[3]);
2368 gp_Vec Cross1 = V1 ^ V2;
2369 gp_Vec Cross2 = V2 ^ V3;
2372 if (Cross1.Dot(Cross2) < 0)
2377 if (Cross1.Dot(Cross2) < 0)
2381 swap ( i, i + 1, idNodes, P );
2383 // for ( int ii = 0; ii < 4; ii++ ) {
2384 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2385 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2391 //=======================================================================
2392 //function : SortHexaNodes
2393 //purpose : Set 8 nodes of a hexahedron in a good order.
2394 // Return success status
2395 //=======================================================================
2397 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2402 DUMPSO( "INPUT: ========================================");
2403 for ( i = 0; i < 8; i++ ) {
2404 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2405 if ( !n ) return false;
2406 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2407 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2409 DUMPSO( "========================================");
2412 set<int> faceNodes; // ids of bottom face nodes, to be found
2413 set<int> checkedId1; // ids of tried 2-nd nodes
2414 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2415 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2416 int iMin, iLoop1 = 0;
2418 // Loop to try the 2-nd nodes
2420 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2422 // Find not checked 2-nd node
2423 for ( i = 1; i < 8; i++ )
2424 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2425 int id1 = idNodes[i];
2426 swap ( 1, i, idNodes, P );
2427 checkedId1.insert ( id1 );
2431 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2432 // ie that all but meybe one (id3 which is on the same face) nodes
2433 // lay on the same side from the triangle plane.
2435 bool manyInPlane = false; // more than 4 nodes lay in plane
2437 while ( ++iLoop2 < 6 ) {
2439 // get 1-2-3 plane coeffs
2440 Standard_Real A, B, C, D;
2441 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2442 if ( N.SquareMagnitude() > gp::Resolution() )
2444 gp_Pln pln ( P[0], N );
2445 pln.Coefficients( A, B, C, D );
2447 // find the node (iMin) closest to pln
2448 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2450 for ( i = 3; i < 8; i++ ) {
2451 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2452 if ( fabs( dist[i] ) < minDist ) {
2453 minDist = fabs( dist[i] );
2456 if ( fabs( dist[i] ) <= tol )
2457 idInPln.insert( idNodes[i] );
2460 // there should not be more than 4 nodes in bottom plane
2461 if ( idInPln.size() > 1 )
2463 DUMPSO( "### idInPln.size() = " << idInPln.size());
2464 // idInPlane does not contain the first 3 nodes
2465 if ( manyInPlane || idInPln.size() == 5)
2466 return false; // all nodes in one plane
2469 // set the 1-st node to be not in plane
2470 for ( i = 3; i < 8; i++ ) {
2471 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2472 DUMPSO( "### Reset 0-th node");
2473 swap( 0, i, idNodes, P );
2478 // reset to re-check second nodes
2479 leastDist = DBL_MAX;
2483 break; // from iLoop2;
2486 // check that the other 4 nodes are on the same side
2487 bool sameSide = true;
2488 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2489 for ( i = 3; sameSide && i < 8; i++ ) {
2491 sameSide = ( isNeg == dist[i] <= 0.);
2494 // keep best solution
2495 if ( sameSide && minDist < leastDist ) {
2496 leastDist = minDist;
2498 faceNodes.insert( idNodes[ 1 ] );
2499 faceNodes.insert( idNodes[ 2 ] );
2500 faceNodes.insert( idNodes[ iMin ] );
2501 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2502 << " leastDist = " << leastDist);
2503 if ( leastDist <= DBL_MIN )
2508 // set next 3-d node to check
2509 int iNext = 2 + iLoop2;
2511 DUMPSO( "Try 2-nd");
2512 swap ( 2, iNext, idNodes, P );
2514 } // while ( iLoop2 < 6 )
2517 if ( faceNodes.empty() ) return false;
2519 // Put the faceNodes in proper places
2520 for ( i = 4; i < 8; i++ ) {
2521 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2522 // find a place to put
2524 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2526 DUMPSO( "Set faceNodes");
2527 swap ( iTo, i, idNodes, P );
2532 // Set nodes of the found bottom face in good order
2533 DUMPSO( " Found bottom face: ");
2534 i = SortQuadNodes( theMesh, idNodes );
2536 gp_Pnt Ptmp = P[ i ];
2541 // for ( int ii = 0; ii < 4; ii++ ) {
2542 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2543 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2546 // Gravity center of the top and bottom faces
2547 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2548 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2550 // Get direction from the bottom to the top face
2551 gp_Vec upDir ( aGCb, aGCt );
2552 Standard_Real upDirSize = upDir.Magnitude();
2553 if ( upDirSize <= gp::Resolution() ) return false;
2556 // Assure that the bottom face normal points up
2557 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2558 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2559 if ( Nb.Dot( upDir ) < 0 ) {
2560 DUMPSO( "Reverse bottom face");
2561 swap( 1, 3, idNodes, P );
2564 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2565 Standard_Real minDist = DBL_MAX;
2566 for ( i = 4; i < 8; i++ ) {
2567 // projection of P[i] to the plane defined by P[0] and upDir
2568 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2569 Standard_Real sqDist = P[0].SquareDistance( Pp );
2570 if ( sqDist < minDist ) {
2575 DUMPSO( "Set 4-th");
2576 swap ( 4, iMin, idNodes, P );
2578 // Set nodes of the top face in good order
2579 DUMPSO( "Sort top face");
2580 i = SortQuadNodes( theMesh, &idNodes[4] );
2583 gp_Pnt Ptmp = P[ i ];
2588 // Assure that direction of the top face normal is from the bottom face
2589 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2590 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2591 if ( Nt.Dot( upDir ) < 0 ) {
2592 DUMPSO( "Reverse top face");
2593 swap( 5, 7, idNodes, P );
2596 // DUMPSO( "OUTPUT: ========================================");
2597 // for ( i = 0; i < 8; i++ ) {
2598 // float *p = ugrid->GetPoint(idNodes[i]);
2599 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2605 //================================================================================
2607 * \brief Return nodes linked to the given one
2608 * \param theNode - the node
2609 * \param linkedNodes - the found nodes
2610 * \param type - the type of elements to check
2612 * Medium nodes are ignored
2614 //================================================================================
2616 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2617 TIDSortedElemSet & linkedNodes,
2618 SMDSAbs_ElementType type )
2620 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2621 while ( elemIt->more() )
2623 const SMDS_MeshElement* elem = elemIt->next();
2624 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2625 if ( elem->GetType() == SMDSAbs_Volume )
2627 SMDS_VolumeTool vol( elem );
2628 while ( nodeIt->more() ) {
2629 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2630 if ( theNode != n && vol.IsLinked( theNode, n ))
2631 linkedNodes.insert( n );
2636 for ( int i = 0; nodeIt->more(); ++i ) {
2637 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2638 if ( n == theNode ) {
2639 int iBefore = i - 1;
2641 if ( elem->IsQuadratic() ) {
2642 int nb = elem->NbNodes() / 2;
2643 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2644 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2646 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2647 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2654 //=======================================================================
2655 //function : laplacianSmooth
2656 //purpose : pulls theNode toward the center of surrounding nodes directly
2657 // connected to that node along an element edge
2658 //=======================================================================
2660 void laplacianSmooth(const SMDS_MeshNode* theNode,
2661 const Handle(Geom_Surface)& theSurface,
2662 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2664 // find surrounding nodes
2666 TIDSortedElemSet nodeSet;
2667 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2669 // compute new coodrs
2671 double coord[] = { 0., 0., 0. };
2672 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2673 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2674 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2675 if ( theSurface.IsNull() ) { // smooth in 3D
2676 coord[0] += node->X();
2677 coord[1] += node->Y();
2678 coord[2] += node->Z();
2680 else { // smooth in 2D
2681 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2682 gp_XY* uv = theUVMap[ node ];
2683 coord[0] += uv->X();
2684 coord[1] += uv->Y();
2687 int nbNodes = nodeSet.size();
2690 coord[0] /= nbNodes;
2691 coord[1] /= nbNodes;
2693 if ( !theSurface.IsNull() ) {
2694 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2695 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2696 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2702 coord[2] /= nbNodes;
2706 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2709 //=======================================================================
2710 //function : centroidalSmooth
2711 //purpose : pulls theNode toward the element-area-weighted centroid of the
2712 // surrounding elements
2713 //=======================================================================
2715 void centroidalSmooth(const SMDS_MeshNode* theNode,
2716 const Handle(Geom_Surface)& theSurface,
2717 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2719 gp_XYZ aNewXYZ(0.,0.,0.);
2720 SMESH::Controls::Area anAreaFunc;
2721 double totalArea = 0.;
2726 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2727 while ( elemIt->more() )
2729 const SMDS_MeshElement* elem = elemIt->next();
2732 gp_XYZ elemCenter(0.,0.,0.);
2733 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2734 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2735 int nn = elem->NbNodes();
2736 if(elem->IsQuadratic()) nn = nn/2;
2738 //while ( itN->more() ) {
2740 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2742 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2743 aNodePoints.push_back( aP );
2744 if ( !theSurface.IsNull() ) { // smooth in 2D
2745 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2746 gp_XY* uv = theUVMap[ aNode ];
2747 aP.SetCoord( uv->X(), uv->Y(), 0. );
2751 double elemArea = anAreaFunc.GetValue( aNodePoints );
2752 totalArea += elemArea;
2754 aNewXYZ += elemCenter * elemArea;
2756 aNewXYZ /= totalArea;
2757 if ( !theSurface.IsNull() ) {
2758 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2759 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2764 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2767 //=======================================================================
2768 //function : getClosestUV
2769 //purpose : return UV of closest projection
2770 //=======================================================================
2772 static bool getClosestUV (Extrema_GenExtPS& projector,
2773 const gp_Pnt& point,
2776 projector.Perform( point );
2777 if ( projector.IsDone() ) {
2778 double u, v, minVal = DBL_MAX;
2779 for ( int i = projector.NbExt(); i > 0; i-- )
2780 if ( projector.Value( i ) < minVal ) {
2781 minVal = projector.Value( i );
2782 projector.Point( i ).Parameter( u, v );
2784 result.SetCoord( u, v );
2790 //=======================================================================
2792 //purpose : Smooth theElements during theNbIterations or until a worst
2793 // element has aspect ratio <= theTgtAspectRatio.
2794 // Aspect Ratio varies in range [1.0, inf].
2795 // If theElements is empty, the whole mesh is smoothed.
2796 // theFixedNodes contains additionally fixed nodes. Nodes built
2797 // on edges and boundary nodes are always fixed.
2798 //=======================================================================
2800 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2801 set<const SMDS_MeshNode*> & theFixedNodes,
2802 const SmoothMethod theSmoothMethod,
2803 const int theNbIterations,
2804 double theTgtAspectRatio,
2807 myLastCreatedElems.Clear();
2808 myLastCreatedNodes.Clear();
2810 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2812 if ( theTgtAspectRatio < 1.0 )
2813 theTgtAspectRatio = 1.0;
2815 const double disttol = 1.e-16;
2817 SMESH::Controls::AspectRatio aQualityFunc;
2819 SMESHDS_Mesh* aMesh = GetMeshDS();
2821 if ( theElems.empty() ) {
2822 // add all faces to theElems
2823 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2824 while ( fIt->more() ) {
2825 const SMDS_MeshElement* face = fIt->next();
2826 theElems.insert( face );
2829 // get all face ids theElems are on
2830 set< int > faceIdSet;
2831 TIDSortedElemSet::iterator itElem;
2833 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2834 int fId = FindShape( *itElem );
2835 // check that corresponding submesh exists and a shape is face
2837 faceIdSet.find( fId ) == faceIdSet.end() &&
2838 aMesh->MeshElements( fId )) {
2839 TopoDS_Shape F = aMesh->IndexToShape( fId );
2840 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2841 faceIdSet.insert( fId );
2844 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2846 // ===============================================
2847 // smooth elements on each TopoDS_Face separately
2848 // ===============================================
2850 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2851 for ( ; fId != faceIdSet.rend(); ++fId ) {
2852 // get face surface and submesh
2853 Handle(Geom_Surface) surface;
2854 SMESHDS_SubMesh* faceSubMesh = 0;
2856 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2857 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2858 bool isUPeriodic = false, isVPeriodic = false;
2860 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2861 surface = BRep_Tool::Surface( face );
2862 faceSubMesh = aMesh->MeshElements( *fId );
2863 fToler2 = BRep_Tool::Tolerance( face );
2864 fToler2 *= fToler2 * 10.;
2865 isUPeriodic = surface->IsUPeriodic();
2867 vPeriod = surface->UPeriod();
2868 isVPeriodic = surface->IsVPeriodic();
2870 uPeriod = surface->VPeriod();
2871 surface->Bounds( u1, u2, v1, v2 );
2873 // ---------------------------------------------------------
2874 // for elements on a face, find movable and fixed nodes and
2875 // compute UV for them
2876 // ---------------------------------------------------------
2877 bool checkBoundaryNodes = false;
2878 bool isQuadratic = false;
2879 set<const SMDS_MeshNode*> setMovableNodes;
2880 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2881 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2882 list< const SMDS_MeshElement* > elemsOnFace;
2884 Extrema_GenExtPS projector;
2885 GeomAdaptor_Surface surfAdaptor;
2886 if ( !surface.IsNull() ) {
2887 surfAdaptor.Load( surface );
2888 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2890 int nbElemOnFace = 0;
2891 itElem = theElems.begin();
2892 // loop on not yet smoothed elements: look for elems on a face
2893 while ( itElem != theElems.end() ) {
2894 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2895 break; // all elements found
2897 const SMDS_MeshElement* elem = *itElem;
2898 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2899 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2903 elemsOnFace.push_back( elem );
2904 theElems.erase( itElem++ );
2908 isQuadratic = elem->IsQuadratic();
2910 // get movable nodes of elem
2911 const SMDS_MeshNode* node;
2912 SMDS_TypeOfPosition posType;
2913 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2914 int nn = 0, nbn = elem->NbNodes();
2915 if(elem->IsQuadratic())
2917 while ( nn++ < nbn ) {
2918 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2919 const SMDS_PositionPtr& pos = node->GetPosition();
2920 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2921 if (posType != SMDS_TOP_EDGE &&
2922 posType != SMDS_TOP_VERTEX &&
2923 theFixedNodes.find( node ) == theFixedNodes.end())
2925 // check if all faces around the node are on faceSubMesh
2926 // because a node on edge may be bound to face
2927 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2929 if ( faceSubMesh ) {
2930 while ( eIt->more() && all ) {
2931 const SMDS_MeshElement* e = eIt->next();
2932 all = faceSubMesh->Contains( e );
2936 setMovableNodes.insert( node );
2938 checkBoundaryNodes = true;
2940 if ( posType == SMDS_TOP_3DSPACE )
2941 checkBoundaryNodes = true;
2944 if ( surface.IsNull() )
2947 // get nodes to check UV
2948 list< const SMDS_MeshNode* > uvCheckNodes;
2949 itN = elem->nodesIterator();
2950 nn = 0; nbn = elem->NbNodes();
2951 if(elem->IsQuadratic())
2953 while ( nn++ < nbn ) {
2954 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2955 if ( uvMap.find( node ) == uvMap.end() )
2956 uvCheckNodes.push_back( node );
2957 // add nodes of elems sharing node
2958 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2959 // while ( eIt->more() ) {
2960 // const SMDS_MeshElement* e = eIt->next();
2961 // if ( e != elem ) {
2962 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2963 // while ( nIt->more() ) {
2964 // const SMDS_MeshNode* n =
2965 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2966 // if ( uvMap.find( n ) == uvMap.end() )
2967 // uvCheckNodes.push_back( n );
2973 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2974 for ( ; n != uvCheckNodes.end(); ++n ) {
2977 const SMDS_PositionPtr& pos = node->GetPosition();
2978 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2980 switch ( posType ) {
2981 case SMDS_TOP_FACE: {
2982 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2983 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2986 case SMDS_TOP_EDGE: {
2987 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2988 Handle(Geom2d_Curve) pcurve;
2989 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2990 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2991 if ( !pcurve.IsNull() ) {
2992 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2993 uv = pcurve->Value( u ).XY();
2997 case SMDS_TOP_VERTEX: {
2998 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2999 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3000 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3005 // check existing UV
3006 bool project = true;
3007 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3008 double dist1 = DBL_MAX, dist2 = 0;
3009 if ( posType != SMDS_TOP_3DSPACE ) {
3010 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3011 project = dist1 > fToler2;
3013 if ( project ) { // compute new UV
3015 if ( !getClosestUV( projector, pNode, newUV )) {
3016 MESSAGE("Node Projection Failed " << node);
3020 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3022 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3024 if ( posType != SMDS_TOP_3DSPACE )
3025 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3026 if ( dist2 < dist1 )
3030 // store UV in the map
3031 listUV.push_back( uv );
3032 uvMap.insert( make_pair( node, &listUV.back() ));
3034 } // loop on not yet smoothed elements
3036 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3037 checkBoundaryNodes = true;
3039 // fix nodes on mesh boundary
3041 if ( checkBoundaryNodes ) {
3042 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3043 map< NLink, int >::iterator link_nb;
3044 // put all elements links to linkNbMap
3045 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3046 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3047 const SMDS_MeshElement* elem = (*elemIt);
3048 int nbn = elem->NbNodes();
3049 if(elem->IsQuadratic())
3051 // loop on elem links: insert them in linkNbMap
3052 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3053 for ( int iN = 0; iN < nbn; ++iN ) {
3054 curNode = elem->GetNode( iN );
3056 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3057 else link = make_pair( prevNode , curNode );
3059 link_nb = linkNbMap.find( link );
3060 if ( link_nb == linkNbMap.end() )
3061 linkNbMap.insert( make_pair ( link, 1 ));
3066 // remove nodes that are in links encountered only once from setMovableNodes
3067 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3068 if ( link_nb->second == 1 ) {
3069 setMovableNodes.erase( link_nb->first.first );
3070 setMovableNodes.erase( link_nb->first.second );
3075 // -----------------------------------------------------
3076 // for nodes on seam edge, compute one more UV ( uvMap2 );
3077 // find movable nodes linked to nodes on seam and which
3078 // are to be smoothed using the second UV ( uvMap2 )
3079 // -----------------------------------------------------
3081 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3082 if ( !surface.IsNull() ) {
3083 TopExp_Explorer eExp( face, TopAbs_EDGE );
3084 for ( ; eExp.More(); eExp.Next() ) {
3085 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3086 if ( !BRep_Tool::IsClosed( edge, face ))
3088 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3089 if ( !sm ) continue;
3090 // find out which parameter varies for a node on seam
3093 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3094 if ( pcurve.IsNull() ) continue;
3095 uv1 = pcurve->Value( f );
3097 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3098 if ( pcurve.IsNull() ) continue;
3099 uv2 = pcurve->Value( f );
3100 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3102 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3103 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3105 // get nodes on seam and its vertices
3106 list< const SMDS_MeshNode* > seamNodes;
3107 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3108 while ( nSeamIt->more() ) {
3109 const SMDS_MeshNode* node = nSeamIt->next();
3110 if ( !isQuadratic || !IsMedium( node ))
3111 seamNodes.push_back( node );
3113 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3114 for ( ; vExp.More(); vExp.Next() ) {
3115 sm = aMesh->MeshElements( vExp.Current() );
3117 nSeamIt = sm->GetNodes();
3118 while ( nSeamIt->more() )
3119 seamNodes.push_back( nSeamIt->next() );
3122 // loop on nodes on seam
3123 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3124 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3125 const SMDS_MeshNode* nSeam = *noSeIt;
3126 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3127 if ( n_uv == uvMap.end() )
3130 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3131 // set the second UV
3132 listUV.push_back( *n_uv->second );
3133 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3134 if ( uvMap2.empty() )
3135 uvMap2 = uvMap; // copy the uvMap contents
3136 uvMap2[ nSeam ] = &listUV.back();
3138 // collect movable nodes linked to ones on seam in nodesNearSeam
3139 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3140 while ( eIt->more() ) {
3141 const SMDS_MeshElement* e = eIt->next();
3142 int nbUseMap1 = 0, nbUseMap2 = 0;
3143 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3144 int nn = 0, nbn = e->NbNodes();
3145 if(e->IsQuadratic()) nbn = nbn/2;
3146 while ( nn++ < nbn )
3148 const SMDS_MeshNode* n =
3149 static_cast<const SMDS_MeshNode*>( nIt->next() );
3151 setMovableNodes.find( n ) == setMovableNodes.end() )
3153 // add only nodes being closer to uv2 than to uv1
3154 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3155 0.5 * ( n->Y() + nSeam->Y() ),
3156 0.5 * ( n->Z() + nSeam->Z() ));
3158 getClosestUV( projector, pMid, uv );
3159 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3160 nodesNearSeam.insert( n );
3166 // for centroidalSmooth all element nodes must
3167 // be on one side of a seam
3168 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3169 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3171 while ( nn++ < nbn ) {
3172 const SMDS_MeshNode* n =
3173 static_cast<const SMDS_MeshNode*>( nIt->next() );
3174 setMovableNodes.erase( n );
3178 } // loop on nodes on seam
3179 } // loop on edge of a face
3180 } // if ( !face.IsNull() )
3182 if ( setMovableNodes.empty() ) {
3183 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3184 continue; // goto next face
3192 double maxRatio = -1., maxDisplacement = -1.;
3193 set<const SMDS_MeshNode*>::iterator nodeToMove;
3194 for ( it = 0; it < theNbIterations; it++ ) {
3195 maxDisplacement = 0.;
3196 nodeToMove = setMovableNodes.begin();
3197 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3198 const SMDS_MeshNode* node = (*nodeToMove);
3199 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3202 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3203 if ( theSmoothMethod == LAPLACIAN )
3204 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3206 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3208 // node displacement
3209 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3210 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3211 if ( aDispl > maxDisplacement )
3212 maxDisplacement = aDispl;
3214 // no node movement => exit
3215 //if ( maxDisplacement < 1.e-16 ) {
3216 if ( maxDisplacement < disttol ) {
3217 MESSAGE("-- no node movement --");
3221 // check elements quality
3223 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3224 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3225 const SMDS_MeshElement* elem = (*elemIt);
3226 if ( !elem || elem->GetType() != SMDSAbs_Face )
3228 SMESH::Controls::TSequenceOfXYZ aPoints;
3229 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3230 double aValue = aQualityFunc.GetValue( aPoints );
3231 if ( aValue > maxRatio )
3235 if ( maxRatio <= theTgtAspectRatio ) {
3236 MESSAGE("-- quality achived --");
3239 if (it+1 == theNbIterations) {
3240 MESSAGE("-- Iteration limit exceeded --");
3242 } // smoothing iterations
3244 MESSAGE(" Face id: " << *fId <<
3245 " Nb iterstions: " << it <<
3246 " Displacement: " << maxDisplacement <<
3247 " Aspect Ratio " << maxRatio);
3249 // ---------------------------------------
3250 // new nodes positions are computed,
3251 // record movement in DS and set new UV
3252 // ---------------------------------------
3253 nodeToMove = setMovableNodes.begin();
3254 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3255 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3256 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3257 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3258 if ( node_uv != uvMap.end() ) {
3259 gp_XY* uv = node_uv->second;
3261 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
3265 // move medium nodes of quadratic elements
3268 SMESH_MesherHelper helper( *GetMesh() );
3269 if ( !face.IsNull() )
3270 helper.SetSubShape( face );
3271 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3272 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3273 const SMDS_QuadraticFaceOfNodes* QF =
3274 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
3276 vector<const SMDS_MeshNode*> Ns;
3277 Ns.reserve(QF->NbNodes()+1);
3278 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
3279 while ( anIter->more() )
3280 Ns.push_back( anIter->next() );
3281 Ns.push_back( Ns[0] );
3283 for(int i=0; i<QF->NbNodes(); i=i+2) {
3284 if ( !surface.IsNull() ) {
3285 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3286 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3287 gp_XY uv = ( uv1 + uv2 ) / 2.;
3288 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3289 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3292 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3293 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3294 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3296 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3297 fabs( Ns[i+1]->Y() - y ) > disttol ||
3298 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3299 // we have to move i+1 node
3300 aMesh->MoveNode( Ns[i+1], x, y, z );
3307 } // loop on face ids
3311 //=======================================================================
3312 //function : isReverse
3313 //purpose : Return true if normal of prevNodes is not co-directied with
3314 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3315 // iNotSame is where prevNodes and nextNodes are different
3316 //=======================================================================
3318 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3319 vector<const SMDS_MeshNode*> nextNodes,
3323 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3324 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3326 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3327 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3328 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3329 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3331 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3332 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3333 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3334 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3336 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3338 return (vA ^ vB) * vN < 0.0;
3341 //=======================================================================
3343 * \brief Create elements by sweeping an element
3344 * \param elem - element to sweep
3345 * \param newNodesItVec - nodes generated from each node of the element
3346 * \param newElems - generated elements
3347 * \param nbSteps - number of sweeping steps
3348 * \param srcElements - to append elem for each generated element
3350 //=======================================================================
3352 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3353 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3354 list<const SMDS_MeshElement*>& newElems,
3356 SMESH_SequenceOfElemPtr& srcElements)
3358 SMESHDS_Mesh* aMesh = GetMeshDS();
3360 // Loop on elem nodes:
3361 // find new nodes and detect same nodes indices
3362 int nbNodes = elem->NbNodes();
3363 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3364 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3365 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3366 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3368 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3369 vector<int> sames(nbNodes);
3370 vector<bool> issimple(nbNodes);
3372 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3373 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3374 const SMDS_MeshNode* node = nnIt->first;
3375 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3376 if ( listNewNodes.empty() ) {
3380 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3382 itNN[ iNode ] = listNewNodes.begin();
3383 prevNod[ iNode ] = node;
3384 nextNod[ iNode ] = listNewNodes.front();
3385 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3386 if ( prevNod[ iNode ] != nextNod [ iNode ])
3387 iNotSameNode = iNode;
3391 sames[nbSame++] = iNode;
3396 //cout<<" nbSame = "<<nbSame<<endl;
3397 if ( nbSame == nbNodes || nbSame > 2) {
3398 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3399 //INFOS( " Too many same nodes of element " << elem->GetID() );
3403 // if( elem->IsQuadratic() && nbSame>0 ) {
3404 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3408 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3409 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3411 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3412 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3413 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3417 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3418 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3419 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3420 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3422 // check element orientation
3424 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3425 //MESSAGE("Reversed elem " << elem );
3429 std::swap( iBeforeSame, iAfterSame );
3432 // make new elements
3433 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3435 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3436 if(issimple[iNode]) {
3437 nextNod[ iNode ] = *itNN[ iNode ];
3441 if( elem->GetType()==SMDSAbs_Node ) {
3442 // we have to use two nodes
3443 midlNod[ iNode ] = *itNN[ iNode ];
3445 nextNod[ iNode ] = *itNN[ iNode ];
3448 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3449 // we have to use each second node
3451 nextNod[ iNode ] = *itNN[ iNode ];
3455 // we have to use two nodes
3456 midlNod[ iNode ] = *itNN[ iNode ];
3458 nextNod[ iNode ] = *itNN[ iNode ];
3463 SMDS_MeshElement* aNewElem = 0;
3464 if(!elem->IsPoly()) {
3465 switch ( nbNodes ) {
3469 if ( nbSame == 0 ) {
3471 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3473 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3479 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3480 nextNod[ 1 ], nextNod[ 0 ] );
3482 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3483 nextNod[ iNotSameNode ] );
3487 case 3: { // TRIANGLE or quadratic edge
3488 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3490 if ( nbSame == 0 ) // --- pentahedron
3491 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3492 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3494 else if ( nbSame == 1 ) // --- pyramid
3495 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3496 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3497 nextNod[ iSameNode ]);
3499 else // 2 same nodes: --- tetrahedron
3500 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3501 nextNod[ iNotSameNode ]);
3503 else { // quadratic edge
3504 if(nbSame==0) { // quadratic quadrangle
3505 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3506 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3508 else if(nbSame==1) { // quadratic triangle
3510 return; // medium node on axis
3512 else if(sames[0]==0) {
3513 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3514 nextNod[2], midlNod[1], prevNod[2]);
3516 else { // sames[0]==1
3517 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3518 midlNod[0], nextNod[2], prevNod[2]);
3527 case 4: { // QUADRANGLE
3529 if ( nbSame == 0 ) // --- hexahedron
3530 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3531 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3533 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3534 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3535 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3536 nextNod[ iSameNode ]);
3537 newElems.push_back( aNewElem );
3538 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3539 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3540 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3542 else if ( nbSame == 2 ) { // pentahedron
3543 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3544 // iBeforeSame is same too
3545 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3546 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3547 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3549 // iAfterSame is same too
3550 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3551 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3552 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3556 case 6: { // quadratic triangle
3557 // create pentahedron with 15 nodes
3559 if(i0>0) { // reversed case
3560 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3561 nextNod[0], nextNod[2], nextNod[1],
3562 prevNod[5], prevNod[4], prevNod[3],
3563 nextNod[5], nextNod[4], nextNod[3],
3564 midlNod[0], midlNod[2], midlNod[1]);
3566 else { // not reversed case
3567 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3568 nextNod[0], nextNod[1], nextNod[2],
3569 prevNod[3], prevNod[4], prevNod[5],
3570 nextNod[3], nextNod[4], nextNod[5],
3571 midlNod[0], midlNod[1], midlNod[2]);
3574 else if(nbSame==1) {
3575 // 2d order pyramid of 13 nodes
3576 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3577 // int n12,int n23,int n34,int n41,
3578 // int n15,int n25,int n35,int n45, int ID);
3580 int n1,n4,n41,n15,n45;
3581 if(i0>0) { // reversed case
3582 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3583 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3589 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3590 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3595 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3596 nextNod[n4], prevNod[n4], prevNod[n5],
3597 midlNod[n1], nextNod[n41],
3598 midlNod[n4], prevNod[n41],
3599 prevNod[n15], nextNod[n15],
3600 nextNod[n45], prevNod[n45]);
3602 else if(nbSame==2) {
3603 // 2d order tetrahedron of 10 nodes
3604 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3605 // int n12,int n23,int n31,
3606 // int n14,int n24,int n34, int ID);
3607 int n1 = iNotSameNode;
3608 int n2,n3,n12,n23,n31;
3609 if(i0>0) { // reversed case
3610 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3611 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3617 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3618 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3623 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3624 prevNod[n12], prevNod[n23], prevNod[n31],
3625 midlNod[n1], nextNod[n12], nextNod[n31]);
3629 case 8: { // quadratic quadrangle
3631 // create hexahedron with 20 nodes
3632 if(i0>0) { // reversed case
3633 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3634 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3635 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3636 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3637 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3639 else { // not reversed case
3640 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3641 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3642 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3643 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3644 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3647 else if(nbSame==1) {
3648 // --- pyramid + pentahedron - can not be created since it is needed
3649 // additional middle node ot the center of face
3650 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3653 else if(nbSame==2) {
3654 // 2d order Pentahedron with 15 nodes
3655 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3656 // int n12,int n23,int n31,int n45,int n56,int n64,
3657 // int n14,int n25,int n36, int ID);
3659 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3660 // iBeforeSame is same too
3667 // iAfterSame is same too
3673 int n12,n45,n14,n25;
3674 if(i0>0) { //reversed case
3686 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3687 prevNod[n4], prevNod[n5], nextNod[n5],
3688 prevNod[n12], midlNod[n2], nextNod[n12],
3689 prevNod[n45], midlNod[n5], nextNod[n45],
3690 prevNod[n14], prevNod[n25], nextNod[n25]);
3695 // realized for extrusion only
3696 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3697 //vector<int> quantities (nbNodes + 2);
3699 //quantities[0] = nbNodes; // bottom of prism
3700 //for (int inode = 0; inode < nbNodes; inode++) {
3701 // polyedre_nodes[inode] = prevNod[inode];
3704 //quantities[1] = nbNodes; // top of prism
3705 //for (int inode = 0; inode < nbNodes; inode++) {
3706 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3709 //for (int iface = 0; iface < nbNodes; iface++) {
3710 // quantities[iface + 2] = 4;
3711 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3712 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3713 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3714 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3715 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3717 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3724 // realized for extrusion only
3725 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3726 vector<int> quantities (nbNodes + 2);
3728 quantities[0] = nbNodes; // bottom of prism
3729 for (int inode = 0; inode < nbNodes; inode++) {
3730 polyedre_nodes[inode] = prevNod[inode];
3733 quantities[1] = nbNodes; // top of prism
3734 for (int inode = 0; inode < nbNodes; inode++) {
3735 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3738 for (int iface = 0; iface < nbNodes; iface++) {
3739 quantities[iface + 2] = 4;
3740 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3741 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3742 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3743 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3744 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3746 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3750 newElems.push_back( aNewElem );
3751 myLastCreatedElems.Append(aNewElem);
3752 srcElements.Append( elem );
3755 // set new prev nodes
3756 for ( iNode = 0; iNode < nbNodes; iNode++ )
3757 prevNod[ iNode ] = nextNod[ iNode ];
3762 //=======================================================================
3764 * \brief Create 1D and 2D elements around swept elements
3765 * \param mapNewNodes - source nodes and ones generated from them
3766 * \param newElemsMap - source elements and ones generated from them
3767 * \param elemNewNodesMap - nodes generated from each node of each element
3768 * \param elemSet - all swept elements
3769 * \param nbSteps - number of sweeping steps
3770 * \param srcElements - to append elem for each generated element
3772 //=======================================================================
3774 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3775 TElemOfElemListMap & newElemsMap,
3776 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3777 TIDSortedElemSet& elemSet,
3779 SMESH_SequenceOfElemPtr& srcElements)
3781 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3782 SMESHDS_Mesh* aMesh = GetMeshDS();
3784 // Find nodes belonging to only one initial element - sweep them to get edges.
3786 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3787 for ( ; nList != mapNewNodes.end(); nList++ ) {
3788 const SMDS_MeshNode* node =
3789 static_cast<const SMDS_MeshNode*>( nList->first );
3790 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3791 int nbInitElems = 0;
3792 const SMDS_MeshElement* el = 0;
3793 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3794 while ( eIt->more() && nbInitElems < 2 ) {
3796 SMDSAbs_ElementType type = el->GetType();
3797 if ( type == SMDSAbs_Volume || type < highType ) continue;
3798 if ( type > highType ) {
3802 if ( elemSet.find(el) != elemSet.end() )
3805 if ( nbInitElems < 2 ) {
3806 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3807 if(!NotCreateEdge) {
3808 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3809 list<const SMDS_MeshElement*> newEdges;
3810 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3815 // Make a ceiling for each element ie an equal element of last new nodes.
3816 // Find free links of faces - make edges and sweep them into faces.
3818 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3819 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3820 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3821 const SMDS_MeshElement* elem = itElem->first;
3822 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3824 if ( elem->GetType() == SMDSAbs_Edge ) {
3825 // create a ceiling edge
3826 if (!elem->IsQuadratic()) {
3827 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3828 vecNewNodes[ 1 ]->second.back())) {
3829 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3830 vecNewNodes[ 1 ]->second.back()));
3831 srcElements.Append( myLastCreatedElems.Last() );
3835 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3836 vecNewNodes[ 1 ]->second.back(),
3837 vecNewNodes[ 2 ]->second.back())) {
3838 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3839 vecNewNodes[ 1 ]->second.back(),
3840 vecNewNodes[ 2 ]->second.back()));
3841 srcElements.Append( myLastCreatedElems.Last() );
3845 if ( elem->GetType() != SMDSAbs_Face )
3848 if(itElem->second.size()==0) continue;
3850 bool hasFreeLinks = false;
3852 TIDSortedElemSet avoidSet;
3853 avoidSet.insert( elem );
3855 set<const SMDS_MeshNode*> aFaceLastNodes;
3856 int iNode, nbNodes = vecNewNodes.size();
3857 if(!elem->IsQuadratic()) {
3858 // loop on the face nodes
3859 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3860 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3861 // look for free links of the face
3862 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3863 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3864 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3865 // check if a link is free
3866 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3867 hasFreeLinks = true;
3868 // make an edge and a ceiling for a new edge
3869 if ( !aMesh->FindEdge( n1, n2 )) {
3870 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3871 srcElements.Append( myLastCreatedElems.Last() );
3873 n1 = vecNewNodes[ iNode ]->second.back();
3874 n2 = vecNewNodes[ iNext ]->second.back();
3875 if ( !aMesh->FindEdge( n1, n2 )) {
3876 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3877 srcElements.Append( myLastCreatedElems.Last() );
3882 else { // elem is quadratic face
3883 int nbn = nbNodes/2;
3884 for ( iNode = 0; iNode < nbn; iNode++ ) {
3885 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3886 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3887 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3888 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3889 // check if a link is free
3890 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3891 hasFreeLinks = true;
3892 // make an edge and a ceiling for a new edge
3894 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3895 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3896 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3897 srcElements.Append( myLastCreatedElems.Last() );
3899 n1 = vecNewNodes[ iNode ]->second.back();
3900 n2 = vecNewNodes[ iNext ]->second.back();
3901 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3902 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3903 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3904 srcElements.Append( myLastCreatedElems.Last() );
3908 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3909 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3913 // sweep free links into faces
3915 if ( hasFreeLinks ) {
3916 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3917 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3919 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3920 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3921 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3922 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3924 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3925 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3927 while ( iVol++ < volNb ) v++;
3928 // find indices of free faces of a volume and their source edges
3929 list< int > freeInd;
3930 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3931 SMDS_VolumeTool vTool( *v );
3932 int iF, nbF = vTool.NbFaces();
3933 for ( iF = 0; iF < nbF; iF ++ ) {
3934 if (vTool.IsFreeFace( iF ) &&
3935 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3936 initNodeSet != faceNodeSet) // except an initial face
3938 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3940 freeInd.push_back( iF );
3941 // find source edge of a free face iF
3942 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3943 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3944 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3945 initNodeSet.begin(), initNodeSet.end(),
3946 commonNodes.begin());
3947 if ( (*v)->IsQuadratic() )
3948 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3950 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3952 if ( !srcEdges.back() )
3954 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3955 << iF << " of volume #" << vTool.ID() << endl;
3960 if ( freeInd.empty() )
3963 // create faces for all steps;
3964 // if such a face has been already created by sweep of edge,
3965 // assure that its orientation is OK
3966 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3968 vTool.SetExternalNormal();
3969 list< int >::iterator ind = freeInd.begin();
3970 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3971 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3973 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3974 int nbn = vTool.NbFaceNodes( *ind );
3976 case 3: { ///// triangle
3977 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3979 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3980 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3981 aMesh->ChangeElementNodes( f, nodes, nbn );
3984 case 4: { ///// quadrangle
3985 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3987 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3988 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3989 aMesh->ChangeElementNodes( f, nodes, nbn );
3993 if( (*v)->IsQuadratic() ) {
3994 if(nbn==6) { /////// quadratic triangle
3995 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3996 nodes[1], nodes[3], nodes[5] );
3998 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3999 nodes[1], nodes[3], nodes[5]));
4001 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4002 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4003 tmpnodes[0] = nodes[0];
4004 tmpnodes[1] = nodes[2];
4005 tmpnodes[2] = nodes[4];
4006 tmpnodes[3] = nodes[1];
4007 tmpnodes[4] = nodes[3];
4008 tmpnodes[5] = nodes[5];
4009 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4012 else { /////// quadratic quadrangle
4013 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4014 nodes[1], nodes[3], nodes[5], nodes[7] );
4016 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4017 nodes[1], nodes[3], nodes[5], nodes[7]));
4019 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4020 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4021 tmpnodes[0] = nodes[0];
4022 tmpnodes[1] = nodes[2];
4023 tmpnodes[2] = nodes[4];
4024 tmpnodes[3] = nodes[6];
4025 tmpnodes[4] = nodes[1];
4026 tmpnodes[5] = nodes[3];
4027 tmpnodes[6] = nodes[5];
4028 tmpnodes[7] = nodes[7];
4029 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
4033 else { //////// polygon
4034 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4035 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4037 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4038 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4039 aMesh->ChangeElementNodes( f, nodes, nbn );
4042 while ( srcElements.Length() < myLastCreatedElems.Length() )
4043 srcElements.Append( *srcEdge );
4045 } // loop on free faces
4047 // go to the next volume
4049 while ( iVol++ < nbVolumesByStep ) v++;
4052 } // sweep free links into faces
4054 // Make a ceiling face with a normal external to a volume
4056 SMDS_VolumeTool lastVol( itElem->second.back() );
4058 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4060 lastVol.SetExternalNormal();
4061 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4062 int nbn = lastVol.NbFaceNodes( iF );
4065 if (!hasFreeLinks ||
4066 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4067 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4070 if (!hasFreeLinks ||
4071 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4072 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4075 if(itElem->second.back()->IsQuadratic()) {
4077 if (!hasFreeLinks ||
4078 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4079 nodes[1], nodes[3], nodes[5]) ) {
4080 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4081 nodes[1], nodes[3], nodes[5]));
4085 if (!hasFreeLinks ||
4086 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4087 nodes[1], nodes[3], nodes[5], nodes[7]) )
4088 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4089 nodes[1], nodes[3], nodes[5], nodes[7]));
4093 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4094 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4095 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4099 while ( srcElements.Length() < myLastCreatedElems.Length() )
4100 srcElements.Append( myLastCreatedElems.Last() );
4102 } // loop on swept elements
4105 //=======================================================================
4106 //function : RotationSweep
4108 //=======================================================================
4110 SMESH_MeshEditor::PGroupIDs
4111 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4112 const gp_Ax1& theAxis,
4113 const double theAngle,
4114 const int theNbSteps,
4115 const double theTol,
4116 const bool theMakeGroups,
4117 const bool theMakeWalls)
4119 myLastCreatedElems.Clear();
4120 myLastCreatedNodes.Clear();
4122 // source elements for each generated one
4123 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4125 MESSAGE( "RotationSweep()");
4127 aTrsf.SetRotation( theAxis, theAngle );
4129 aTrsf2.SetRotation( theAxis, theAngle/2. );
4131 gp_Lin aLine( theAxis );
4132 double aSqTol = theTol * theTol;
4134 SMESHDS_Mesh* aMesh = GetMeshDS();
4136 TNodeOfNodeListMap mapNewNodes;
4137 TElemOfVecOfNnlmiMap mapElemNewNodes;
4138 TElemOfElemListMap newElemsMap;
4141 TIDSortedElemSet::iterator itElem;
4142 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4143 const SMDS_MeshElement* elem = *itElem;
4144 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4146 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4147 newNodesItVec.reserve( elem->NbNodes() );
4149 // loop on elem nodes
4150 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4151 while ( itN->more() ) {
4152 // check if a node has been already sweeped
4153 const SMDS_MeshNode* node = cast2Node( itN->next() );
4155 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4157 aXYZ.Coord( coord[0], coord[1], coord[2] );
4158 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4160 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4161 if ( nIt == mapNewNodes.end() ) {
4162 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4163 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4166 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4168 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4169 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4170 const SMDS_MeshNode * newNode = node;
4171 for ( int i = 0; i < theNbSteps; i++ ) {
4173 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4175 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4176 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4177 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4178 myLastCreatedNodes.Append(newNode);
4179 srcNodes.Append( node );
4180 listNewNodes.push_back( newNode );
4181 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4182 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4185 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4187 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4188 myLastCreatedNodes.Append(newNode);
4189 srcNodes.Append( node );
4190 listNewNodes.push_back( newNode );
4193 listNewNodes.push_back( newNode );
4194 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4195 listNewNodes.push_back( newNode );
4202 // if current elem is quadratic and current node is not medium
4203 // we have to check - may be it is needed to insert additional nodes
4204 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4205 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4206 if(listNewNodes.size()==theNbSteps) {
4207 listNewNodes.clear();
4209 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4211 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4212 const SMDS_MeshNode * newNode = node;
4214 for(int i = 0; i<theNbSteps; i++) {
4215 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4216 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4217 cout<<" 3 AddNode: "<<newNode;
4218 myLastCreatedNodes.Append(newNode);
4219 listNewNodes.push_back( newNode );
4220 srcNodes.Append( node );
4221 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4222 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4223 cout<<" 4 AddNode: "<<newNode;
4224 myLastCreatedNodes.Append(newNode);
4225 srcNodes.Append( node );
4226 listNewNodes.push_back( newNode );
4230 listNewNodes.push_back( newNode );
4236 newNodesItVec.push_back( nIt );
4238 // make new elements
4239 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4243 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4245 PGroupIDs newGroupIDs;
4246 if ( theMakeGroups )
4247 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4253 //=======================================================================
4254 //function : CreateNode
4256 //=======================================================================
4257 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4260 const double tolnode,
4261 SMESH_SequenceOfNode& aNodes)
4263 myLastCreatedElems.Clear();
4264 myLastCreatedNodes.Clear();
4267 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4269 // try to search in sequence of existing nodes
4270 // if aNodes.Length()>0 we 'nave to use given sequence
4271 // else - use all nodes of mesh
4272 if(aNodes.Length()>0) {
4274 for(i=1; i<=aNodes.Length(); i++) {
4275 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4276 if(P1.Distance(P2)<tolnode)
4277 return aNodes.Value(i);
4281 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4282 while(itn->more()) {
4283 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4284 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4285 if(P1.Distance(P2)<tolnode)
4290 // create new node and return it
4291 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4292 myLastCreatedNodes.Append(NewNode);
4297 //=======================================================================
4298 //function : ExtrusionSweep
4300 //=======================================================================
4302 SMESH_MeshEditor::PGroupIDs
4303 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4304 const gp_Vec& theStep,
4305 const int theNbSteps,
4306 TElemOfElemListMap& newElemsMap,
4307 const bool theMakeGroups,
4309 const double theTolerance)
4311 ExtrusParam aParams;
4312 aParams.myDir = gp_Dir(theStep);
4313 aParams.myNodes.Clear();
4314 aParams.mySteps = new TColStd_HSequenceOfReal;
4316 for(i=1; i<=theNbSteps; i++)
4317 aParams.mySteps->Append(theStep.Magnitude());
4320 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4324 //=======================================================================
4325 //function : ExtrusionSweep
4327 //=======================================================================
4329 SMESH_MeshEditor::PGroupIDs
4330 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4331 ExtrusParam& theParams,
4332 TElemOfElemListMap& newElemsMap,
4333 const bool theMakeGroups,
4335 const double theTolerance)
4337 myLastCreatedElems.Clear();
4338 myLastCreatedNodes.Clear();
4340 // source elements for each generated one
4341 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4343 SMESHDS_Mesh* aMesh = GetMeshDS();
4345 int nbsteps = theParams.mySteps->Length();
4347 TNodeOfNodeListMap mapNewNodes;
4348 //TNodeOfNodeVecMap mapNewNodes;
4349 TElemOfVecOfNnlmiMap mapElemNewNodes;
4350 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4353 TIDSortedElemSet::iterator itElem;
4354 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4355 // check element type
4356 const SMDS_MeshElement* elem = *itElem;
4357 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4360 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4361 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4362 newNodesItVec.reserve( elem->NbNodes() );
4364 // loop on elem nodes
4365 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4366 while ( itN->more() )
4368 // check if a node has been already sweeped
4369 const SMDS_MeshNode* node = cast2Node( itN->next() );
4370 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4371 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4372 if ( nIt == mapNewNodes.end() ) {
4373 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4374 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4375 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4376 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4377 //vecNewNodes.reserve(nbsteps);
4380 double coord[] = { node->X(), node->Y(), node->Z() };
4381 //int nbsteps = theParams.mySteps->Length();
4382 for ( int i = 0; i < nbsteps; i++ ) {
4383 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4384 // create additional node
4385 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4386 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4387 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4388 if( theFlags & EXTRUSION_FLAG_SEW ) {
4389 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4390 theTolerance, theParams.myNodes);
4391 listNewNodes.push_back( newNode );
4394 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4395 myLastCreatedNodes.Append(newNode);
4396 srcNodes.Append( node );
4397 listNewNodes.push_back( newNode );
4400 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4401 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4402 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4403 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4404 if( theFlags & EXTRUSION_FLAG_SEW ) {
4405 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4406 theTolerance, theParams.myNodes);
4407 listNewNodes.push_back( newNode );
4408 //vecNewNodes[i]=newNode;
4411 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4412 myLastCreatedNodes.Append(newNode);
4413 srcNodes.Append( node );
4414 listNewNodes.push_back( newNode );
4415 //vecNewNodes[i]=newNode;
4420 // if current elem is quadratic and current node is not medium
4421 // we have to check - may be it is needed to insert additional nodes
4422 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4423 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4424 if(listNewNodes.size()==nbsteps) {
4425 listNewNodes.clear();
4426 double coord[] = { node->X(), node->Y(), node->Z() };
4427 for ( int i = 0; i < nbsteps; i++ ) {
4428 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4429 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4430 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4431 if( theFlags & EXTRUSION_FLAG_SEW ) {
4432 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4433 theTolerance, theParams.myNodes);
4434 listNewNodes.push_back( newNode );
4437 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4438 myLastCreatedNodes.Append(newNode);
4439 srcNodes.Append( node );
4440 listNewNodes.push_back( newNode );
4442 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4443 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4444 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4445 if( theFlags & EXTRUSION_FLAG_SEW ) {
4446 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4447 theTolerance, theParams.myNodes);
4448 listNewNodes.push_back( newNode );
4451 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4452 myLastCreatedNodes.Append(newNode);
4453 srcNodes.Append( node );
4454 listNewNodes.push_back( newNode );
4460 newNodesItVec.push_back( nIt );
4462 // make new elements
4463 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4466 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4467 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4469 PGroupIDs newGroupIDs;
4470 if ( theMakeGroups )
4471 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4477 //=======================================================================
4478 //class : SMESH_MeshEditor_PathPoint
4479 //purpose : auxiliary class
4480 //=======================================================================
4481 class SMESH_MeshEditor_PathPoint {
4483 SMESH_MeshEditor_PathPoint() {
4484 myPnt.SetCoord(99., 99., 99.);
4485 myTgt.SetCoord(1.,0.,0.);
4489 void SetPnt(const gp_Pnt& aP3D){
4492 void SetTangent(const gp_Dir& aTgt){
4495 void SetAngle(const double& aBeta){
4498 void SetParameter(const double& aPrm){
4501 const gp_Pnt& Pnt()const{
4504 const gp_Dir& Tangent()const{
4507 double Angle()const{
4510 double Parameter()const{
4522 //=======================================================================
4523 //function : ExtrusionAlongTrack
4525 //=======================================================================
4526 SMESH_MeshEditor::Extrusion_Error
4527 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4528 SMESH_subMesh* theTrack,
4529 const SMDS_MeshNode* theN1,
4530 const bool theHasAngles,
4531 list<double>& theAngles,
4532 const bool theLinearVariation,
4533 const bool theHasRefPoint,
4534 const gp_Pnt& theRefPoint,
4535 const bool theMakeGroups)
4537 myLastCreatedElems.Clear();
4538 myLastCreatedNodes.Clear();
4541 std::list<double> aPrms;
4542 TIDSortedElemSet::iterator itElem;
4545 TopoDS_Edge aTrackEdge;
4546 TopoDS_Vertex aV1, aV2;
4548 SMDS_ElemIteratorPtr aItE;
4549 SMDS_NodeIteratorPtr aItN;
4550 SMDSAbs_ElementType aTypeE;
4552 TNodeOfNodeListMap mapNewNodes;
4555 aNbE = theElements.size();
4558 return EXTR_NO_ELEMENTS;
4560 // 1.1 Track Pattern
4563 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4565 aItE = pSubMeshDS->GetElements();
4566 while ( aItE->more() ) {
4567 const SMDS_MeshElement* pE = aItE->next();
4568 aTypeE = pE->GetType();
4569 // Pattern must contain links only
4570 if ( aTypeE != SMDSAbs_Edge )
4571 return EXTR_PATH_NOT_EDGE;
4574 list<SMESH_MeshEditor_PathPoint> fullList;
4576 const TopoDS_Shape& aS = theTrack->GetSubShape();
4577 // Sub shape for the Pattern must be an Edge or Wire
4578 if( aS.ShapeType() == TopAbs_EDGE ) {
4579 aTrackEdge = TopoDS::Edge( aS );
4580 // the Edge must not be degenerated
4581 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4582 return EXTR_BAD_PATH_SHAPE;
4583 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4584 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4585 const SMDS_MeshNode* aN1 = aItN->next();
4586 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4587 const SMDS_MeshNode* aN2 = aItN->next();
4588 // starting node must be aN1 or aN2
4589 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4590 return EXTR_BAD_STARTING_NODE;
4591 aItN = pSubMeshDS->GetNodes();
4592 while ( aItN->more() ) {
4593 const SMDS_MeshNode* pNode = aItN->next();
4594 const SMDS_EdgePosition* pEPos =
4595 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4596 double aT = pEPos->GetUParameter();
4597 aPrms.push_back( aT );
4599 //Extrusion_Error err =
4600 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4602 else if( aS.ShapeType() == TopAbs_WIRE ) {
4603 list< SMESH_subMesh* > LSM;
4604 TopTools_SequenceOfShape Edges;
4605 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4606 while(itSM->more()) {
4607 SMESH_subMesh* SM = itSM->next();
4609 const TopoDS_Shape& aS = SM->GetSubShape();
4612 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4613 int startNid = theN1->GetID();
4614 TColStd_MapOfInteger UsedNums;
4615 int NbEdges = Edges.Length();
4617 for(; i<=NbEdges; i++) {
4619 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4620 for(; itLSM!=LSM.end(); itLSM++) {
4622 if(UsedNums.Contains(k)) continue;
4623 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4624 SMESH_subMesh* locTrack = *itLSM;
4625 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4626 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4627 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4628 const SMDS_MeshNode* aN1 = aItN->next();
4629 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4630 const SMDS_MeshNode* aN2 = aItN->next();
4631 // starting node must be aN1 or aN2
4632 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4633 // 2. Collect parameters on the track edge
4635 aItN = locMeshDS->GetNodes();
4636 while ( aItN->more() ) {
4637 const SMDS_MeshNode* pNode = aItN->next();
4638 const SMDS_EdgePosition* pEPos =
4639 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4640 double aT = pEPos->GetUParameter();
4641 aPrms.push_back( aT );
4643 list<SMESH_MeshEditor_PathPoint> LPP;
4644 //Extrusion_Error err =
4645 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4646 LLPPs.push_back(LPP);
4648 // update startN for search following egde
4649 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4650 else startNid = aN1->GetID();
4654 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4655 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4656 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4657 for(; itPP!=firstList.end(); itPP++) {
4658 fullList.push_back( *itPP );
4660 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4661 fullList.pop_back();
4663 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4664 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4665 itPP = currList.begin();
4666 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4667 gp_Dir D1 = PP1.Tangent();
4668 gp_Dir D2 = PP2.Tangent();
4669 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4670 (D1.Z()+D2.Z())/2 ) );
4671 PP1.SetTangent(Dnew);
4672 fullList.push_back(PP1);
4674 for(; itPP!=firstList.end(); itPP++) {
4675 fullList.push_back( *itPP );
4677 PP1 = fullList.back();
4678 fullList.pop_back();
4680 // if wire not closed
4681 fullList.push_back(PP1);
4685 return EXTR_BAD_PATH_SHAPE;
4688 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4689 theHasRefPoint, theRefPoint, theMakeGroups);
4693 //=======================================================================
4694 //function : ExtrusionAlongTrack
4696 //=======================================================================
4697 SMESH_MeshEditor::Extrusion_Error
4698 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4699 SMESH_Mesh* theTrack,
4700 const SMDS_MeshNode* theN1,
4701 const bool theHasAngles,
4702 list<double>& theAngles,
4703 const bool theLinearVariation,
4704 const bool theHasRefPoint,
4705 const gp_Pnt& theRefPoint,
4706 const bool theMakeGroups)
4708 myLastCreatedElems.Clear();
4709 myLastCreatedNodes.Clear();
4712 std::list<double> aPrms;
4713 TIDSortedElemSet::iterator itElem;
4716 TopoDS_Edge aTrackEdge;
4717 TopoDS_Vertex aV1, aV2;
4719 SMDS_ElemIteratorPtr aItE;
4720 SMDS_NodeIteratorPtr aItN;
4721 SMDSAbs_ElementType aTypeE;
4723 TNodeOfNodeListMap mapNewNodes;
4726 aNbE = theElements.size();
4729 return EXTR_NO_ELEMENTS;
4731 // 1.1 Track Pattern
4734 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4736 aItE = pMeshDS->elementsIterator();
4737 while ( aItE->more() ) {
4738 const SMDS_MeshElement* pE = aItE->next();
4739 aTypeE = pE->GetType();
4740 // Pattern must contain links only
4741 if ( aTypeE != SMDSAbs_Edge )
4742 return EXTR_PATH_NOT_EDGE;
4745 list<SMESH_MeshEditor_PathPoint> fullList;
4747 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4748 // Sub shape for the Pattern must be an Edge or Wire
4749 if( aS.ShapeType() == TopAbs_EDGE ) {
4750 aTrackEdge = TopoDS::Edge( aS );
4751 // the Edge must not be degenerated
4752 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4753 return EXTR_BAD_PATH_SHAPE;
4754 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4755 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4756 const SMDS_MeshNode* aN1 = aItN->next();
4757 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4758 const SMDS_MeshNode* aN2 = aItN->next();
4759 // starting node must be aN1 or aN2
4760 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4761 return EXTR_BAD_STARTING_NODE;
4762 aItN = pMeshDS->nodesIterator();
4763 while ( aItN->more() ) {
4764 const SMDS_MeshNode* pNode = aItN->next();
4765 if( pNode==aN1 || pNode==aN2 ) continue;
4766 const SMDS_EdgePosition* pEPos =
4767 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4768 double aT = pEPos->GetUParameter();
4769 aPrms.push_back( aT );
4771 //Extrusion_Error err =
4772 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4774 else if( aS.ShapeType() == TopAbs_WIRE ) {
4775 list< SMESH_subMesh* > LSM;
4776 TopTools_SequenceOfShape Edges;
4777 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4778 for(; eExp.More(); eExp.Next()) {
4779 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4780 if( BRep_Tool::Degenerated(E) ) continue;
4781 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4787 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4788 int startNid = theN1->GetID();
4789 TColStd_MapOfInteger UsedNums;
4790 int NbEdges = Edges.Length();
4792 for(; i<=NbEdges; i++) {
4794 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4795 for(; itLSM!=LSM.end(); itLSM++) {
4797 if(UsedNums.Contains(k)) continue;
4798 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4799 SMESH_subMesh* locTrack = *itLSM;
4800 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4801 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4802 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4803 const SMDS_MeshNode* aN1 = aItN->next();
4804 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4805 const SMDS_MeshNode* aN2 = aItN->next();
4806 // starting node must be aN1 or aN2
4807 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4808 // 2. Collect parameters on the track edge
4810 aItN = locMeshDS->GetNodes();
4811 while ( aItN->more() ) {
4812 const SMDS_MeshNode* pNode = aItN->next();
4813 const SMDS_EdgePosition* pEPos =
4814 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4815 double aT = pEPos->GetUParameter();
4816 aPrms.push_back( aT );
4818 list<SMESH_MeshEditor_PathPoint> LPP;
4819 //Extrusion_Error err =
4820 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4821 LLPPs.push_back(LPP);
4823 // update startN for search following egde
4824 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4825 else startNid = aN1->GetID();
4829 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4830 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4831 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4832 for(; itPP!=firstList.end(); itPP++) {
4833 fullList.push_back( *itPP );
4835 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4836 fullList.pop_back();
4838 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4839 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4840 itPP = currList.begin();
4841 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4842 gp_Pnt P1 = PP1.Pnt();
4843 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4844 gp_Pnt P2 = PP2.Pnt();
4845 gp_Dir D1 = PP1.Tangent();
4846 gp_Dir D2 = PP2.Tangent();
4847 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4848 (D1.Z()+D2.Z())/2 ) );
4849 PP1.SetTangent(Dnew);
4850 fullList.push_back(PP1);
4852 for(; itPP!=currList.end(); itPP++) {
4853 fullList.push_back( *itPP );
4855 PP1 = fullList.back();
4856 fullList.pop_back();
4858 // if wire not closed
4859 fullList.push_back(PP1);
4863 return EXTR_BAD_PATH_SHAPE;
4866 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4867 theHasRefPoint, theRefPoint, theMakeGroups);
4871 //=======================================================================
4872 //function : MakeEdgePathPoints
4873 //purpose : auxilary for ExtrusionAlongTrack
4874 //=======================================================================
4875 SMESH_MeshEditor::Extrusion_Error
4876 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4877 const TopoDS_Edge& aTrackEdge,
4879 list<SMESH_MeshEditor_PathPoint>& LPP)
4881 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4883 aTolVec2=aTolVec*aTolVec;
4885 TopoDS_Vertex aV1, aV2;
4886 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4887 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4888 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4889 // 2. Collect parameters on the track edge
4890 aPrms.push_front( aT1 );
4891 aPrms.push_back( aT2 );
4894 if( FirstIsStart ) {
4905 SMESH_MeshEditor_PathPoint aPP;
4906 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4907 std::list<double>::iterator aItD = aPrms.begin();
4908 for(; aItD != aPrms.end(); ++aItD) {
4912 aC3D->D1( aT, aP3D, aVec );
4913 aL2 = aVec.SquareMagnitude();
4914 if ( aL2 < aTolVec2 )
4915 return EXTR_CANT_GET_TANGENT;
4916 gp_Dir aTgt( aVec );
4918 aPP.SetTangent( aTgt );
4919 aPP.SetParameter( aT );
4926 //=======================================================================
4927 //function : MakeExtrElements
4928 //purpose : auxilary for ExtrusionAlongTrack
4929 //=======================================================================
4930 SMESH_MeshEditor::Extrusion_Error
4931 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4932 list<SMESH_MeshEditor_PathPoint>& fullList,
4933 const bool theHasAngles,
4934 list<double>& theAngles,
4935 const bool theLinearVariation,
4936 const bool theHasRefPoint,
4937 const gp_Pnt& theRefPoint,
4938 const bool theMakeGroups)
4940 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4941 int aNbTP = fullList.size();
4942 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4944 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4945 LinearAngleVariation(aNbTP-1, theAngles);
4947 vector<double> aAngles( aNbTP );
4949 for(; j<aNbTP; ++j) {
4952 if ( theHasAngles ) {
4954 std::list<double>::iterator aItD = theAngles.begin();
4955 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4957 aAngles[j] = anAngle;
4960 // fill vector of path points with angles
4961 //aPPs.resize(fullList.size());
4963 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4964 for(; itPP!=fullList.end(); itPP++) {
4966 SMESH_MeshEditor_PathPoint PP = *itPP;
4967 PP.SetAngle(aAngles[j]);
4971 TNodeOfNodeListMap mapNewNodes;
4972 TElemOfVecOfNnlmiMap mapElemNewNodes;
4973 TElemOfElemListMap newElemsMap;
4974 TIDSortedElemSet::iterator itElem;
4977 SMDSAbs_ElementType aTypeE;
4978 // source elements for each generated one
4979 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4981 // 3. Center of rotation aV0
4982 gp_Pnt aV0 = theRefPoint;
4984 if ( !theHasRefPoint ) {
4986 aGC.SetCoord( 0.,0.,0. );
4988 itElem = theElements.begin();
4989 for ( ; itElem != theElements.end(); itElem++ ) {
4990 const SMDS_MeshElement* elem = *itElem;
4992 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4993 while ( itN->more() ) {
4994 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4999 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5000 list<const SMDS_MeshNode*> aLNx;
5001 mapNewNodes[node] = aLNx;
5003 gp_XYZ aXYZ( aX, aY, aZ );
5011 } // if (!theHasRefPoint) {
5012 mapNewNodes.clear();
5014 // 4. Processing the elements
5015 SMESHDS_Mesh* aMesh = GetMeshDS();
5017 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5018 // check element type
5019 const SMDS_MeshElement* elem = *itElem;
5020 aTypeE = elem->GetType();
5021 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5024 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5025 newNodesItVec.reserve( elem->NbNodes() );
5027 // loop on elem nodes
5029 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5030 while ( itN->more() )
5033 // check if a node has been already processed
5034 const SMDS_MeshNode* node =
5035 static_cast<const SMDS_MeshNode*>( itN->next() );
5036 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5037 if ( nIt == mapNewNodes.end() ) {
5038 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5039 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5042 aX = node->X(); aY = node->Y(); aZ = node->Z();
5044 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5045 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5046 gp_Ax1 anAx1, anAxT1T0;
5047 gp_Dir aDT1x, aDT0x, aDT1T0;
5052 aPN0.SetCoord(aX, aY, aZ);
5054 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5056 aDT0x= aPP0.Tangent();
5057 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5059 for ( j = 1; j < aNbTP; ++j ) {
5060 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5062 aDT1x = aPP1.Tangent();
5063 aAngle1x = aPP1.Angle();
5065 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5067 gp_Vec aV01x( aP0x, aP1x );
5068 aTrsf.SetTranslation( aV01x );
5071 aV1x = aV0x.Transformed( aTrsf );
5072 aPN1 = aPN0.Transformed( aTrsf );
5074 // rotation 1 [ T1,T0 ]
5075 aAngleT1T0=-aDT1x.Angle( aDT0x );
5076 if (fabs(aAngleT1T0) > aTolAng) {
5078 anAxT1T0.SetLocation( aV1x );
5079 anAxT1T0.SetDirection( aDT1T0 );
5080 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5082 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5086 if ( theHasAngles ) {
5087 anAx1.SetLocation( aV1x );
5088 anAx1.SetDirection( aDT1x );
5089 aTrsfRot.SetRotation( anAx1, aAngle1x );
5091 aPN1 = aPN1.Transformed( aTrsfRot );
5095 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5096 // create additional node
5097 double x = ( aPN1.X() + aPN0.X() )/2.;
5098 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5099 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5100 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5101 myLastCreatedNodes.Append(newNode);
5102 srcNodes.Append( node );
5103 listNewNodes.push_back( newNode );
5108 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5109 myLastCreatedNodes.Append(newNode);
5110 srcNodes.Append( node );
5111 listNewNodes.push_back( newNode );
5121 // if current elem is quadratic and current node is not medium
5122 // we have to check - may be it is needed to insert additional nodes
5123 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5124 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5125 if(listNewNodes.size()==aNbTP-1) {
5126 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5127 gp_XYZ P(node->X(), node->Y(), node->Z());
5128 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5130 for(i=0; i<aNbTP-1; i++) {
5131 const SMDS_MeshNode* N = *it;
5132 double x = ( N->X() + P.X() )/2.;
5133 double y = ( N->Y() + P.Y() )/2.;
5134 double z = ( N->Z() + P.Z() )/2.;
5135 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5136 srcNodes.Append( node );
5137 myLastCreatedNodes.Append(newN);
5140 P = gp_XYZ(N->X(),N->Y(),N->Z());
5142 listNewNodes.clear();
5143 for(i=0; i<2*(aNbTP-1); i++) {
5144 listNewNodes.push_back(aNodes[i]);
5150 newNodesItVec.push_back( nIt );
5152 // make new elements
5153 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5154 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5155 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5158 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5160 if ( theMakeGroups )
5161 generateGroups( srcNodes, srcElems, "extruded");
5167 //=======================================================================
5168 //function : LinearAngleVariation
5169 //purpose : auxilary for ExtrusionAlongTrack
5170 //=======================================================================
5171 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5172 list<double>& Angles)
5174 int nbAngles = Angles.size();
5175 if( nbSteps > nbAngles ) {
5176 vector<double> theAngles(nbAngles);
5177 list<double>::iterator it = Angles.begin();
5179 for(; it!=Angles.end(); it++) {
5181 theAngles[i] = (*it);
5184 double rAn2St = double( nbAngles ) / double( nbSteps );
5185 double angPrev = 0, angle;
5186 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5187 double angCur = rAn2St * ( iSt+1 );
5188 double angCurFloor = floor( angCur );
5189 double angPrevFloor = floor( angPrev );
5190 if ( angPrevFloor == angCurFloor )
5191 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5193 int iP = int( angPrevFloor );
5194 double angPrevCeil = ceil(angPrev);
5195 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5197 int iC = int( angCurFloor );
5198 if ( iC < nbAngles )
5199 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5201 iP = int( angPrevCeil );
5203 angle += theAngles[ iC ];
5205 res.push_back(angle);
5210 for(; it!=res.end(); it++)
5211 Angles.push_back( *it );
5216 //================================================================================
5218 * \brief Move or copy theElements applying theTrsf to their nodes
5219 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5220 * \param theTrsf - transformation to apply
5221 * \param theCopy - if true, create translated copies of theElems
5222 * \param theMakeGroups - if true and theCopy, create translated groups
5223 * \param theTargetMesh - mesh to copy translated elements into
5224 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5226 //================================================================================
5228 SMESH_MeshEditor::PGroupIDs
5229 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5230 const gp_Trsf& theTrsf,
5232 const bool theMakeGroups,
5233 SMESH_Mesh* theTargetMesh)
5235 myLastCreatedElems.Clear();
5236 myLastCreatedNodes.Clear();
5238 bool needReverse = false;
5239 string groupPostfix;
5240 switch ( theTrsf.Form() ) {
5245 groupPostfix = "mirrored";
5248 groupPostfix = "rotated";
5250 case gp_Translation:
5251 groupPostfix = "translated";
5254 case gp_CompoundTrsf: // different scale by axis
5255 groupPostfix = "scaled";
5258 needReverse = false;
5259 groupPostfix = "transformed";
5262 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5263 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5264 SMESHDS_Mesh* aMesh = GetMeshDS();
5267 // map old node to new one
5268 TNodeNodeMap nodeMap;
5270 // elements sharing moved nodes; those of them which have all
5271 // nodes mirrored but are not in theElems are to be reversed
5272 TIDSortedElemSet inverseElemSet;
5274 // source elements for each generated one
5275 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5277 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5278 list<SMDS_MeshNode> orphanCopy; // copies of orphan nodes
5279 vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5281 if ( theElems.empty() ) // transform the whole mesh
5284 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5285 while ( eIt->more() ) theElems.insert( eIt->next() );
5287 SMDS_MeshElementIDFactory idFactory;
5288 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5289 while ( nIt->more() )
5291 const SMDS_MeshNode* node = nIt->next();
5292 if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5294 // node was not inserted into theElems because an element with the same ID
5295 // is already there. As a work around we insert a copy of node with
5296 // an ID = -<index in orphanNode>
5297 orphanCopy.push_back( *node ); // copy node
5298 SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5299 int uniqueID = -orphanNode.size();
5300 orphanNode.push_back( node );
5301 idFactory.BindID( uniqueID, nodeCopy );
5302 theElems.insert( nodeCopy );
5306 // loop on theElems to transorm nodes
5307 TIDSortedElemSet::iterator itElem;
5308 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5309 const SMDS_MeshElement* elem = *itElem;
5313 // loop on elem nodes
5314 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5315 while ( itN->more() ) {
5317 const SMDS_MeshNode* node = cast2Node( itN->next() );
5318 if ( node->GetID() < 0 )
5319 node = orphanNode[ -node->GetID() ];
5320 // check if a node has been already transformed
5321 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5322 nodeMap.insert( make_pair ( node, node ));
5323 if ( !n2n_isnew.second )
5327 coord[0] = node->X();
5328 coord[1] = node->Y();
5329 coord[2] = node->Z();
5330 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5331 if ( theTargetMesh ) {
5332 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5333 n2n_isnew.first->second = newNode;
5334 myLastCreatedNodes.Append(newNode);
5335 srcNodes.Append( node );
5337 else if ( theCopy ) {
5338 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5339 n2n_isnew.first->second = newNode;
5340 myLastCreatedNodes.Append(newNode);
5341 srcNodes.Append( node );
5344 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5345 // node position on shape becomes invalid
5346 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5347 ( SMDS_SpacePosition::originSpacePosition() );
5350 // keep inverse elements
5351 if ( !theCopy && !theTargetMesh && needReverse ) {
5352 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5353 while ( invElemIt->more() ) {
5354 const SMDS_MeshElement* iel = invElemIt->next();
5355 inverseElemSet.insert( iel );
5361 // either create new elements or reverse mirrored ones
5362 if ( !theCopy && !needReverse && !theTargetMesh )
5365 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5366 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5367 theElems.insert( *invElemIt );
5369 // replicate or reverse elements
5372 REV_TETRA = 0, // = nbNodes - 4
5373 REV_PYRAMID = 1, // = nbNodes - 4
5374 REV_PENTA = 2, // = nbNodes - 4
5376 REV_HEXA = 4, // = nbNodes - 4
5380 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5381 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5382 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5383 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5384 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5385 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5388 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5390 const SMDS_MeshElement* elem = *itElem;
5391 if ( !elem || elem->GetType() == SMDSAbs_Node )
5394 int nbNodes = elem->NbNodes();
5395 int elemType = elem->GetType();
5397 if (elem->IsPoly()) {
5398 // Polygon or Polyhedral Volume
5399 switch ( elemType ) {
5402 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5404 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5405 while (itN->more()) {
5406 const SMDS_MeshNode* node =
5407 static_cast<const SMDS_MeshNode*>(itN->next());
5408 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5409 if (nodeMapIt == nodeMap.end())
5410 break; // not all nodes transformed
5412 // reverse mirrored faces and volumes
5413 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5415 poly_nodes[iNode] = (*nodeMapIt).second;
5419 if ( iNode != nbNodes )
5420 continue; // not all nodes transformed
5422 if ( theTargetMesh ) {
5423 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5424 srcElems.Append( elem );
5426 else if ( theCopy ) {
5427 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5428 srcElems.Append( elem );
5431 aMesh->ChangePolygonNodes(elem, poly_nodes);
5435 case SMDSAbs_Volume:
5437 // ATTENTION: Reversing is not yet done!!!
5438 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5439 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5441 MESSAGE("Warning: bad volumic element");
5445 vector<const SMDS_MeshNode*> poly_nodes;
5446 vector<int> quantities;
5448 bool allTransformed = true;
5449 int nbFaces = aPolyedre->NbFaces();
5450 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5451 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5452 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5453 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5454 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5455 if (nodeMapIt == nodeMap.end()) {
5456 allTransformed = false; // not all nodes transformed
5458 poly_nodes.push_back((*nodeMapIt).second);
5461 quantities.push_back(nbFaceNodes);
5463 if ( !allTransformed )
5464 continue; // not all nodes transformed
5466 if ( theTargetMesh ) {
5467 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5468 srcElems.Append( elem );
5470 else if ( theCopy ) {
5471 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5472 srcElems.Append( elem );
5475 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5485 int* i = index[ FORWARD ];
5486 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5487 if ( elemType == SMDSAbs_Face )
5488 i = index[ REV_FACE ];
5490 i = index[ nbNodes - 4 ];
5492 if(elem->IsQuadratic()) {
5493 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5496 if(nbNodes==3) { // quadratic edge
5497 static int anIds[] = {1,0,2};
5500 else if(nbNodes==6) { // quadratic triangle
5501 static int anIds[] = {0,2,1,5,4,3};
5504 else if(nbNodes==8) { // quadratic quadrangle
5505 static int anIds[] = {0,3,2,1,7,6,5,4};
5508 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5509 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5512 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5513 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5516 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5517 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5520 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5521 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5527 // find transformed nodes
5528 vector<const SMDS_MeshNode*> nodes(nbNodes);
5530 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5531 while ( itN->more() ) {
5532 const SMDS_MeshNode* node =
5533 static_cast<const SMDS_MeshNode*>( itN->next() );
5534 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5535 if ( nodeMapIt == nodeMap.end() )
5536 break; // not all nodes transformed
5537 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5539 if ( iNode != nbNodes )
5540 continue; // not all nodes transformed
5542 if ( theTargetMesh ) {
5543 if ( SMDS_MeshElement* copy =
5544 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5545 myLastCreatedElems.Append( copy );
5546 srcElems.Append( elem );
5549 else if ( theCopy ) {
5550 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5551 srcElems.Append( elem );
5554 // reverse element as it was reversed by transformation
5556 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5560 PGroupIDs newGroupIDs;
5562 if ( theMakeGroups && theCopy ||
5563 theMakeGroups && theTargetMesh )
5564 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5569 //=======================================================================
5571 * \brief Create groups of elements made during transformation
5572 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5573 * \param elemGens - elements making corresponding myLastCreatedElems
5574 * \param postfix - to append to names of new groups
5576 //=======================================================================
5578 SMESH_MeshEditor::PGroupIDs
5579 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5580 const SMESH_SequenceOfElemPtr& elemGens,
5581 const std::string& postfix,
5582 SMESH_Mesh* targetMesh)
5584 PGroupIDs newGroupIDs( new list<int> );
5585 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5587 // Sort existing groups by types and collect their names
5589 // to store an old group and a generated new one
5590 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5591 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5593 set< string > groupNames;
5595 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5596 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5597 while ( groupIt->more() ) {
5598 SMESH_Group * group = groupIt->next();
5599 if ( !group ) continue;
5600 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5601 if ( !groupDS || groupDS->IsEmpty() ) continue;
5602 groupNames.insert( group->GetName() );
5603 groupDS->SetStoreName( group->GetName() );
5604 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5609 // loop on nodes and elements
5610 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5612 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5613 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5614 if ( gens.Length() != elems.Length() )
5615 throw SALOME_Exception(LOCALIZED("invalid args"));
5617 // loop on created elements
5618 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5620 const SMDS_MeshElement* sourceElem = gens( iElem );
5621 if ( !sourceElem ) {
5622 MESSAGE("generateGroups(): NULL source element");
5625 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5626 if ( groupsOldNew.empty() ) {
5627 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5628 ++iElem; // skip all elements made by sourceElem
5631 // collect all elements made by sourceElem
5632 list< const SMDS_MeshElement* > resultElems;
5633 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5634 if ( resElem != sourceElem )
5635 resultElems.push_back( resElem );
5636 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5637 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5638 if ( resElem != sourceElem )
5639 resultElems.push_back( resElem );
5640 // do not generate element groups from node ones
5641 if ( sourceElem->GetType() == SMDSAbs_Node &&
5642 elems( iElem )->GetType() != SMDSAbs_Node )
5645 // add resultElems to groups made by ones the sourceElem belongs to
5646 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5647 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5649 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5650 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5652 SMDS_MeshGroup* & newGroup = gOldNew->second;
5653 if ( !newGroup )// create a new group
5656 string name = oldGroup->GetStoreName();
5657 if ( !targetMesh ) {
5661 while ( !groupNames.insert( name ).second ) // name exists
5667 TCollection_AsciiString nbStr(nb+1);
5668 name.resize( name.rfind('_')+1 );
5669 name += nbStr.ToCString();
5676 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5678 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5679 newGroup = & groupDS->SMDSGroup();
5680 newGroupIDs->push_back( id );
5683 // fill in a new group
5684 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5685 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5686 newGroup->Add( *resElemIt );
5689 } // loop on created elements
5690 }// loop on nodes and elements
5695 //================================================================================
5697 * \brief Return list of group of nodes close to each other within theTolerance
5698 * Search among theNodes or in the whole mesh if theNodes is empty using
5699 * an Octree algorithm
5701 //================================================================================
5703 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
5704 const double theTolerance,
5705 TListOfListOfNodes & theGroupsOfNodes)
5707 myLastCreatedElems.Clear();
5708 myLastCreatedNodes.Clear();
5710 if ( theNodes.empty() )
5711 { // get all nodes in the mesh
5712 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
5713 while ( nIt->more() )
5714 theNodes.insert( theNodes.end(),nIt->next());
5717 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
5721 //=======================================================================
5723 * \brief Implementation of search for the node closest to point
5725 //=======================================================================
5727 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5729 //---------------------------------------------------------------------
5731 * \brief Constructor
5733 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5735 myMesh = ( SMESHDS_Mesh* ) theMesh;
5737 TIDSortedNodeSet nodes;
5739 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
5740 while ( nIt->more() )
5741 nodes.insert( nodes.end(), nIt->next() );
5743 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5745 // get max size of a leaf box
5746 SMESH_OctreeNode* tree = myOctreeNode;
5747 while ( !tree->isLeaf() )
5749 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5753 myHalfLeafSize = tree->maxSize() / 2.;
5756 //---------------------------------------------------------------------
5758 * \brief Move node and update myOctreeNode accordingly
5760 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5762 myOctreeNode->UpdateByMoveNode( node, toPnt );
5763 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5766 //---------------------------------------------------------------------
5768 * \brief Do it's job
5770 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5772 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5773 map<double, const SMDS_MeshNode*> dist2Nodes;
5774 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5775 if ( !dist2Nodes.empty() )
5776 return dist2Nodes.begin()->second;
5777 list<const SMDS_MeshNode*> nodes;
5778 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5780 double minSqDist = DBL_MAX;
5781 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5783 // sort leafs by their distance from thePnt
5784 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5785 TDistTreeMap treeMap;
5786 list< SMESH_OctreeNode* > treeList;
5787 list< SMESH_OctreeNode* >::iterator trIt;
5788 treeList.push_back( myOctreeNode );
5790 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5791 bool pointInside = myOctreeNode->isInside( &pointNode, myHalfLeafSize );
5792 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5794 SMESH_OctreeNode* tree = *trIt;
5795 if ( !tree->isLeaf() ) // put children to the queue
5797 if ( pointInside && !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5798 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5799 while ( cIt->more() )
5800 treeList.push_back( cIt->next() );
5802 else if ( tree->NbNodes() ) // put a tree to the treeMap
5804 const Bnd_B3d& box = tree->getBox();
5805 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5806 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5807 if ( !it_in.second ) // not unique distance to box center
5808 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5811 // find distance after which there is no sense to check tree's
5812 double sqLimit = DBL_MAX;
5813 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5814 if ( treeMap.size() > 5 ) {
5815 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5816 const Bnd_B3d& box = closestTree->getBox();
5817 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5818 sqLimit = limit * limit;
5820 // get all nodes from trees
5821 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5822 if ( sqDist_tree->first > sqLimit )
5824 SMESH_OctreeNode* tree = sqDist_tree->second;
5825 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5828 // find closest among nodes
5829 minSqDist = DBL_MAX;
5830 const SMDS_MeshNode* closestNode = 0;
5831 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5832 for ( ; nIt != nodes.end(); ++nIt ) {
5833 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5834 if ( minSqDist > sqDist ) {
5842 //---------------------------------------------------------------------
5846 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5848 //---------------------------------------------------------------------
5850 * \brief Return the node tree
5852 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5855 SMESH_OctreeNode* myOctreeNode;
5856 SMESHDS_Mesh* myMesh;
5857 double myHalfLeafSize; // max size of a leaf box
5860 //=======================================================================
5862 * \brief Return SMESH_NodeSearcher
5864 //=======================================================================
5866 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5868 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5871 // ========================================================================
5872 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5874 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5875 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5876 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5878 //=======================================================================
5880 * \brief Octal tree of bounding boxes of elements
5882 //=======================================================================
5884 class ElementBndBoxTree : public SMESH_Octree
5888 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
5889 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5890 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5891 ~ElementBndBoxTree();
5894 ElementBndBoxTree() {}
5895 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5896 void buildChildrenData();
5897 Bnd_B3d* buildRootBox();
5899 //!< Bounding box of element
5900 struct ElementBox : public Bnd_B3d
5902 const SMDS_MeshElement* _element;
5903 int _refCount; // an ElementBox can be included in several tree branches
5904 ElementBox(const SMDS_MeshElement* elem, double tolerance);
5906 vector< ElementBox* > _elements;
5909 //================================================================================
5911 * \brief ElementBndBoxTree creation
5913 //================================================================================
5915 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
5916 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5918 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5919 _elements.reserve( nbElems );
5921 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5922 while ( elemIt->more() )
5923 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
5925 if ( _elements.size() > MaxNbElemsInLeaf )
5931 //================================================================================
5935 //================================================================================
5937 ElementBndBoxTree::~ElementBndBoxTree()
5939 for ( int i = 0; i < _elements.size(); ++i )
5940 if ( --_elements[i]->_refCount <= 0 )
5941 delete _elements[i];
5944 //================================================================================
5946 * \brief Return the maximal box
5948 //================================================================================
5950 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5952 Bnd_B3d* box = new Bnd_B3d;
5953 for ( int i = 0; i < _elements.size(); ++i )
5954 box->Add( *_elements[i] );
5958 //================================================================================
5960 * \brief Redistrubute element boxes among children
5962 //================================================================================
5964 void ElementBndBoxTree::buildChildrenData()
5966 for ( int i = 0; i < _elements.size(); ++i )
5968 for (int j = 0; j < 8; j++)
5970 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5972 _elements[i]->_refCount++;
5973 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5976 _elements[i]->_refCount--;
5980 for (int j = 0; j < 8; j++)
5982 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5983 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5984 child->myIsLeaf = true;
5986 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5987 child->_elements.resize( child->_elements.size() ); // compact
5991 //================================================================================
5993 * \brief Return elements which can include the point
5995 //================================================================================
5997 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5998 TIDSortedElemSet& foundElems)
6000 if ( level() && getBox().IsOut( point.XYZ() ))
6005 for ( int i = 0; i < _elements.size(); ++i )
6006 if ( !_elements[i]->IsOut( point.XYZ() ))
6007 foundElems.insert( _elements[i]->_element );
6011 for (int i = 0; i < 8; i++)
6012 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6016 //================================================================================
6018 * \brief Return elements which can be intersected by the line
6020 //================================================================================
6022 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6023 TIDSortedElemSet& foundElems)
6025 if ( level() && getBox().IsOut( line ))
6030 for ( int i = 0; i < _elements.size(); ++i )
6031 if ( !_elements[i]->IsOut( line ))
6032 foundElems.insert( _elements[i]->_element );
6036 for (int i = 0; i < 8; i++)
6037 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6041 //================================================================================
6043 * \brief Construct the element box
6045 //================================================================================
6047 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6051 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6052 while ( nIt->more() )
6053 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6054 Enlarge( tolerance );
6059 //=======================================================================
6061 * \brief Implementation of search for the elements by point and
6062 * of classification of point in 2D mesh
6064 //=======================================================================
6066 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6068 SMESHDS_Mesh* _mesh;
6069 ElementBndBoxTree* _ebbTree;
6070 SMESH_NodeSearcherImpl* _nodeSearcher;
6071 SMDSAbs_ElementType _elementType;
6073 bool _outerFacesFound;
6074 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6076 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6077 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6078 ~SMESH_ElementSearcherImpl()
6080 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6081 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6083 virtual int FindElementsByPoint(const gp_Pnt& point,
6084 SMDSAbs_ElementType type,
6085 vector< const SMDS_MeshElement* >& foundElements);
6086 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6088 void GetElementsNearLine( const gp_Ax1& line,
6089 SMDSAbs_ElementType type,
6090 vector< const SMDS_MeshElement* >& foundElems);
6091 double getTolerance();
6092 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6093 const double tolerance, double & param);
6094 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6095 bool isOuterBoundary(const SMDS_MeshElement* face) const
6097 return _outerFaces.empty() || _outerFaces.count(face);
6099 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6101 const SMDS_MeshElement* _face;
6103 bool _coincides; //!< the line lays in face plane
6104 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6105 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6107 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6110 TIDSortedElemSet _faces;
6111 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6112 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6116 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6118 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6119 << ", _coincides="<<i._coincides << ")";
6122 //=======================================================================
6124 * \brief define tolerance for search
6126 //=======================================================================
6128 double SMESH_ElementSearcherImpl::getTolerance()
6130 if ( _tolerance < 0 )
6132 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6135 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6137 double boxSize = _nodeSearcher->getTree()->maxSize();
6138 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6140 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6142 double boxSize = _ebbTree->maxSize();
6143 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6145 if ( _tolerance == 0 )
6147 // define tolerance by size of a most complex element
6148 int complexType = SMDSAbs_Volume;
6149 while ( complexType > SMDSAbs_All &&
6150 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6152 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6155 if ( complexType == int( SMDSAbs_Node ))
6157 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6159 if ( meshInfo.NbNodes() > 2 )
6160 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6164 const SMDS_MeshElement* elem =
6165 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6166 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6167 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6168 while ( nodeIt->more() )
6170 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6171 elemSize = max( dist, elemSize );
6174 _tolerance = 1e-4 * elemSize;
6180 //================================================================================
6182 * \brief Find intersection of the line and an edge of face and return parameter on line
6184 //================================================================================
6186 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6187 const SMDS_MeshElement* face,
6194 GeomAPI_ExtremaCurveCurve anExtCC;
6195 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6197 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6198 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6200 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6201 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6202 anExtCC.Init( lineCurve, edge);
6203 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6205 Quantity_Parameter pl, pe;
6206 anExtCC.LowerDistanceParameters( pl, pe );
6208 if ( ++nbInts == 2 )
6212 if ( nbInts > 0 ) param /= nbInts;
6215 //================================================================================
6217 * \brief Find all faces belonging to the outer boundary of mesh
6219 //================================================================================
6221 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6223 if ( _outerFacesFound ) return;
6225 // Collect all outer faces by passing from one outer face to another via their links
6226 // and BTW find out if there are internal faces at all.
6228 // checked links and links where outer boundary meets internal one
6229 set< SMESH_TLink > visitedLinks, seamLinks;
6231 // links to treat with already visited faces sharing them
6232 list < TFaceLink > startLinks;
6234 // load startLinks with the first outerFace
6235 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6236 _outerFaces.insert( outerFace );
6238 TIDSortedElemSet emptySet;
6239 while ( !startLinks.empty() )
6241 const SMESH_TLink& link = startLinks.front()._link;
6242 TIDSortedElemSet& faces = startLinks.front()._faces;
6244 outerFace = *faces.begin();
6245 // find other faces sharing the link
6246 const SMDS_MeshElement* f;
6247 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6250 // select another outer face among the found
6251 const SMDS_MeshElement* outerFace2 = 0;
6252 if ( faces.size() == 2 )
6254 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6256 else if ( faces.size() > 2 )
6258 seamLinks.insert( link );
6260 // link direction within the outerFace
6261 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6262 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6263 int i1 = outerFace->GetNodeIndex( link.node1() );
6264 int i2 = outerFace->GetNodeIndex( link.node2() );
6265 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6266 if ( rev ) n1n2.Reverse();
6268 gp_XYZ ofNorm, fNorm;
6269 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6271 // direction from the link inside outerFace
6272 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6273 // sort all other faces by angle with the dirInOF
6274 map< double, const SMDS_MeshElement* > angle2Face;
6275 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6276 for ( ; face != faces.end(); ++face )
6278 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6280 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6281 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6282 if ( angle < 0 ) angle += 2*PI;
6283 angle2Face.insert( make_pair( angle, *face ));
6285 if ( !angle2Face.empty() )
6286 outerFace2 = angle2Face.begin()->second;
6289 // store the found outer face and add its links to continue seaching from
6292 _outerFaces.insert( outerFace );
6293 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6294 for ( int i = 0; i < nbNodes; ++i )
6296 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6297 if ( visitedLinks.insert( link2 ).second )
6298 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6301 startLinks.pop_front();
6303 _outerFacesFound = true;
6305 if ( !seamLinks.empty() )
6307 // There are internal boundaries touching the outher one,
6308 // find all faces of internal boundaries in order to find
6309 // faces of boundaries of holes, if any.
6314 _outerFaces.clear();
6318 //=======================================================================
6320 * \brief Find elements of given type where the given point is IN or ON.
6321 * Returns nb of found elements and elements them-selves.
6323 * 'ALL' type means elements of any type excluding nodes and 0D elements
6325 //=======================================================================
6327 int SMESH_ElementSearcherImpl::
6328 FindElementsByPoint(const gp_Pnt& point,
6329 SMDSAbs_ElementType type,
6330 vector< const SMDS_MeshElement* >& foundElements)
6332 foundElements.clear();
6334 double tolerance = getTolerance();
6336 // =================================================================================
6337 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6339 if ( !_nodeSearcher )
6340 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6342 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6343 if ( !closeNode ) return foundElements.size();
6345 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6346 return foundElements.size(); // to far from any node
6348 if ( type == SMDSAbs_Node )
6350 foundElements.push_back( closeNode );
6354 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6355 while ( elemIt->more() )
6356 foundElements.push_back( elemIt->next() );
6359 // =================================================================================
6360 else // elements more complex than 0D
6362 if ( !_ebbTree || _elementType != type )
6364 if ( _ebbTree ) delete _ebbTree;
6365 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6367 TIDSortedElemSet suspectElems;
6368 _ebbTree->getElementsNearPoint( point, suspectElems );
6369 TIDSortedElemSet::iterator elem = suspectElems.begin();
6370 for ( ; elem != suspectElems.end(); ++elem )
6371 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6372 foundElements.push_back( *elem );
6374 return foundElements.size();
6377 //================================================================================
6379 * \brief Classify the given point in the closed 2D mesh
6381 //================================================================================
6383 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6385 double tolerance = getTolerance();
6386 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6388 if ( _ebbTree ) delete _ebbTree;
6389 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6391 // Algo: analyse transition of a line starting at the point through mesh boundary;
6392 // try three lines parallel to axis of the coordinate system and perform rough
6393 // analysis. If solution is not clear perform thorough analysis.
6395 const int nbAxes = 3;
6396 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6397 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6398 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6399 multimap< int, int > nbInt2Axis; // to find the simplest case
6400 for ( int axis = 0; axis < nbAxes; ++axis )
6402 gp_Ax1 lineAxis( point, axisDir[axis]);
6403 gp_Lin line ( lineAxis );
6405 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6406 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6408 // Intersect faces with the line
6410 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6411 TIDSortedElemSet::iterator face = suspectFaces.begin();
6412 for ( ; face != suspectFaces.end(); ++face )
6416 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6417 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6419 // perform intersection
6420 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6421 if ( !intersection.IsDone() )
6423 if ( intersection.IsInQuadric() )
6425 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6427 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6429 gp_Pnt intersectionPoint = intersection.Point(1);
6430 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6431 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6434 // Analyse intersections roughly
6436 int nbInter = u2inters.size();
6440 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6441 if ( nbInter == 1 ) // not closed mesh
6442 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6444 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6447 if ( (f<0) == (l<0) )
6450 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6451 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6452 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6455 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6457 if ( _outerFacesFound ) break; // pass to thorough analysis
6459 } // three attempts - loop on CS axes
6461 // Analyse intersections thoroughly.
6462 // We make two loops maximum, on the first one we only exclude touching intersections,
6463 // on the second, if situation is still unclear, we gather and use information on
6464 // position of faces (internal or outer). If faces position is already gathered,
6465 // we make the second loop right away.
6467 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6469 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6470 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6472 int axis = nb_axis->second;
6473 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6475 gp_Ax1 lineAxis( point, axisDir[axis]);
6476 gp_Lin line ( lineAxis );
6478 // add tangent intersections to u2inters
6480 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6481 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6482 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6483 u2inters.insert(make_pair( param, *tgtInt ));
6484 tangentInters[ axis ].clear();
6486 // Count intersections before and after the point excluding touching ones.
6487 // If hasPositionInfo we count intersections of outer boundary only
6489 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6490 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6491 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6492 bool ok = ! u_int1->second._coincides;
6493 while ( ok && u_int1 != u2inters.end() )
6495 double u = u_int1->first;
6496 bool touchingInt = false;
6497 if ( ++u_int2 != u2inters.end() )
6499 // skip intersections at the same point (if the line passes through edge or node)
6501 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6507 // skip tangent intersections
6509 const SMDS_MeshElement* prevFace = u_int1->second._face;
6510 while ( ok && u_int2->second._coincides )
6512 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6518 ok = ( u_int2 != u2inters.end() );
6523 // skip intersections at the same point after tangent intersections
6526 double u2 = u_int2->first;
6528 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6534 // decide if we skipped a touching intersection
6535 if ( nbSamePnt + nbTgt > 0 )
6537 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6538 map< double, TInters >::iterator u_int = u_int1;
6539 for ( ; u_int != u_int2; ++u_int )
6541 if ( u_int->second._coincides ) continue;
6542 double dot = u_int->second._faceNorm * line.Direction();
6543 if ( dot > maxDot ) maxDot = dot;
6544 if ( dot < minDot ) minDot = dot;
6546 touchingInt = ( minDot*maxDot < 0 );
6551 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6562 u_int1 = u_int2; // to next intersection
6564 } // loop on intersections with one line
6568 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6571 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6574 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6575 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6577 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6580 if ( (f<0) == (l<0) )
6583 if ( hasPositionInfo )
6584 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6586 } // loop on intersections of the tree lines - thorough analysis
6588 if ( !hasPositionInfo )
6590 // gather info on faces position - is face in the outer boundary or not
6591 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6592 findOuterBoundary( u2inters.begin()->second._face );
6595 } // two attempts - with and w/o faces position info in the mesh
6597 return TopAbs_UNKNOWN;
6600 //=======================================================================
6602 * \brief Return elements possibly intersecting the line
6604 //=======================================================================
6606 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
6607 SMDSAbs_ElementType type,
6608 vector< const SMDS_MeshElement* >& foundElems)
6610 if ( !_ebbTree || _elementType != type )
6612 if ( _ebbTree ) delete _ebbTree;
6613 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6615 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6616 _ebbTree->getElementsNearLine( line, suspectFaces );
6617 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6620 //=======================================================================
6622 * \brief Return SMESH_ElementSearcher
6624 //=======================================================================
6626 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6628 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6631 //=======================================================================
6633 * \brief Return true if the point is IN or ON of the element
6635 //=======================================================================
6637 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6639 if ( element->GetType() == SMDSAbs_Volume)
6641 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6644 // get ordered nodes
6646 vector< gp_XYZ > xyz;
6648 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6649 if ( element->IsQuadratic() )
6650 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6651 nodeIt = f->interlacedNodesElemIterator();
6652 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6653 nodeIt = e->interlacedNodesElemIterator();
6655 while ( nodeIt->more() )
6656 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6658 int i, nbNodes = element->NbNodes();
6660 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6662 // compute face normal
6663 gp_Vec faceNorm(0,0,0);
6664 xyz.push_back( xyz.front() );
6665 for ( i = 0; i < nbNodes; ++i )
6667 gp_Vec edge1( xyz[i+1], xyz[i]);
6668 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6669 faceNorm += edge1 ^ edge2;
6671 double normSize = faceNorm.Magnitude();
6672 if ( normSize <= tol )
6674 // degenerated face: point is out if it is out of all face edges
6675 for ( i = 0; i < nbNodes; ++i )
6677 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6678 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6679 SMDS_MeshEdge edge( &n1, &n2 );
6680 if ( !isOut( &edge, point, tol ))
6685 faceNorm /= normSize;
6687 // check if the point lays on face plane
6688 gp_Vec n2p( xyz[0], point );
6689 if ( fabs( n2p * faceNorm ) > tol )
6690 return true; // not on face plane
6692 // check if point is out of face boundary:
6693 // define it by closest transition of a ray point->infinity through face boundary
6694 // on the face plane.
6695 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6696 // to find intersections of the ray with the boundary.
6698 gp_Vec plnNorm = ray ^ faceNorm;
6699 normSize = plnNorm.Magnitude();
6700 if ( normSize <= tol ) return false; // point coincides with the first node
6701 plnNorm /= normSize;
6702 // for each node of the face, compute its signed distance to the plane
6703 vector<double> dist( nbNodes + 1);
6704 for ( i = 0; i < nbNodes; ++i )
6706 gp_Vec n2p( xyz[i], point );
6707 dist[i] = n2p * plnNorm;
6709 dist.back() = dist.front();
6710 // find the closest intersection
6712 double rClosest, distClosest = 1e100;;
6714 for ( i = 0; i < nbNodes; ++i )
6717 if ( fabs( dist[i]) < tol )
6719 else if ( fabs( dist[i+1]) < tol )
6721 else if ( dist[i] * dist[i+1] < 0 )
6722 r = dist[i] / ( dist[i] - dist[i+1] );
6724 continue; // no intersection
6725 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6726 gp_Vec p2int ( point, pInt);
6727 if ( p2int * ray > -tol ) // right half-space
6729 double intDist = p2int.SquareMagnitude();
6730 if ( intDist < distClosest )
6735 distClosest = intDist;
6740 return true; // no intesections - out
6742 // analyse transition
6743 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6744 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6745 gp_Vec p2int ( point, pClosest );
6746 bool out = (edgeNorm * p2int) < -tol;
6747 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6750 // ray pass through a face node; analyze transition through an adjacent edge
6751 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6752 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6753 gp_Vec edgeAdjacent( p1, p2 );
6754 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6755 bool out2 = (edgeNorm2 * p2int) < -tol;
6757 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6758 return covexCorner ? (out || out2) : (out && out2);
6760 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6762 // point is out of edge if it is NOT ON any straight part of edge
6763 // (we consider quadratic edge as being composed of two straight parts)
6764 for ( i = 1; i < nbNodes; ++i )
6766 gp_Vec edge( xyz[i-1], xyz[i]);
6767 gp_Vec n1p ( xyz[i-1], point);
6768 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6771 gp_Vec n2p( xyz[i], point );
6772 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6774 return false; // point is ON this part
6778 // Node or 0D element -------------------------------------------------------------------------
6780 gp_Vec n2p ( xyz[0], point );
6781 return n2p.Magnitude() <= tol;
6786 //=======================================================================
6787 //function : SimplifyFace
6789 //=======================================================================
6790 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6791 vector<const SMDS_MeshNode *>& poly_nodes,
6792 vector<int>& quantities) const
6794 int nbNodes = faceNodes.size();
6799 set<const SMDS_MeshNode*> nodeSet;
6801 // get simple seq of nodes
6802 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6803 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6804 int iSimple = 0, nbUnique = 0;
6806 simpleNodes[iSimple++] = faceNodes[0];
6808 for (int iCur = 1; iCur < nbNodes; iCur++) {
6809 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6810 simpleNodes[iSimple++] = faceNodes[iCur];
6811 if (nodeSet.insert( faceNodes[iCur] ).second)
6815 int nbSimple = iSimple;
6816 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6826 bool foundLoop = (nbSimple > nbUnique);
6829 set<const SMDS_MeshNode*> loopSet;
6830 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6831 const SMDS_MeshNode* n = simpleNodes[iSimple];
6832 if (!loopSet.insert( n ).second) {
6836 int iC = 0, curLast = iSimple;
6837 for (; iC < curLast; iC++) {
6838 if (simpleNodes[iC] == n) break;
6840 int loopLen = curLast - iC;
6842 // create sub-element
6844 quantities.push_back(loopLen);
6845 for (; iC < curLast; iC++) {
6846 poly_nodes.push_back(simpleNodes[iC]);
6849 // shift the rest nodes (place from the first loop position)
6850 for (iC = curLast + 1; iC < nbSimple; iC++) {
6851 simpleNodes[iC - loopLen] = simpleNodes[iC];
6853 nbSimple -= loopLen;
6856 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6857 } // while (foundLoop)
6861 quantities.push_back(iSimple);
6862 for (int i = 0; i < iSimple; i++)
6863 poly_nodes.push_back(simpleNodes[i]);
6869 //=======================================================================
6870 //function : MergeNodes
6871 //purpose : In each group, the cdr of nodes are substituted by the first one
6873 //=======================================================================
6875 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6877 myLastCreatedElems.Clear();
6878 myLastCreatedNodes.Clear();
6880 SMESHDS_Mesh* aMesh = GetMeshDS();
6882 TNodeNodeMap nodeNodeMap; // node to replace - new node
6883 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6884 list< int > rmElemIds, rmNodeIds;
6886 // Fill nodeNodeMap and elems
6888 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6889 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6890 list<const SMDS_MeshNode*>& nodes = *grIt;
6891 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6892 const SMDS_MeshNode* nToKeep = *nIt;
6893 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6894 const SMDS_MeshNode* nToRemove = *nIt;
6895 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6896 if ( nToRemove != nToKeep ) {
6897 rmNodeIds.push_back( nToRemove->GetID() );
6898 AddToSameGroups( nToKeep, nToRemove, aMesh );
6901 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6902 while ( invElemIt->more() ) {
6903 const SMDS_MeshElement* elem = invElemIt->next();
6908 // Change element nodes or remove an element
6910 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6911 for ( ; eIt != elems.end(); eIt++ ) {
6912 const SMDS_MeshElement* elem = *eIt;
6913 int nbNodes = elem->NbNodes();
6914 int aShapeId = FindShape( elem );
6916 set<const SMDS_MeshNode*> nodeSet;
6917 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6918 int iUnique = 0, iCur = 0, nbRepl = 0;
6919 vector<int> iRepl( nbNodes );
6921 // get new seq of nodes
6922 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6923 while ( itN->more() ) {
6924 const SMDS_MeshNode* n =
6925 static_cast<const SMDS_MeshNode*>( itN->next() );
6927 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6928 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6930 // BUG 0020185: begin
6932 bool stopRecur = false;
6933 set<const SMDS_MeshNode*> nodesRecur;
6934 nodesRecur.insert(n);
6935 while (!stopRecur) {
6936 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6937 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6938 n = (*nnIt_i).second;
6939 if (!nodesRecur.insert(n).second) {
6940 // error: recursive dependancy
6949 iRepl[ nbRepl++ ] = iCur;
6951 curNodes[ iCur ] = n;
6952 bool isUnique = nodeSet.insert( n ).second;
6954 uniqueNodes[ iUnique++ ] = n;
6958 // Analyse element topology after replacement
6961 int nbUniqueNodes = nodeSet.size();
6962 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6963 // Polygons and Polyhedral volumes
6964 if (elem->IsPoly()) {
6966 if (elem->GetType() == SMDSAbs_Face) {
6968 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6970 for (; inode < nbNodes; inode++) {
6971 face_nodes[inode] = curNodes[inode];
6974 vector<const SMDS_MeshNode *> polygons_nodes;
6975 vector<int> quantities;
6976 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6980 for (int iface = 0; iface < nbNew - 1; iface++) {
6981 int nbNodes = quantities[iface];
6982 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6983 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6984 poly_nodes[ii] = polygons_nodes[inode];
6986 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6987 myLastCreatedElems.Append(newElem);
6989 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6991 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6994 rmElemIds.push_back(elem->GetID());
6998 else if (elem->GetType() == SMDSAbs_Volume) {
6999 // Polyhedral volume
7000 if (nbUniqueNodes < 4) {
7001 rmElemIds.push_back(elem->GetID());
7004 // each face has to be analized in order to check volume validity
7005 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7006 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7008 int nbFaces = aPolyedre->NbFaces();
7010 vector<const SMDS_MeshNode *> poly_nodes;
7011 vector<int> quantities;
7013 for (int iface = 1; iface <= nbFaces; iface++) {
7014 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7015 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7017 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7018 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7019 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7020 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7021 faceNode = (*nnIt).second;
7023 faceNodes[inode - 1] = faceNode;
7026 SimplifyFace(faceNodes, poly_nodes, quantities);
7029 if (quantities.size() > 3) {
7030 // to be done: remove coincident faces
7033 if (quantities.size() > 3)
7034 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7036 rmElemIds.push_back(elem->GetID());
7040 rmElemIds.push_back(elem->GetID());
7051 switch ( nbNodes ) {
7052 case 2: ///////////////////////////////////// EDGE
7053 isOk = false; break;
7054 case 3: ///////////////////////////////////// TRIANGLE
7055 isOk = false; break;
7057 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7059 else { //////////////////////////////////// QUADRANGLE
7060 if ( nbUniqueNodes < 3 )
7062 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7063 isOk = false; // opposite nodes stick
7066 case 6: ///////////////////////////////////// PENTAHEDRON
7067 if ( nbUniqueNodes == 4 ) {
7068 // ---------------------------------> tetrahedron
7070 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7071 // all top nodes stick: reverse a bottom
7072 uniqueNodes[ 0 ] = curNodes [ 1 ];
7073 uniqueNodes[ 1 ] = curNodes [ 0 ];
7075 else if (nbRepl == 3 &&
7076 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7077 // all bottom nodes stick: set a top before
7078 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7079 uniqueNodes[ 0 ] = curNodes [ 3 ];
7080 uniqueNodes[ 1 ] = curNodes [ 4 ];
7081 uniqueNodes[ 2 ] = curNodes [ 5 ];
7083 else if (nbRepl == 4 &&
7084 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7085 // a lateral face turns into a line: reverse a bottom
7086 uniqueNodes[ 0 ] = curNodes [ 1 ];
7087 uniqueNodes[ 1 ] = curNodes [ 0 ];
7092 else if ( nbUniqueNodes == 5 ) {
7093 // PENTAHEDRON --------------------> 2 tetrahedrons
7094 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7095 // a bottom node sticks with a linked top one
7097 SMDS_MeshElement* newElem =
7098 aMesh->AddVolume(curNodes[ 3 ],
7101 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7102 myLastCreatedElems.Append(newElem);
7104 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7105 // 2. : reverse a bottom
7106 uniqueNodes[ 0 ] = curNodes [ 1 ];
7107 uniqueNodes[ 1 ] = curNodes [ 0 ];
7117 if(elem->IsQuadratic()) { // Quadratic quadrangle
7130 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7131 uniqueNodes[0] = curNodes[0];
7132 uniqueNodes[1] = curNodes[2];
7133 uniqueNodes[2] = curNodes[3];
7134 uniqueNodes[3] = curNodes[5];
7135 uniqueNodes[4] = curNodes[6];
7136 uniqueNodes[5] = curNodes[7];
7139 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7140 uniqueNodes[0] = curNodes[0];
7141 uniqueNodes[1] = curNodes[1];
7142 uniqueNodes[2] = curNodes[2];
7143 uniqueNodes[3] = curNodes[4];
7144 uniqueNodes[4] = curNodes[5];
7145 uniqueNodes[5] = curNodes[6];
7148 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7149 uniqueNodes[0] = curNodes[1];
7150 uniqueNodes[1] = curNodes[2];
7151 uniqueNodes[2] = curNodes[3];
7152 uniqueNodes[3] = curNodes[5];
7153 uniqueNodes[4] = curNodes[6];
7154 uniqueNodes[5] = curNodes[0];
7157 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7158 uniqueNodes[0] = curNodes[0];
7159 uniqueNodes[1] = curNodes[1];
7160 uniqueNodes[2] = curNodes[3];
7161 uniqueNodes[3] = curNodes[4];
7162 uniqueNodes[4] = curNodes[6];
7163 uniqueNodes[5] = curNodes[7];
7166 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7167 uniqueNodes[0] = curNodes[0];
7168 uniqueNodes[1] = curNodes[2];
7169 uniqueNodes[2] = curNodes[3];
7170 uniqueNodes[3] = curNodes[1];
7171 uniqueNodes[4] = curNodes[6];
7172 uniqueNodes[5] = curNodes[7];
7175 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7176 uniqueNodes[0] = curNodes[0];
7177 uniqueNodes[1] = curNodes[1];
7178 uniqueNodes[2] = curNodes[2];
7179 uniqueNodes[3] = curNodes[4];
7180 uniqueNodes[4] = curNodes[5];
7181 uniqueNodes[5] = curNodes[7];
7184 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7185 uniqueNodes[0] = curNodes[0];
7186 uniqueNodes[1] = curNodes[1];
7187 uniqueNodes[2] = curNodes[3];
7188 uniqueNodes[3] = curNodes[4];
7189 uniqueNodes[4] = curNodes[2];
7190 uniqueNodes[5] = curNodes[7];
7193 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7194 uniqueNodes[0] = curNodes[0];
7195 uniqueNodes[1] = curNodes[1];
7196 uniqueNodes[2] = curNodes[2];
7197 uniqueNodes[3] = curNodes[4];
7198 uniqueNodes[4] = curNodes[5];
7199 uniqueNodes[5] = curNodes[3];
7205 //////////////////////////////////// HEXAHEDRON
7207 SMDS_VolumeTool hexa (elem);
7208 hexa.SetExternalNormal();
7209 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7210 //////////////////////// ---> tetrahedron
7211 for ( int iFace = 0; iFace < 6; iFace++ ) {
7212 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7213 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7214 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7215 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7216 // one face turns into a point ...
7217 int iOppFace = hexa.GetOppFaceIndex( iFace );
7218 ind = hexa.GetFaceNodesIndices( iOppFace );
7220 iUnique = 2; // reverse a tetrahedron bottom
7221 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7222 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7224 else if ( iUnique >= 0 )
7225 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7227 if ( nbStick == 1 ) {
7228 // ... and the opposite one - into a triangle.
7230 ind = hexa.GetFaceNodesIndices( iFace );
7231 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7238 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7239 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7240 for ( int iFace = 0; iFace < 6; iFace++ ) {
7241 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7242 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7243 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7244 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7245 // one face turns into a point ...
7246 int iOppFace = hexa.GetOppFaceIndex( iFace );
7247 ind = hexa.GetFaceNodesIndices( iOppFace );
7249 iUnique = 2; // reverse a tetrahedron 1 bottom
7250 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7251 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7253 else if ( iUnique >= 0 )
7254 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7256 if ( nbStick == 0 ) {
7257 // ... and the opposite one is a quadrangle
7259 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7260 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7263 SMDS_MeshElement* newElem =
7264 aMesh->AddVolume(curNodes[ind[ 0 ]],
7267 curNodes[indTop[ 0 ]]);
7268 myLastCreatedElems.Append(newElem);
7270 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7277 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7278 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7279 // find indices of quad and tri faces
7280 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7281 for ( iFace = 0; iFace < 6; iFace++ ) {
7282 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7284 for ( iCur = 0; iCur < 4; iCur++ )
7285 nodeSet.insert( curNodes[ind[ iCur ]] );
7286 nbUniqueNodes = nodeSet.size();
7287 if ( nbUniqueNodes == 3 )
7288 iTriFace[ nbTri++ ] = iFace;
7289 else if ( nbUniqueNodes == 4 )
7290 iQuadFace[ nbQuad++ ] = iFace;
7292 if (nbQuad == 2 && nbTri == 4 &&
7293 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7294 // 2 opposite quadrangles stuck with a diagonal;
7295 // sample groups of merged indices: (0-4)(2-6)
7296 // --------------------------------------------> 2 tetrahedrons
7297 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7298 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7299 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7300 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7301 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7302 // stuck with 0-2 diagonal
7310 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7311 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7312 // stuck with 1-3 diagonal
7324 uniqueNodes[ 0 ] = curNodes [ i0 ];
7325 uniqueNodes[ 1 ] = curNodes [ i1d ];
7326 uniqueNodes[ 2 ] = curNodes [ i3d ];
7327 uniqueNodes[ 3 ] = curNodes [ i0t ];
7330 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7334 myLastCreatedElems.Append(newElem);
7336 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7339 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7340 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7341 // --------------------------------------------> prism
7342 // find 2 opposite triangles
7344 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7345 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7346 // find indices of kept and replaced nodes
7347 // and fill unique nodes of 2 opposite triangles
7348 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7349 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7350 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7351 // fill unique nodes
7354 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7355 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7356 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7358 // iCur of a linked node of the opposite face (make normals co-directed):
7359 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7360 // check that correspondent corners of triangles are linked
7361 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7364 uniqueNodes[ iUnique ] = n;
7365 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7374 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7380 } // switch ( nbNodes )
7382 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7385 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7386 // Change nodes of polyedre
7387 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7388 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7390 int nbFaces = aPolyedre->NbFaces();
7392 vector<const SMDS_MeshNode *> poly_nodes;
7393 vector<int> quantities (nbFaces);
7395 for (int iface = 1; iface <= nbFaces; iface++) {
7396 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7397 quantities[iface - 1] = nbFaceNodes;
7399 for (inode = 1; inode <= nbFaceNodes; inode++) {
7400 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7402 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7403 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7404 curNode = (*nnIt).second;
7406 poly_nodes.push_back(curNode);
7409 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7413 // Change regular element or polygon
7414 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7418 // Remove invalid regular element or invalid polygon
7419 rmElemIds.push_back( elem->GetID() );
7422 } // loop on elements
7424 // Remove equal nodes and bad elements
7426 Remove( rmNodeIds, true );
7427 Remove( rmElemIds, false );
7432 // ========================================================
7433 // class : SortableElement
7434 // purpose : allow sorting elements basing on their nodes
7435 // ========================================================
7436 class SortableElement : public set <const SMDS_MeshElement*>
7440 SortableElement( const SMDS_MeshElement* theElem )
7443 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7444 while ( nodeIt->more() )
7445 this->insert( nodeIt->next() );
7448 const SMDS_MeshElement* Get() const
7451 void Set(const SMDS_MeshElement* e) const
7456 mutable const SMDS_MeshElement* myElem;
7459 //=======================================================================
7460 //function : FindEqualElements
7461 //purpose : Return list of group of elements built on the same nodes.
7462 // Search among theElements or in the whole mesh if theElements is empty
7463 //=======================================================================
7464 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7465 TListOfListOfElementsID & theGroupsOfElementsID)
7467 myLastCreatedElems.Clear();
7468 myLastCreatedNodes.Clear();
7470 typedef set<const SMDS_MeshElement*> TElemsSet;
7471 typedef map< SortableElement, int > TMapOfNodeSet;
7472 typedef list<int> TGroupOfElems;
7475 if ( theElements.empty() )
7476 { // get all elements in the mesh
7477 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7478 while ( eIt->more() )
7479 elems.insert( elems.end(), eIt->next());
7482 elems = theElements;
7484 vector< TGroupOfElems > arrayOfGroups;
7485 TGroupOfElems groupOfElems;
7486 TMapOfNodeSet mapOfNodeSet;
7488 TElemsSet::iterator elemIt = elems.begin();
7489 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7490 const SMDS_MeshElement* curElem = *elemIt;
7491 SortableElement SE(curElem);
7494 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7495 if( !(pp.second) ) {
7496 TMapOfNodeSet::iterator& itSE = pp.first;
7497 ind = (*itSE).second;
7498 arrayOfGroups[ind].push_back(curElem->GetID());
7501 groupOfElems.clear();
7502 groupOfElems.push_back(curElem->GetID());
7503 arrayOfGroups.push_back(groupOfElems);
7508 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7509 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7510 groupOfElems = *groupIt;
7511 if ( groupOfElems.size() > 1 ) {
7512 groupOfElems.sort();
7513 theGroupsOfElementsID.push_back(groupOfElems);
7518 //=======================================================================
7519 //function : MergeElements
7520 //purpose : In each given group, substitute all elements by the first one.
7521 //=======================================================================
7523 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7525 myLastCreatedElems.Clear();
7526 myLastCreatedNodes.Clear();
7528 typedef list<int> TListOfIDs;
7529 TListOfIDs rmElemIds; // IDs of elems to remove
7531 SMESHDS_Mesh* aMesh = GetMeshDS();
7533 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7534 while ( groupsIt != theGroupsOfElementsID.end() ) {
7535 TListOfIDs& aGroupOfElemID = *groupsIt;
7536 aGroupOfElemID.sort();
7537 int elemIDToKeep = aGroupOfElemID.front();
7538 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7539 aGroupOfElemID.pop_front();
7540 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7541 while ( idIt != aGroupOfElemID.end() ) {
7542 int elemIDToRemove = *idIt;
7543 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7544 // add the kept element in groups of removed one (PAL15188)
7545 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7546 rmElemIds.push_back( elemIDToRemove );
7552 Remove( rmElemIds, false );
7555 //=======================================================================
7556 //function : MergeEqualElements
7557 //purpose : Remove all but one of elements built on the same nodes.
7558 //=======================================================================
7560 void SMESH_MeshEditor::MergeEqualElements()
7562 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7563 to merge equal elements in the whole mesh */
7564 TListOfListOfElementsID aGroupsOfElementsID;
7565 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7566 MergeElements(aGroupsOfElementsID);
7569 //=======================================================================
7570 //function : FindFaceInSet
7571 //purpose : Return a face having linked nodes n1 and n2 and which is
7572 // - not in avoidSet,
7573 // - in elemSet provided that !elemSet.empty()
7574 // i1 and i2 optionally returns indices of n1 and n2
7575 //=======================================================================
7577 const SMDS_MeshElement*
7578 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7579 const SMDS_MeshNode* n2,
7580 const TIDSortedElemSet& elemSet,
7581 const TIDSortedElemSet& avoidSet,
7587 const SMDS_MeshElement* face = 0;
7589 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7590 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7592 const SMDS_MeshElement* elem = invElemIt->next();
7593 if (avoidSet.count( elem ))
7595 if ( !elemSet.empty() && !elemSet.count( elem ))
7598 i1 = elem->GetNodeIndex( n1 );
7599 // find a n2 linked to n1
7600 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7601 for ( int di = -1; di < 2 && !face; di += 2 )
7603 i2 = (i1+di+nbN) % nbN;
7604 if ( elem->GetNode( i2 ) == n2 )
7607 if ( !face && elem->IsQuadratic())
7609 // analysis for quadratic elements using all nodes
7610 const SMDS_QuadraticFaceOfNodes* F =
7611 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7612 // use special nodes iterator
7613 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7614 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7615 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7617 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7618 if ( n1 == prevN && n2 == n )
7622 else if ( n2 == prevN && n1 == n )
7624 face = elem; swap( i1, i2 );
7630 if ( n1ind ) *n1ind = i1;
7631 if ( n2ind ) *n2ind = i2;
7635 //=======================================================================
7636 //function : findAdjacentFace
7638 //=======================================================================
7640 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7641 const SMDS_MeshNode* n2,
7642 const SMDS_MeshElement* elem)
7644 TIDSortedElemSet elemSet, avoidSet;
7646 avoidSet.insert ( elem );
7647 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7650 //=======================================================================
7651 //function : FindFreeBorder
7653 //=======================================================================
7655 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7657 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7658 const SMDS_MeshNode* theSecondNode,
7659 const SMDS_MeshNode* theLastNode,
7660 list< const SMDS_MeshNode* > & theNodes,
7661 list< const SMDS_MeshElement* >& theFaces)
7663 if ( !theFirstNode || !theSecondNode )
7665 // find border face between theFirstNode and theSecondNode
7666 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7670 theFaces.push_back( curElem );
7671 theNodes.push_back( theFirstNode );
7672 theNodes.push_back( theSecondNode );
7674 //vector<const SMDS_MeshNode*> nodes;
7675 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7676 TIDSortedElemSet foundElems;
7677 bool needTheLast = ( theLastNode != 0 );
7679 while ( nStart != theLastNode ) {
7680 if ( nStart == theFirstNode )
7681 return !needTheLast;
7683 // find all free border faces sharing form nStart
7685 list< const SMDS_MeshElement* > curElemList;
7686 list< const SMDS_MeshNode* > nStartList;
7687 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7688 while ( invElemIt->more() ) {
7689 const SMDS_MeshElement* e = invElemIt->next();
7690 if ( e == curElem || foundElems.insert( e ).second ) {
7692 int iNode = 0, nbNodes = e->NbNodes();
7693 //const SMDS_MeshNode* nodes[nbNodes+1];
7694 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7696 if(e->IsQuadratic()) {
7697 const SMDS_QuadraticFaceOfNodes* F =
7698 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7699 // use special nodes iterator
7700 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7701 while( anIter->more() ) {
7702 nodes[ iNode++ ] = anIter->next();
7706 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7707 while ( nIt->more() )
7708 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7710 nodes[ iNode ] = nodes[ 0 ];
7712 for ( iNode = 0; iNode < nbNodes; iNode++ )
7713 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7714 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7715 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7717 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7718 curElemList.push_back( e );
7722 // analyse the found
7724 int nbNewBorders = curElemList.size();
7725 if ( nbNewBorders == 0 ) {
7726 // no free border furthermore
7727 return !needTheLast;
7729 else if ( nbNewBorders == 1 ) {
7730 // one more element found
7732 nStart = nStartList.front();
7733 curElem = curElemList.front();
7734 theFaces.push_back( curElem );
7735 theNodes.push_back( nStart );
7738 // several continuations found
7739 list< const SMDS_MeshElement* >::iterator curElemIt;
7740 list< const SMDS_MeshNode* >::iterator nStartIt;
7741 // check if one of them reached the last node
7742 if ( needTheLast ) {
7743 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7744 curElemIt!= curElemList.end();
7745 curElemIt++, nStartIt++ )
7746 if ( *nStartIt == theLastNode ) {
7747 theFaces.push_back( *curElemIt );
7748 theNodes.push_back( *nStartIt );
7752 // find the best free border by the continuations
7753 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7754 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7755 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7756 curElemIt!= curElemList.end();
7757 curElemIt++, nStartIt++ )
7759 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7760 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7761 // find one more free border
7762 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7766 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7767 // choice: clear a worse one
7768 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7769 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7770 contNodes[ iWorse ].clear();
7771 contFaces[ iWorse ].clear();
7774 if ( contNodes[0].empty() && contNodes[1].empty() )
7777 // append the best free border
7778 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7779 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7780 theNodes.pop_back(); // remove nIgnore
7781 theNodes.pop_back(); // remove nStart
7782 theFaces.pop_back(); // remove curElem
7783 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7784 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7785 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7786 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7789 } // several continuations found
7790 } // while ( nStart != theLastNode )
7795 //=======================================================================
7796 //function : CheckFreeBorderNodes
7797 //purpose : Return true if the tree nodes are on a free border
7798 //=======================================================================
7800 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7801 const SMDS_MeshNode* theNode2,
7802 const SMDS_MeshNode* theNode3)
7804 list< const SMDS_MeshNode* > nodes;
7805 list< const SMDS_MeshElement* > faces;
7806 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7809 //=======================================================================
7810 //function : SewFreeBorder
7812 //=======================================================================
7814 SMESH_MeshEditor::Sew_Error
7815 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7816 const SMDS_MeshNode* theBordSecondNode,
7817 const SMDS_MeshNode* theBordLastNode,
7818 const SMDS_MeshNode* theSideFirstNode,
7819 const SMDS_MeshNode* theSideSecondNode,
7820 const SMDS_MeshNode* theSideThirdNode,
7821 const bool theSideIsFreeBorder,
7822 const bool toCreatePolygons,
7823 const bool toCreatePolyedrs)
7825 myLastCreatedElems.Clear();
7826 myLastCreatedNodes.Clear();
7828 MESSAGE("::SewFreeBorder()");
7829 Sew_Error aResult = SEW_OK;
7831 // ====================================
7832 // find side nodes and elements
7833 // ====================================
7835 list< const SMDS_MeshNode* > nSide[ 2 ];
7836 list< const SMDS_MeshElement* > eSide[ 2 ];
7837 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7838 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7842 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7843 nSide[0], eSide[0])) {
7844 MESSAGE(" Free Border 1 not found " );
7845 aResult = SEW_BORDER1_NOT_FOUND;
7847 if (theSideIsFreeBorder) {
7850 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7851 nSide[1], eSide[1])) {
7852 MESSAGE(" Free Border 2 not found " );
7853 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7856 if ( aResult != SEW_OK )
7859 if (!theSideIsFreeBorder) {
7863 // -------------------------------------------------------------------------
7865 // 1. If nodes to merge are not coincident, move nodes of the free border
7866 // from the coord sys defined by the direction from the first to last
7867 // nodes of the border to the correspondent sys of the side 2
7868 // 2. On the side 2, find the links most co-directed with the correspondent
7869 // links of the free border
7870 // -------------------------------------------------------------------------
7872 // 1. Since sewing may brake if there are volumes to split on the side 2,
7873 // we wont move nodes but just compute new coordinates for them
7874 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7875 TNodeXYZMap nBordXYZ;
7876 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7877 list< const SMDS_MeshNode* >::iterator nBordIt;
7879 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7880 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7881 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7882 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7883 double tol2 = 1.e-8;
7884 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7885 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7886 // Need node movement.
7888 // find X and Z axes to create trsf
7889 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7891 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7893 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7896 gp_Ax3 toBordAx( Pb1, Zb, X );
7897 gp_Ax3 fromSideAx( Ps1, Zs, X );
7898 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7900 gp_Trsf toBordSys, fromSide2Sys;
7901 toBordSys.SetTransformation( toBordAx );
7902 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7903 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7906 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7907 const SMDS_MeshNode* n = *nBordIt;
7908 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7909 toBordSys.Transforms( xyz );
7910 fromSide2Sys.Transforms( xyz );
7911 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7915 // just insert nodes XYZ in the nBordXYZ map
7916 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7917 const SMDS_MeshNode* n = *nBordIt;
7918 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7922 // 2. On the side 2, find the links most co-directed with the correspondent
7923 // links of the free border
7925 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7926 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7927 sideNodes.push_back( theSideFirstNode );
7929 bool hasVolumes = false;
7930 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7931 set<long> foundSideLinkIDs, checkedLinkIDs;
7932 SMDS_VolumeTool volume;
7933 //const SMDS_MeshNode* faceNodes[ 4 ];
7935 const SMDS_MeshNode* sideNode;
7936 const SMDS_MeshElement* sideElem;
7937 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7938 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7939 nBordIt = bordNodes.begin();
7941 // border node position and border link direction to compare with
7942 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7943 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7944 // choose next side node by link direction or by closeness to
7945 // the current border node:
7946 bool searchByDir = ( *nBordIt != theBordLastNode );
7948 // find the next node on the Side 2
7950 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7952 checkedLinkIDs.clear();
7953 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7955 // loop on inverse elements of current node (prevSideNode) on the Side 2
7956 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7957 while ( invElemIt->more() )
7959 const SMDS_MeshElement* elem = invElemIt->next();
7960 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7961 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7962 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7963 bool isVolume = volume.Set( elem );
7964 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7965 if ( isVolume ) // --volume
7967 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7968 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7969 if(elem->IsQuadratic()) {
7970 const SMDS_QuadraticFaceOfNodes* F =
7971 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7972 // use special nodes iterator
7973 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7974 while( anIter->more() ) {
7975 nodes[ iNode ] = anIter->next();
7976 if ( nodes[ iNode++ ] == prevSideNode )
7977 iPrevNode = iNode - 1;
7981 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7982 while ( nIt->more() ) {
7983 nodes[ iNode ] = cast2Node( nIt->next() );
7984 if ( nodes[ iNode++ ] == prevSideNode )
7985 iPrevNode = iNode - 1;
7988 // there are 2 links to check
7993 // loop on links, to be precise, on the second node of links
7994 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7995 const SMDS_MeshNode* n = nodes[ iNode ];
7997 if ( !volume.IsLinked( n, prevSideNode ))
8001 if ( iNode ) // a node before prevSideNode
8002 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8003 else // a node after prevSideNode
8004 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8006 // check if this link was already used
8007 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8008 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8009 if (!isJustChecked &&
8010 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8012 // test a link geometrically
8013 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8014 bool linkIsBetter = false;
8015 double dot = 0.0, dist = 0.0;
8016 if ( searchByDir ) { // choose most co-directed link
8017 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8018 linkIsBetter = ( dot > maxDot );
8020 else { // choose link with the node closest to bordPos
8021 dist = ( nextXYZ - bordPos ).SquareModulus();
8022 linkIsBetter = ( dist < minDist );
8024 if ( linkIsBetter ) {
8033 } // loop on inverse elements of prevSideNode
8036 MESSAGE(" Cant find path by links of the Side 2 ");
8037 return SEW_BAD_SIDE_NODES;
8039 sideNodes.push_back( sideNode );
8040 sideElems.push_back( sideElem );
8041 foundSideLinkIDs.insert ( linkID );
8042 prevSideNode = sideNode;
8044 if ( *nBordIt == theBordLastNode )
8045 searchByDir = false;
8047 // find the next border link to compare with
8048 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8049 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8050 // move to next border node if sideNode is before forward border node (bordPos)
8051 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8052 prevBordNode = *nBordIt;
8054 bordPos = nBordXYZ[ *nBordIt ];
8055 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8056 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8060 while ( sideNode != theSideSecondNode );
8062 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8063 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8064 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8066 } // end nodes search on the side 2
8068 // ============================
8069 // sew the border to the side 2
8070 // ============================
8072 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8073 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8075 TListOfListOfNodes nodeGroupsToMerge;
8076 if ( nbNodes[0] == nbNodes[1] ||
8077 ( theSideIsFreeBorder && !theSideThirdNode)) {
8079 // all nodes are to be merged
8081 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8082 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8083 nIt[0]++, nIt[1]++ )
8085 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8086 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8087 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8092 // insert new nodes into the border and the side to get equal nb of segments
8094 // get normalized parameters of nodes on the borders
8095 //double param[ 2 ][ maxNbNodes ];
8097 param[0] = new double [ maxNbNodes ];
8098 param[1] = new double [ maxNbNodes ];
8100 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8101 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8102 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8103 const SMDS_MeshNode* nPrev = *nIt;
8104 double bordLength = 0;
8105 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8106 const SMDS_MeshNode* nCur = *nIt;
8107 gp_XYZ segment (nCur->X() - nPrev->X(),
8108 nCur->Y() - nPrev->Y(),
8109 nCur->Z() - nPrev->Z());
8110 double segmentLen = segment.Modulus();
8111 bordLength += segmentLen;
8112 param[ iBord ][ iNode ] = bordLength;
8115 // normalize within [0,1]
8116 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8117 param[ iBord ][ iNode ] /= bordLength;
8121 // loop on border segments
8122 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8123 int i[ 2 ] = { 0, 0 };
8124 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8125 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8127 TElemOfNodeListMap insertMap;
8128 TElemOfNodeListMap::iterator insertMapIt;
8130 // key: elem to insert nodes into
8131 // value: 2 nodes to insert between + nodes to be inserted
8133 bool next[ 2 ] = { false, false };
8135 // find min adjacent segment length after sewing
8136 double nextParam = 10., prevParam = 0;
8137 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8138 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8139 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8140 if ( i[ iBord ] > 0 )
8141 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8143 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8144 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8145 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8147 // choose to insert or to merge nodes
8148 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8149 if ( Abs( du ) <= minSegLen * 0.2 ) {
8152 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8153 const SMDS_MeshNode* n0 = *nIt[0];
8154 const SMDS_MeshNode* n1 = *nIt[1];
8155 nodeGroupsToMerge.back().push_back( n1 );
8156 nodeGroupsToMerge.back().push_back( n0 );
8157 // position of node of the border changes due to merge
8158 param[ 0 ][ i[0] ] += du;
8159 // move n1 for the sake of elem shape evaluation during insertion.
8160 // n1 will be removed by MergeNodes() anyway
8161 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8162 next[0] = next[1] = true;
8167 int intoBord = ( du < 0 ) ? 0 : 1;
8168 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8169 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8170 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8171 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8172 if ( intoBord == 1 ) {
8173 // move node of the border to be on a link of elem of the side
8174 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8175 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8176 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8177 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8178 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8180 insertMapIt = insertMap.find( elem );
8181 bool notFound = ( insertMapIt == insertMap.end() );
8182 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8184 // insert into another link of the same element:
8185 // 1. perform insertion into the other link of the elem
8186 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8187 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8188 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8189 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8190 // 2. perform insertion into the link of adjacent faces
8192 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8194 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8198 if (toCreatePolyedrs) {
8199 // perform insertion into the links of adjacent volumes
8200 UpdateVolumes(n12, n22, nodeList);
8202 // 3. find an element appeared on n1 and n2 after the insertion
8203 insertMap.erase( elem );
8204 elem = findAdjacentFace( n1, n2, 0 );
8206 if ( notFound || otherLink ) {
8207 // add element and nodes of the side into the insertMap
8208 insertMapIt = insertMap.insert
8209 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8210 (*insertMapIt).second.push_back( n1 );
8211 (*insertMapIt).second.push_back( n2 );
8213 // add node to be inserted into elem
8214 (*insertMapIt).second.push_back( nIns );
8215 next[ 1 - intoBord ] = true;
8218 // go to the next segment
8219 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8220 if ( next[ iBord ] ) {
8221 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8223 nPrev[ iBord ] = *nIt[ iBord ];
8224 nIt[ iBord ]++; i[ iBord ]++;
8228 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8230 // perform insertion of nodes into elements
8232 for (insertMapIt = insertMap.begin();
8233 insertMapIt != insertMap.end();
8236 const SMDS_MeshElement* elem = (*insertMapIt).first;
8237 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8238 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8239 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8241 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8243 if ( !theSideIsFreeBorder ) {
8244 // look for and insert nodes into the faces adjacent to elem
8246 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8248 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8253 if (toCreatePolyedrs) {
8254 // perform insertion into the links of adjacent volumes
8255 UpdateVolumes(n1, n2, nodeList);
8261 } // end: insert new nodes
8263 MergeNodes ( nodeGroupsToMerge );
8268 //=======================================================================
8269 //function : InsertNodesIntoLink
8270 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8271 // and theBetweenNode2 and split theElement
8272 //=======================================================================
8274 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8275 const SMDS_MeshNode* theBetweenNode1,
8276 const SMDS_MeshNode* theBetweenNode2,
8277 list<const SMDS_MeshNode*>& theNodesToInsert,
8278 const bool toCreatePoly)
8280 if ( theFace->GetType() != SMDSAbs_Face ) return;
8282 // find indices of 2 link nodes and of the rest nodes
8283 int iNode = 0, il1, il2, i3, i4;
8284 il1 = il2 = i3 = i4 = -1;
8285 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8286 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8288 if(theFace->IsQuadratic()) {
8289 const SMDS_QuadraticFaceOfNodes* F =
8290 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8291 // use special nodes iterator
8292 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8293 while( anIter->more() ) {
8294 const SMDS_MeshNode* n = anIter->next();
8295 if ( n == theBetweenNode1 )
8297 else if ( n == theBetweenNode2 )
8303 nodes[ iNode++ ] = n;
8307 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8308 while ( nodeIt->more() ) {
8309 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8310 if ( n == theBetweenNode1 )
8312 else if ( n == theBetweenNode2 )
8318 nodes[ iNode++ ] = n;
8321 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8324 // arrange link nodes to go one after another regarding the face orientation
8325 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8326 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8331 aNodesToInsert.reverse();
8333 // check that not link nodes of a quadrangles are in good order
8334 int nbFaceNodes = theFace->NbNodes();
8335 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8341 if (toCreatePoly || theFace->IsPoly()) {
8344 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8346 // add nodes of face up to first node of link
8349 if(theFace->IsQuadratic()) {
8350 const SMDS_QuadraticFaceOfNodes* F =
8351 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8352 // use special nodes iterator
8353 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8354 while( anIter->more() && !isFLN ) {
8355 const SMDS_MeshNode* n = anIter->next();
8356 poly_nodes[iNode++] = n;
8357 if (n == nodes[il1]) {
8361 // add nodes to insert
8362 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8363 for (; nIt != aNodesToInsert.end(); nIt++) {
8364 poly_nodes[iNode++] = *nIt;
8366 // add nodes of face starting from last node of link
8367 while ( anIter->more() ) {
8368 poly_nodes[iNode++] = anIter->next();
8372 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8373 while ( nodeIt->more() && !isFLN ) {
8374 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8375 poly_nodes[iNode++] = n;
8376 if (n == nodes[il1]) {
8380 // add nodes to insert
8381 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8382 for (; nIt != aNodesToInsert.end(); nIt++) {
8383 poly_nodes[iNode++] = *nIt;
8385 // add nodes of face starting from last node of link
8386 while ( nodeIt->more() ) {
8387 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8388 poly_nodes[iNode++] = n;
8392 // edit or replace the face
8393 SMESHDS_Mesh *aMesh = GetMeshDS();
8395 if (theFace->IsPoly()) {
8396 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8399 int aShapeId = FindShape( theFace );
8401 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8402 myLastCreatedElems.Append(newElem);
8403 if ( aShapeId && newElem )
8404 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8406 aMesh->RemoveElement(theFace);
8411 if( !theFace->IsQuadratic() ) {
8413 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8414 int nbLinkNodes = 2 + aNodesToInsert.size();
8415 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8416 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8417 linkNodes[ 0 ] = nodes[ il1 ];
8418 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8419 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8420 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8421 linkNodes[ iNode++ ] = *nIt;
8423 // decide how to split a quadrangle: compare possible variants
8424 // and choose which of splits to be a quadrangle
8425 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8426 if ( nbFaceNodes == 3 ) {
8427 iBestQuad = nbSplits;
8430 else if ( nbFaceNodes == 4 ) {
8431 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8432 double aBestRate = DBL_MAX;
8433 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8435 double aBadRate = 0;
8436 // evaluate elements quality
8437 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8438 if ( iSplit == iQuad ) {
8439 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8443 aBadRate += getBadRate( &quad, aCrit );
8446 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8448 nodes[ iSplit < iQuad ? i4 : i3 ]);
8449 aBadRate += getBadRate( &tria, aCrit );
8453 if ( aBadRate < aBestRate ) {
8455 aBestRate = aBadRate;
8460 // create new elements
8461 SMESHDS_Mesh *aMesh = GetMeshDS();
8462 int aShapeId = FindShape( theFace );
8465 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8466 SMDS_MeshElement* newElem = 0;
8467 if ( iSplit == iBestQuad )
8468 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8473 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8475 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8476 myLastCreatedElems.Append(newElem);
8477 if ( aShapeId && newElem )
8478 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8481 // change nodes of theFace
8482 const SMDS_MeshNode* newNodes[ 4 ];
8483 newNodes[ 0 ] = linkNodes[ i1 ];
8484 newNodes[ 1 ] = linkNodes[ i2 ];
8485 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8486 newNodes[ 3 ] = nodes[ i4 ];
8487 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8488 } // end if(!theFace->IsQuadratic())
8489 else { // theFace is quadratic
8490 // we have to split theFace on simple triangles and one simple quadrangle
8492 int nbshift = tmp*2;
8493 // shift nodes in nodes[] by nbshift
8495 for(i=0; i<nbshift; i++) {
8496 const SMDS_MeshNode* n = nodes[0];
8497 for(j=0; j<nbFaceNodes-1; j++) {
8498 nodes[j] = nodes[j+1];
8500 nodes[nbFaceNodes-1] = n;
8502 il1 = il1 - nbshift;
8503 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8504 // n0 n1 n2 n0 n1 n2
8505 // +-----+-----+ +-----+-----+
8514 // create new elements
8515 SMESHDS_Mesh *aMesh = GetMeshDS();
8516 int aShapeId = FindShape( theFace );
8519 if(nbFaceNodes==6) { // quadratic triangle
8520 SMDS_MeshElement* newElem =
8521 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8522 myLastCreatedElems.Append(newElem);
8523 if ( aShapeId && newElem )
8524 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8525 if(theFace->IsMediumNode(nodes[il1])) {
8526 // create quadrangle
8527 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8528 myLastCreatedElems.Append(newElem);
8529 if ( aShapeId && newElem )
8530 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8536 // create quadrangle
8537 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8538 myLastCreatedElems.Append(newElem);
8539 if ( aShapeId && newElem )
8540 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8546 else { // nbFaceNodes==8 - quadratic quadrangle
8547 SMDS_MeshElement* newElem =
8548 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8549 myLastCreatedElems.Append(newElem);
8550 if ( aShapeId && newElem )
8551 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8552 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8553 myLastCreatedElems.Append(newElem);
8554 if ( aShapeId && newElem )
8555 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8556 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8557 myLastCreatedElems.Append(newElem);
8558 if ( aShapeId && newElem )
8559 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8560 if(theFace->IsMediumNode(nodes[il1])) {
8561 // create quadrangle
8562 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8563 myLastCreatedElems.Append(newElem);
8564 if ( aShapeId && newElem )
8565 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8571 // create quadrangle
8572 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8573 myLastCreatedElems.Append(newElem);
8574 if ( aShapeId && newElem )
8575 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8581 // create needed triangles using n1,n2,n3 and inserted nodes
8582 int nbn = 2 + aNodesToInsert.size();
8583 //const SMDS_MeshNode* aNodes[nbn];
8584 vector<const SMDS_MeshNode*> aNodes(nbn);
8585 aNodes[0] = nodes[n1];
8586 aNodes[nbn-1] = nodes[n2];
8587 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8588 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8589 aNodes[iNode++] = *nIt;
8591 for(i=1; i<nbn; i++) {
8592 SMDS_MeshElement* newElem =
8593 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8594 myLastCreatedElems.Append(newElem);
8595 if ( aShapeId && newElem )
8596 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8598 // remove old quadratic face
8599 aMesh->RemoveElement(theFace);
8603 //=======================================================================
8604 //function : UpdateVolumes
8606 //=======================================================================
8607 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8608 const SMDS_MeshNode* theBetweenNode2,
8609 list<const SMDS_MeshNode*>& theNodesToInsert)
8611 myLastCreatedElems.Clear();
8612 myLastCreatedNodes.Clear();
8614 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8615 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8616 const SMDS_MeshElement* elem = invElemIt->next();
8618 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8619 SMDS_VolumeTool aVolume (elem);
8620 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8623 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8624 int iface, nbFaces = aVolume.NbFaces();
8625 vector<const SMDS_MeshNode *> poly_nodes;
8626 vector<int> quantities (nbFaces);
8628 for (iface = 0; iface < nbFaces; iface++) {
8629 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8630 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8631 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8633 for (int inode = 0; inode < nbFaceNodes; inode++) {
8634 poly_nodes.push_back(faceNodes[inode]);
8636 if (nbInserted == 0) {
8637 if (faceNodes[inode] == theBetweenNode1) {
8638 if (faceNodes[inode + 1] == theBetweenNode2) {
8639 nbInserted = theNodesToInsert.size();
8641 // add nodes to insert
8642 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8643 for (; nIt != theNodesToInsert.end(); nIt++) {
8644 poly_nodes.push_back(*nIt);
8648 else if (faceNodes[inode] == theBetweenNode2) {
8649 if (faceNodes[inode + 1] == theBetweenNode1) {
8650 nbInserted = theNodesToInsert.size();
8652 // add nodes to insert in reversed order
8653 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8655 for (; nIt != theNodesToInsert.begin(); nIt--) {
8656 poly_nodes.push_back(*nIt);
8658 poly_nodes.push_back(*nIt);
8665 quantities[iface] = nbFaceNodes + nbInserted;
8668 // Replace or update the volume
8669 SMESHDS_Mesh *aMesh = GetMeshDS();
8671 if (elem->IsPoly()) {
8672 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8676 int aShapeId = FindShape( elem );
8678 SMDS_MeshElement* newElem =
8679 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8680 myLastCreatedElems.Append(newElem);
8681 if (aShapeId && newElem)
8682 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8684 aMesh->RemoveElement(elem);
8689 //=======================================================================
8691 * \brief Convert elements contained in a submesh to quadratic
8692 * \retval int - nb of checked elements
8694 //=======================================================================
8696 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8697 SMESH_MesherHelper& theHelper,
8698 const bool theForce3d)
8701 if( !theSm ) return nbElem;
8703 vector<int> nbNodeInFaces;
8704 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8705 while(ElemItr->more())
8708 const SMDS_MeshElement* elem = ElemItr->next();
8709 if( !elem || elem->IsQuadratic() ) continue;
8711 int id = elem->GetID();
8712 int nbNodes = elem->NbNodes();
8713 SMDSAbs_ElementType aType = elem->GetType();
8715 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
8716 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
8717 nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >( elem )->GetQuanities();
8719 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
8721 const SMDS_MeshElement* NewElem = 0;
8727 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
8735 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8738 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8741 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
8746 case SMDSAbs_Volume :
8751 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8754 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
8757 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
8760 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8761 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8764 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8771 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8773 theSm->AddElement( NewElem );
8778 //=======================================================================
8779 //function : ConvertToQuadratic
8781 //=======================================================================
8782 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8784 SMESHDS_Mesh* meshDS = GetMeshDS();
8786 SMESH_MesherHelper aHelper(*myMesh);
8787 aHelper.SetIsQuadratic( true );
8789 int nbCheckedElems = 0;
8790 if ( myMesh->HasShapeToMesh() )
8792 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8794 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8795 while ( smIt->more() ) {
8796 SMESH_subMesh* sm = smIt->next();
8797 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8798 aHelper.SetSubShape( sm->GetSubShape() );
8799 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8804 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8805 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8807 SMESHDS_SubMesh *smDS = 0;
8808 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8809 while(aEdgeItr->more())
8811 const SMDS_MeshEdge* edge = aEdgeItr->next();
8812 if(edge && !edge->IsQuadratic())
8814 int id = edge->GetID();
8815 const SMDS_MeshNode* n1 = edge->GetNode(0);
8816 const SMDS_MeshNode* n2 = edge->GetNode(1);
8818 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
8820 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8821 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8824 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8825 while(aFaceItr->more())
8827 const SMDS_MeshFace* face = aFaceItr->next();
8828 if(!face || face->IsQuadratic() ) continue;
8830 int id = face->GetID();
8831 int nbNodes = face->NbNodes();
8832 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
8834 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
8836 SMDS_MeshFace * NewFace = 0;
8840 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
8843 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
8846 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
8848 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8850 vector<int> nbNodeInFaces;
8851 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8852 while(aVolumeItr->more())
8854 const SMDS_MeshVolume* volume = aVolumeItr->next();
8855 if(!volume || volume->IsQuadratic() ) continue;
8857 int id = volume->GetID();
8858 int nbNodes = volume->NbNodes();
8859 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
8860 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
8861 nbNodeInFaces = static_cast<const SMDS_PolyhedralVolumeOfNodes* >(volume)->GetQuanities();
8863 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
8865 SMDS_MeshVolume * NewVolume = 0;
8869 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8870 nodes[3], id, theForce3d );
8873 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8874 nodes[3], nodes[4], id, theForce3d);
8877 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
8878 nodes[3], nodes[4], nodes[5], id, theForce3d);
8881 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
8882 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
8885 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
8887 ReplaceElemInGroups(volume, NewVolume, meshDS);
8891 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
8892 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
8893 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
8894 aHelper.FixQuadraticElements();
8898 //=======================================================================
8900 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8901 * \retval int - nb of checked elements
8903 //=======================================================================
8905 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8906 SMDS_ElemIteratorPtr theItr,
8907 const int theShapeID)
8910 SMESHDS_Mesh* meshDS = GetMeshDS();
8911 const bool notFromGroups = false;
8913 while( theItr->more() )
8915 const SMDS_MeshElement* elem = theItr->next();
8917 if( elem && elem->IsQuadratic())
8919 int id = elem->GetID();
8920 int nbNodes = elem->NbNodes();
8921 vector<const SMDS_MeshNode *> nodes, mediumNodes;
8922 nodes.reserve( nbNodes );
8923 mediumNodes.reserve( nbNodes );
8925 for(int i = 0; i < nbNodes; i++)
8927 const SMDS_MeshNode* n = elem->GetNode(i);
8929 if( elem->IsMediumNode( n ) )
8930 mediumNodes.push_back( n );
8932 nodes.push_back( n );
8934 if( nodes.empty() ) continue;
8935 SMDSAbs_ElementType aType = elem->GetType();
8937 //remove old quadratic element
8938 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8940 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
8941 ReplaceElemInGroups(elem, NewElem, meshDS);
8942 if( theSm && NewElem )
8943 theSm->AddElement( NewElem );
8945 // remove medium nodes
8946 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8947 for ( ; nIt != mediumNodes.end(); ++nIt ) {
8948 const SMDS_MeshNode* n = *nIt;
8949 if ( n->NbInverseElements() == 0 ) {
8950 if ( n->GetPosition()->GetShapeId() != theShapeID )
8951 meshDS->RemoveFreeNode( n, meshDS->MeshElements
8952 ( n->GetPosition()->GetShapeId() ));
8954 meshDS->RemoveFreeNode( n, theSm );
8962 //=======================================================================
8963 //function : ConvertFromQuadratic
8965 //=======================================================================
8966 bool SMESH_MeshEditor::ConvertFromQuadratic()
8968 int nbCheckedElems = 0;
8969 if ( myMesh->HasShapeToMesh() )
8971 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8973 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8974 while ( smIt->more() ) {
8975 SMESH_subMesh* sm = smIt->next();
8976 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8977 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8983 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8984 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8986 SMESHDS_SubMesh *aSM = 0;
8987 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8993 //=======================================================================
8994 //function : SewSideElements
8996 //=======================================================================
8998 SMESH_MeshEditor::Sew_Error
8999 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9000 TIDSortedElemSet& theSide2,
9001 const SMDS_MeshNode* theFirstNode1,
9002 const SMDS_MeshNode* theFirstNode2,
9003 const SMDS_MeshNode* theSecondNode1,
9004 const SMDS_MeshNode* theSecondNode2)
9006 myLastCreatedElems.Clear();
9007 myLastCreatedNodes.Clear();
9009 MESSAGE ("::::SewSideElements()");
9010 if ( theSide1.size() != theSide2.size() )
9011 return SEW_DIFF_NB_OF_ELEMENTS;
9013 Sew_Error aResult = SEW_OK;
9015 // 1. Build set of faces representing each side
9016 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9017 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9019 // =======================================================================
9020 // 1. Build set of faces representing each side:
9021 // =======================================================================
9022 // a. build set of nodes belonging to faces
9023 // b. complete set of faces: find missing fices whose nodes are in set of nodes
9024 // c. create temporary faces representing side of volumes if correspondent
9025 // face does not exist
9027 SMESHDS_Mesh* aMesh = GetMeshDS();
9028 SMDS_Mesh aTmpFacesMesh;
9029 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9030 set<const SMDS_MeshElement*> volSet1, volSet2;
9031 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9032 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9033 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9034 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9035 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9036 int iSide, iFace, iNode;
9038 for ( iSide = 0; iSide < 2; iSide++ ) {
9039 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9040 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9041 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9042 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9043 set<const SMDS_MeshElement*>::iterator vIt;
9044 TIDSortedElemSet::iterator eIt;
9045 set<const SMDS_MeshNode*>::iterator nIt;
9047 // check that given nodes belong to given elements
9048 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9049 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9050 int firstIndex = -1, secondIndex = -1;
9051 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9052 const SMDS_MeshElement* elem = *eIt;
9053 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9054 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9055 if ( firstIndex > -1 && secondIndex > -1 ) break;
9057 if ( firstIndex < 0 || secondIndex < 0 ) {
9058 // we can simply return until temporary faces created
9059 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9062 // -----------------------------------------------------------
9063 // 1a. Collect nodes of existing faces
9064 // and build set of face nodes in order to detect missing
9065 // faces corresponing to sides of volumes
9066 // -----------------------------------------------------------
9068 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9070 // loop on the given element of a side
9071 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9072 //const SMDS_MeshElement* elem = *eIt;
9073 const SMDS_MeshElement* elem = *eIt;
9074 if ( elem->GetType() == SMDSAbs_Face ) {
9075 faceSet->insert( elem );
9076 set <const SMDS_MeshNode*> faceNodeSet;
9077 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9078 while ( nodeIt->more() ) {
9079 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9080 nodeSet->insert( n );
9081 faceNodeSet.insert( n );
9083 setOfFaceNodeSet.insert( faceNodeSet );
9085 else if ( elem->GetType() == SMDSAbs_Volume )
9086 volSet->insert( elem );
9088 // ------------------------------------------------------------------------------
9089 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
9090 // ------------------------------------------------------------------------------
9092 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9093 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9094 while ( fIt->more() ) { // loop on faces sharing a node
9095 const SMDS_MeshElement* f = fIt->next();
9096 if ( faceSet->find( f ) == faceSet->end() ) {
9097 // check if all nodes are in nodeSet and
9098 // complete setOfFaceNodeSet if they are
9099 set <const SMDS_MeshNode*> faceNodeSet;
9100 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9101 bool allInSet = true;
9102 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9103 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9104 if ( nodeSet->find( n ) == nodeSet->end() )
9107 faceNodeSet.insert( n );
9110 faceSet->insert( f );
9111 setOfFaceNodeSet.insert( faceNodeSet );
9117 // -------------------------------------------------------------------------
9118 // 1c. Create temporary faces representing sides of volumes if correspondent
9119 // face does not exist
9120 // -------------------------------------------------------------------------
9122 if ( !volSet->empty() ) {
9123 //int nodeSetSize = nodeSet->size();
9125 // loop on given volumes
9126 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9127 SMDS_VolumeTool vol (*vIt);
9128 // loop on volume faces: find free faces
9129 // --------------------------------------
9130 list<const SMDS_MeshElement* > freeFaceList;
9131 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9132 if ( !vol.IsFreeFace( iFace ))
9134 // check if there is already a face with same nodes in a face set
9135 const SMDS_MeshElement* aFreeFace = 0;
9136 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9137 int nbNodes = vol.NbFaceNodes( iFace );
9138 set <const SMDS_MeshNode*> faceNodeSet;
9139 vol.GetFaceNodes( iFace, faceNodeSet );
9140 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9142 // no such a face is given but it still can exist, check it
9143 if ( nbNodes == 3 ) {
9144 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9146 else if ( nbNodes == 4 ) {
9147 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9150 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9151 aFreeFace = aMesh->FindFace(poly_nodes);
9155 // create a temporary face
9156 if ( nbNodes == 3 ) {
9157 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9159 else if ( nbNodes == 4 ) {
9160 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9163 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9164 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9168 freeFaceList.push_back( aFreeFace );
9170 } // loop on faces of a volume
9172 // choose one of several free faces
9173 // --------------------------------------
9174 if ( freeFaceList.size() > 1 ) {
9175 // choose a face having max nb of nodes shared by other elems of a side
9176 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9177 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9178 while ( fIt != freeFaceList.end() ) { // loop on free faces
9179 int nbSharedNodes = 0;
9180 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9181 while ( nodeIt->more() ) { // loop on free face nodes
9182 const SMDS_MeshNode* n =
9183 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9184 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9185 while ( invElemIt->more() ) {
9186 const SMDS_MeshElement* e = invElemIt->next();
9187 if ( faceSet->find( e ) != faceSet->end() )
9189 if ( elemSet->find( e ) != elemSet->end() )
9193 if ( nbSharedNodes >= maxNbNodes ) {
9194 maxNbNodes = nbSharedNodes;
9198 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9200 if ( freeFaceList.size() > 1 )
9202 // could not choose one face, use another way
9203 // choose a face most close to the bary center of the opposite side
9204 gp_XYZ aBC( 0., 0., 0. );
9205 set <const SMDS_MeshNode*> addedNodes;
9206 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9207 eIt = elemSet2->begin();
9208 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9209 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9210 while ( nodeIt->more() ) { // loop on free face nodes
9211 const SMDS_MeshNode* n =
9212 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9213 if ( addedNodes.insert( n ).second )
9214 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9217 aBC /= addedNodes.size();
9218 double minDist = DBL_MAX;
9219 fIt = freeFaceList.begin();
9220 while ( fIt != freeFaceList.end() ) { // loop on free faces
9222 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9223 while ( nodeIt->more() ) { // loop on free face nodes
9224 const SMDS_MeshNode* n =
9225 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9226 gp_XYZ p( n->X(),n->Y(),n->Z() );
9227 dist += ( aBC - p ).SquareModulus();
9229 if ( dist < minDist ) {
9231 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9234 fIt = freeFaceList.erase( fIt++ );
9237 } // choose one of several free faces of a volume
9239 if ( freeFaceList.size() == 1 ) {
9240 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9241 faceSet->insert( aFreeFace );
9242 // complete a node set with nodes of a found free face
9243 // for ( iNode = 0; iNode < ; iNode++ )
9244 // nodeSet->insert( fNodes[ iNode ] );
9247 } // loop on volumes of a side
9249 // // complete a set of faces if new nodes in a nodeSet appeared
9250 // // ----------------------------------------------------------
9251 // if ( nodeSetSize != nodeSet->size() ) {
9252 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9253 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9254 // while ( fIt->more() ) { // loop on faces sharing a node
9255 // const SMDS_MeshElement* f = fIt->next();
9256 // if ( faceSet->find( f ) == faceSet->end() ) {
9257 // // check if all nodes are in nodeSet and
9258 // // complete setOfFaceNodeSet if they are
9259 // set <const SMDS_MeshNode*> faceNodeSet;
9260 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9261 // bool allInSet = true;
9262 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9263 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9264 // if ( nodeSet->find( n ) == nodeSet->end() )
9265 // allInSet = false;
9267 // faceNodeSet.insert( n );
9269 // if ( allInSet ) {
9270 // faceSet->insert( f );
9271 // setOfFaceNodeSet.insert( faceNodeSet );
9277 } // Create temporary faces, if there are volumes given
9280 if ( faceSet1.size() != faceSet2.size() ) {
9281 // delete temporary faces: they are in reverseElements of actual nodes
9282 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9283 while ( tmpFaceIt->more() )
9284 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9285 MESSAGE("Diff nb of faces");
9286 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9289 // ============================================================
9290 // 2. Find nodes to merge:
9291 // bind a node to remove to a node to put instead
9292 // ============================================================
9294 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9295 if ( theFirstNode1 != theFirstNode2 )
9296 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9297 if ( theSecondNode1 != theSecondNode2 )
9298 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9300 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9301 set< long > linkIdSet; // links to process
9302 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9304 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9305 list< NLink > linkList[2];
9306 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9307 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9308 // loop on links in linkList; find faces by links and append links
9309 // of the found faces to linkList
9310 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9311 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9312 NLink link[] = { *linkIt[0], *linkIt[1] };
9313 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9314 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9317 // by links, find faces in the face sets,
9318 // and find indices of link nodes in the found faces;
9319 // in a face set, there is only one or no face sharing a link
9320 // ---------------------------------------------------------------
9322 const SMDS_MeshElement* face[] = { 0, 0 };
9323 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9324 vector<const SMDS_MeshNode*> fnodes1(9);
9325 vector<const SMDS_MeshNode*> fnodes2(9);
9326 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9327 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9328 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9329 int iLinkNode[2][2];
9330 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9331 const SMDS_MeshNode* n1 = link[iSide].first;
9332 const SMDS_MeshNode* n2 = link[iSide].second;
9333 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9334 set< const SMDS_MeshElement* > fMap;
9335 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9336 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9337 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9338 while ( fIt->more() ) { // loop on faces sharing a node
9339 const SMDS_MeshElement* f = fIt->next();
9340 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9341 ! fMap.insert( f ).second ) // f encounters twice
9343 if ( face[ iSide ] ) {
9344 MESSAGE( "2 faces per link " );
9345 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9349 faceSet->erase( f );
9350 // get face nodes and find ones of a link
9355 fnodes1.resize(f->NbNodes()+1);
9356 notLinkNodes1.resize(f->NbNodes()-2);
9359 fnodes2.resize(f->NbNodes()+1);
9360 notLinkNodes2.resize(f->NbNodes()-2);
9363 if(!f->IsQuadratic()) {
9364 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9365 while ( nIt->more() ) {
9366 const SMDS_MeshNode* n =
9367 static_cast<const SMDS_MeshNode*>( nIt->next() );
9369 iLinkNode[ iSide ][ 0 ] = iNode;
9371 else if ( n == n2 ) {
9372 iLinkNode[ iSide ][ 1 ] = iNode;
9374 //else if ( notLinkNodes[ iSide ][ 0 ] )
9375 // notLinkNodes[ iSide ][ 1 ] = n;
9377 // notLinkNodes[ iSide ][ 0 ] = n;
9381 notLinkNodes1[nbl] = n;
9382 //notLinkNodes1.push_back(n);
9384 notLinkNodes2[nbl] = n;
9385 //notLinkNodes2.push_back(n);
9387 //faceNodes[ iSide ][ iNode++ ] = n;
9389 fnodes1[iNode++] = n;
9392 fnodes2[iNode++] = n;
9396 else { // f->IsQuadratic()
9397 const SMDS_QuadraticFaceOfNodes* F =
9398 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9399 // use special nodes iterator
9400 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9401 while ( anIter->more() ) {
9402 const SMDS_MeshNode* n =
9403 static_cast<const SMDS_MeshNode*>( anIter->next() );
9405 iLinkNode[ iSide ][ 0 ] = iNode;
9407 else if ( n == n2 ) {
9408 iLinkNode[ iSide ][ 1 ] = iNode;
9413 notLinkNodes1[nbl] = n;
9416 notLinkNodes2[nbl] = n;
9420 fnodes1[iNode++] = n;
9423 fnodes2[iNode++] = n;
9427 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9429 fnodes1[iNode] = fnodes1[0];
9432 fnodes2[iNode] = fnodes1[0];
9439 // check similarity of elements of the sides
9440 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9441 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9442 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9443 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9446 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9448 break; // do not return because it s necessary to remove tmp faces
9451 // set nodes to merge
9452 // -------------------
9454 if ( face[0] && face[1] ) {
9455 int nbNodes = face[0]->NbNodes();
9456 if ( nbNodes != face[1]->NbNodes() ) {
9457 MESSAGE("Diff nb of face nodes");
9458 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9459 break; // do not return because it s necessary to remove tmp faces
9461 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9462 if ( nbNodes == 3 ) {
9463 //nReplaceMap.insert( TNodeNodeMap::value_type
9464 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9465 nReplaceMap.insert( TNodeNodeMap::value_type
9466 ( notLinkNodes1[0], notLinkNodes2[0] ));
9469 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9470 // analyse link orientation in faces
9471 int i1 = iLinkNode[ iSide ][ 0 ];
9472 int i2 = iLinkNode[ iSide ][ 1 ];
9473 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9474 // if notLinkNodes are the first and the last ones, then
9475 // their order does not correspond to the link orientation
9476 if (( i1 == 1 && i2 == 2 ) ||
9477 ( i1 == 2 && i2 == 1 ))
9478 reverse[ iSide ] = !reverse[ iSide ];
9480 if ( reverse[0] == reverse[1] ) {
9481 //nReplaceMap.insert( TNodeNodeMap::value_type
9482 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9483 //nReplaceMap.insert( TNodeNodeMap::value_type
9484 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9485 for(int nn=0; nn<nbNodes-2; nn++) {
9486 nReplaceMap.insert( TNodeNodeMap::value_type
9487 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9491 //nReplaceMap.insert( TNodeNodeMap::value_type
9492 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9493 //nReplaceMap.insert( TNodeNodeMap::value_type
9494 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9495 for(int nn=0; nn<nbNodes-2; nn++) {
9496 nReplaceMap.insert( TNodeNodeMap::value_type
9497 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9502 // add other links of the faces to linkList
9503 // -----------------------------------------
9505 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9506 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9507 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9508 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9509 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9510 if ( !iter_isnew.second ) { // already in a set: no need to process
9511 linkIdSet.erase( iter_isnew.first );
9513 else // new in set == encountered for the first time: add
9515 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9516 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9517 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9518 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9519 linkList[0].push_back ( NLink( n1, n2 ));
9520 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9524 } // loop on link lists
9526 if ( aResult == SEW_OK &&
9527 ( linkIt[0] != linkList[0].end() ||
9528 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9529 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9530 " " << (faceSetPtr[1]->empty()));
9531 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9534 // ====================================================================
9535 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9536 // ====================================================================
9538 // delete temporary faces: they are in reverseElements of actual nodes
9539 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9540 while ( tmpFaceIt->more() )
9541 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9543 if ( aResult != SEW_OK)
9546 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9547 // loop on nodes replacement map
9548 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9549 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9550 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9551 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9552 nodeIDsToRemove.push_back( nToRemove->GetID() );
9553 // loop on elements sharing nToRemove
9554 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9555 while ( invElemIt->more() ) {
9556 const SMDS_MeshElement* e = invElemIt->next();
9557 // get a new suite of nodes: make replacement
9558 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9559 vector< const SMDS_MeshNode*> nodes( nbNodes );
9560 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9561 while ( nIt->more() ) {
9562 const SMDS_MeshNode* n =
9563 static_cast<const SMDS_MeshNode*>( nIt->next() );
9564 nnIt = nReplaceMap.find( n );
9565 if ( nnIt != nReplaceMap.end() ) {
9571 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9572 // elemIDsToRemove.push_back( e->GetID() );
9575 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9579 Remove( nodeIDsToRemove, true );
9584 //================================================================================
9586 * \brief Find corresponding nodes in two sets of faces
9587 * \param theSide1 - first face set
9588 * \param theSide2 - second first face
9589 * \param theFirstNode1 - a boundary node of set 1
9590 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9591 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9592 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9593 * \param nReplaceMap - output map of corresponding nodes
9594 * \retval bool - is a success or not
9596 //================================================================================
9599 //#define DEBUG_MATCHING_NODES
9602 SMESH_MeshEditor::Sew_Error
9603 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9604 set<const SMDS_MeshElement*>& theSide2,
9605 const SMDS_MeshNode* theFirstNode1,
9606 const SMDS_MeshNode* theFirstNode2,
9607 const SMDS_MeshNode* theSecondNode1,
9608 const SMDS_MeshNode* theSecondNode2,
9609 TNodeNodeMap & nReplaceMap)
9611 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9613 nReplaceMap.clear();
9614 if ( theFirstNode1 != theFirstNode2 )
9615 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9616 if ( theSecondNode1 != theSecondNode2 )
9617 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9619 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9620 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9622 list< NLink > linkList[2];
9623 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9624 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9626 // loop on links in linkList; find faces by links and append links
9627 // of the found faces to linkList
9628 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9629 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9630 NLink link[] = { *linkIt[0], *linkIt[1] };
9631 if ( linkSet.find( link[0] ) == linkSet.end() )
9634 // by links, find faces in the face sets,
9635 // and find indices of link nodes in the found faces;
9636 // in a face set, there is only one or no face sharing a link
9637 // ---------------------------------------------------------------
9639 const SMDS_MeshElement* face[] = { 0, 0 };
9640 list<const SMDS_MeshNode*> notLinkNodes[2];
9641 //bool reverse[] = { false, false }; // order of notLinkNodes
9643 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9645 const SMDS_MeshNode* n1 = link[iSide].first;
9646 const SMDS_MeshNode* n2 = link[iSide].second;
9647 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9648 set< const SMDS_MeshElement* > facesOfNode1;
9649 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9651 // during a loop of the first node, we find all faces around n1,
9652 // during a loop of the second node, we find one face sharing both n1 and n2
9653 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9654 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9655 while ( fIt->more() ) { // loop on faces sharing a node
9656 const SMDS_MeshElement* f = fIt->next();
9657 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9658 ! facesOfNode1.insert( f ).second ) // f encounters twice
9660 if ( face[ iSide ] ) {
9661 MESSAGE( "2 faces per link " );
9662 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9665 faceSet->erase( f );
9667 // get not link nodes
9668 int nbN = f->NbNodes();
9669 if ( f->IsQuadratic() )
9671 nbNodes[ iSide ] = nbN;
9672 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9673 int i1 = f->GetNodeIndex( n1 );
9674 int i2 = f->GetNodeIndex( n2 );
9675 int iEnd = nbN, iBeg = -1, iDelta = 1;
9676 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9678 std::swap( iEnd, iBeg ); iDelta = -1;
9683 if ( i == iEnd ) i = iBeg + iDelta;
9684 if ( i == i1 ) break;
9685 nodes.push_back ( f->GetNode( i ) );
9691 // check similarity of elements of the sides
9692 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9693 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9694 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9695 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9698 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9702 // set nodes to merge
9703 // -------------------
9705 if ( face[0] && face[1] ) {
9706 if ( nbNodes[0] != nbNodes[1] ) {
9707 MESSAGE("Diff nb of face nodes");
9708 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9710 #ifdef DEBUG_MATCHING_NODES
9711 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9712 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9713 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9715 int nbN = nbNodes[0];
9717 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9718 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9719 for ( int i = 0 ; i < nbN - 2; ++i ) {
9720 #ifdef DEBUG_MATCHING_NODES
9721 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9723 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9727 // add other links of the face 1 to linkList
9728 // -----------------------------------------
9730 const SMDS_MeshElement* f0 = face[0];
9731 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9732 for ( int i = 0; i < nbN; i++ )
9734 const SMDS_MeshNode* n2 = f0->GetNode( i );
9735 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9736 linkSet.insert( SMESH_TLink( n1, n2 ));
9737 if ( !iter_isnew.second ) { // already in a set: no need to process
9738 linkSet.erase( iter_isnew.first );
9740 else // new in set == encountered for the first time: add
9742 #ifdef DEBUG_MATCHING_NODES
9743 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9744 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9746 linkList[0].push_back ( NLink( n1, n2 ));
9747 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9752 } // loop on link lists
9757 //================================================================================
9759 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9760 \param theElems - the list of elements (edges or faces) to be replicated
9761 The nodes for duplication could be found from these elements
9762 \param theNodesNot - list of nodes to NOT replicate
9763 \param theAffectedElems - the list of elements (cells and edges) to which the
9764 replicated nodes should be associated to.
9765 \return TRUE if operation has been completed successfully, FALSE otherwise
9767 //================================================================================
9769 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9770 const TIDSortedElemSet& theNodesNot,
9771 const TIDSortedElemSet& theAffectedElems )
9773 myLastCreatedElems.Clear();
9774 myLastCreatedNodes.Clear();
9776 if ( theElems.size() == 0 )
9779 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9784 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9785 // duplicate elements and nodes
9786 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9787 // replce nodes by duplications
9788 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9792 //================================================================================
9794 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9795 \param theMeshDS - mesh instance
9796 \param theElems - the elements replicated or modified (nodes should be changed)
9797 \param theNodesNot - nodes to NOT replicate
9798 \param theNodeNodeMap - relation of old node to new created node
9799 \param theIsDoubleElem - flag os to replicate element or modify
9800 \return TRUE if operation has been completed successfully, FALSE otherwise
9802 //================================================================================
9804 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9805 const TIDSortedElemSet& theElems,
9806 const TIDSortedElemSet& theNodesNot,
9807 std::map< const SMDS_MeshNode*,
9808 const SMDS_MeshNode* >& theNodeNodeMap,
9809 const bool theIsDoubleElem )
9811 // iterate on through element and duplicate them (by nodes duplication)
9813 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9814 for ( ; elemItr != theElems.end(); ++elemItr )
9816 const SMDS_MeshElement* anElem = *elemItr;
9820 bool isDuplicate = false;
9821 // duplicate nodes to duplicate element
9822 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9823 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9825 while ( anIter->more() )
9828 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9829 SMDS_MeshNode* aNewNode = aCurrNode;
9830 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9831 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9832 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9835 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9836 theNodeNodeMap[ aCurrNode ] = aNewNode;
9837 myLastCreatedNodes.Append( aNewNode );
9839 isDuplicate |= (aCurrNode != aNewNode);
9840 newNodes[ ind++ ] = aNewNode;
9845 if ( theIsDoubleElem )
9846 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
9848 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9855 //================================================================================
9857 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9858 \param theNodes - identifiers of nodes to be doubled
9859 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9860 nodes. If list of element identifiers is empty then nodes are doubled but
9861 they not assigned to elements
9862 \return TRUE if operation has been completed successfully, FALSE otherwise
9864 //================================================================================
9866 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9867 const std::list< int >& theListOfModifiedElems )
9869 myLastCreatedElems.Clear();
9870 myLastCreatedNodes.Clear();
9872 if ( theListOfNodes.size() == 0 )
9875 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9879 // iterate through nodes and duplicate them
9881 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9883 std::list< int >::const_iterator aNodeIter;
9884 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9886 int aCurr = *aNodeIter;
9887 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9893 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9896 anOldNodeToNewNode[ aNode ] = aNewNode;
9897 myLastCreatedNodes.Append( aNewNode );
9901 // Create map of new nodes for modified elements
9903 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9905 std::list< int >::const_iterator anElemIter;
9906 for ( anElemIter = theListOfModifiedElems.begin();
9907 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9909 int aCurr = *anElemIter;
9910 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9914 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9916 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9918 while ( anIter->more() )
9920 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9921 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9923 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9924 aNodeArr[ ind++ ] = aNewNode;
9927 aNodeArr[ ind++ ] = aCurrNode;
9929 anElemToNodes[ anElem ] = aNodeArr;
9932 // Change nodes of elements
9934 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9935 anElemToNodesIter = anElemToNodes.begin();
9936 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9938 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9939 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9941 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9949 //================================================================================
9951 \brief Check if element located inside shape
9952 \return TRUE if IN or ON shape, FALSE otherwise
9954 //================================================================================
9956 template<class Classifier>
9957 bool isInside(const SMDS_MeshElement* theElem,
9958 Classifier& theClassifier,
9959 const double theTol)
9961 gp_XYZ centerXYZ (0, 0, 0);
9962 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9963 while (aNodeItr->more())
9964 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9966 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9967 theClassifier.Perform(aPnt, theTol);
9968 TopAbs_State aState = theClassifier.State();
9969 return (aState == TopAbs_IN || aState == TopAbs_ON );
9972 //================================================================================
9974 * \brief Classifier of the 3D point on the TopoDS_Face
9975 * with interaface suitable for isInside()
9977 //================================================================================
9979 struct _FaceClassifier
9981 Extrema_ExtPS _extremum;
9982 BRepAdaptor_Surface _surface;
9983 TopAbs_State _state;
9985 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9987 _extremum.Initialize( _surface,
9988 _surface.FirstUParameter(), _surface.LastUParameter(),
9989 _surface.FirstVParameter(), _surface.LastVParameter(),
9990 _surface.Tolerance(), _surface.Tolerance() );
9992 void Perform(const gp_Pnt& aPnt, double theTol)
9994 _state = TopAbs_OUT;
9995 _extremum.Perform(aPnt);
9996 if ( _extremum.IsDone() )
9997 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9998 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10000 TopAbs_State State() const
10007 //================================================================================
10009 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10010 \param theElems - group of of elements (edges or faces) to be replicated
10011 \param theNodesNot - group of nodes not to replicate
10012 \param theShape - shape to detect affected elements (element which geometric center
10013 located on or inside shape).
10014 The replicated nodes should be associated to affected elements.
10015 \return TRUE if operation has been completed successfully, FALSE otherwise
10017 //================================================================================
10019 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10020 const TIDSortedElemSet& theNodesNot,
10021 const TopoDS_Shape& theShape )
10023 if ( theShape.IsNull() )
10026 const double aTol = Precision::Confusion();
10027 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10028 auto_ptr<_FaceClassifier> aFaceClassifier;
10029 if ( theShape.ShapeType() == TopAbs_SOLID )
10031 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10032 bsc3d->PerformInfinitePoint(aTol);
10034 else if (theShape.ShapeType() == TopAbs_FACE )
10036 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10039 // iterates on indicated elements and get elements by back references from their nodes
10040 TIDSortedElemSet anAffected;
10041 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10042 for ( ; elemItr != theElems.end(); ++elemItr )
10044 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10048 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10049 while ( nodeItr->more() )
10051 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10052 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10054 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10055 while ( backElemItr->more() )
10057 const SMDS_MeshElement* curElem = backElemItr->next();
10058 if ( curElem && theElems.find(curElem) == theElems.end() &&
10060 isInside( curElem, *bsc3d, aTol ) :
10061 isInside( curElem, *aFaceClassifier, aTol )))
10062 anAffected.insert( curElem );
10066 return DoubleNodes( theElems, theNodesNot, anAffected );
10069 //================================================================================
10071 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10072 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10073 * \return TRUE if operation has been completed successfully, FALSE otherwise
10075 //================================================================================
10077 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10079 // iterates on volume elements and detect all free faces on them
10080 SMESHDS_Mesh* aMesh = GetMeshDS();
10083 //bool res = false;
10084 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10085 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10088 const SMDS_MeshVolume* volume = vIt->next();
10089 SMDS_VolumeTool vTool( volume );
10090 vTool.SetExternalNormal();
10091 const bool isPoly = volume->IsPoly();
10092 const bool isQuad = volume->IsQuadratic();
10093 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10095 if (!vTool.IsFreeFace(iface))
10098 vector<const SMDS_MeshNode *> nodes;
10099 int nbFaceNodes = vTool.NbFaceNodes(iface);
10100 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10102 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10103 nodes.push_back(faceNodes[inode]);
10105 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10106 nodes.push_back(faceNodes[inode]);
10108 // add new face based on volume nodes
10109 if (aMesh->FindFace( nodes ) ) {
10111 continue; // face already exsist
10113 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10117 return ( nbFree==(nbExisted+nbCreated) );
10122 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10124 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10126 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10129 //================================================================================
10131 * \brief Creates missing boundary elements
10132 * \param elements - elements whose boundary is to be checked
10133 * \param dimension - defines type of boundary elements to create
10134 * \param group - a group to store created boundary elements in
10135 * \param targetMesh - a mesh to store created boundary elements in
10136 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10137 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10138 * boundary elements will be copied into the targetMesh
10140 //================================================================================
10142 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10143 Bnd_Dimension dimension,
10144 SMESH_Group* group/*=0*/,
10145 SMESH_Mesh* targetMesh/*=0*/,
10146 bool toCopyElements/*=false*/,
10147 bool toCopyExistingBondary/*=false*/)
10149 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10150 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10151 // hope that all elements are of the same type, do not check them all
10152 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10153 throw SALOME_Exception(LOCALIZED("wrong element type"));
10156 toCopyElements = toCopyExistingBondary = false;
10158 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10159 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10161 SMDS_VolumeTool vTool;
10162 TIDSortedElemSet emptySet, avoidSet;
10165 typedef vector<const SMDS_MeshNode*> TConnectivity;
10167 SMDS_ElemIteratorPtr eIt;
10168 if (elements.empty())
10169 eIt = aMesh->elementsIterator(elemType);
10171 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10173 while (eIt->more())
10175 const SMDS_MeshElement* elem = eIt->next();
10176 const int iQuad = elem->IsQuadratic();
10178 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10179 vector<const SMDS_MeshElement*> presentBndElems;
10180 vector<TConnectivity> missingBndElems;
10181 TConnectivity nodes;
10182 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10184 vTool.SetExternalNormal();
10185 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10187 if (!vTool.IsFreeFace(iface))
10189 int nbFaceNodes = vTool.NbFaceNodes(iface);
10190 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10191 if ( missType == SMDSAbs_Edge ) // boundary edges
10193 nodes.resize( 2+iQuad );
10194 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10196 for ( int j = 0; j < nodes.size(); ++j )
10198 if ( const SMDS_MeshElement* edge =
10199 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10200 presentBndElems.push_back( edge );
10202 missingBndElems.push_back( nodes );
10205 else // boundary face
10208 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10209 nodes.push_back( nn[inode] );
10211 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10212 nodes.push_back( nn[inode] );
10214 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10215 presentBndElems.push_back( f );
10217 missingBndElems.push_back( nodes );
10221 else // elem is a face ------------------------------------------
10223 avoidSet.clear(), avoidSet.insert( elem );
10224 int nbNodes = elem->NbCornerNodes();
10225 nodes.resize( 2 /*+ iQuad*/);
10226 for ( int i = 0; i < nbNodes; i++ )
10228 nodes[0] = elem->GetNode(i);
10229 nodes[1] = elem->GetNode((i+1)%nbNodes);
10230 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10231 continue; // not free link
10234 //nodes[2] = elem->GetNode( i + nbNodes );
10235 if ( const SMDS_MeshElement* edge =
10236 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10237 presentBndElems.push_back( edge );
10239 missingBndElems.push_back( nodes );
10243 // 2. Add missing boundary elements
10244 if ( targetMesh != myMesh )
10245 // instead of making a map of nodes in this mesh and targetMesh,
10246 // we create nodes with same IDs. We can renumber them later, if needed
10247 for ( int i = 0; i < missingBndElems.size(); ++i )
10249 TConnectivity& srcNodes = missingBndElems[i];
10250 TConnectivity nodes( srcNodes.size() );
10251 for ( inode = 0; inode < nodes.size(); ++inode )
10252 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10253 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10256 for ( int i = 0; i < missingBndElems.size(); ++i )
10258 TConnectivity& nodes = missingBndElems[i];
10259 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10262 // 3. Copy present boundary elements
10263 if ( toCopyExistingBondary )
10264 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10266 const SMDS_MeshElement* e = presentBndElems[i];
10267 TConnectivity nodes( e->NbNodes() );
10268 for ( inode = 0; inode < nodes.size(); ++inode )
10269 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10270 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10271 // leave only missing elements in tgtEditor.myLastCreatedElems
10272 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10274 } // loop on given elements
10276 // 4. Fill group with missing boundary elements
10279 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10280 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10281 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10283 tgtEditor.myLastCreatedElems.Clear();
10285 // 5. Copy given elements
10286 if ( toCopyElements )
10288 if (elements.empty())
10289 eIt = aMesh->elementsIterator(elemType);
10291 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10292 while (eIt->more())
10294 const SMDS_MeshElement* elem = eIt->next();
10295 TConnectivity nodes( elem->NbNodes() );
10296 for ( inode = 0; inode < nodes.size(); ++inode )
10297 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10298 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10300 tgtEditor.myLastCreatedElems.Clear();