1 // Copyright (C) 2007-2008 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
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
27 #include "SMESH_MeshEditor.hxx"
29 #include "SMDS_FaceOfNodes.hxx"
30 #include "SMDS_VolumeTool.hxx"
31 #include "SMDS_EdgePosition.hxx"
32 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
33 #include "SMDS_FacePosition.hxx"
34 #include "SMDS_SpacePosition.hxx"
35 #include "SMDS_QuadraticFaceOfNodes.hxx"
36 #include "SMDS_MeshGroup.hxx"
38 #include "SMESHDS_Group.hxx"
39 #include "SMESHDS_Mesh.hxx"
41 #include "SMESH_subMesh.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_MesherHelper.hxx"
44 #include "SMESH_OctreeNode.hxx"
45 #include "SMESH_Group.hxx"
47 #include "utilities.h"
49 #include <BRepAdaptor_Surface.hxx>
50 #include <BRepClass3d_SolidClassifier.hxx>
51 #include <BRep_Tool.hxx>
53 #include <Extrema_GenExtPS.hxx>
54 #include <Extrema_POnSurf.hxx>
55 #include <Geom2d_Curve.hxx>
56 #include <GeomAdaptor_Surface.hxx>
57 #include <Geom_Curve.hxx>
58 #include <Geom_Surface.hxx>
59 #include <Precision.hxx>
60 #include <TColStd_ListOfInteger.hxx>
61 #include <TopAbs_State.hxx>
63 #include <TopExp_Explorer.hxx>
64 #include <TopTools_ListIteratorOfListOfShape.hxx>
65 #include <TopTools_ListOfShape.hxx>
66 #include <TopTools_SequenceOfShape.hxx>
68 #include <TopoDS_Face.hxx>
74 #include <gp_Trsf.hxx>
85 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
88 using namespace SMESH::Controls;
90 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
91 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
93 //=======================================================================
94 //function : SMESH_MeshEditor
96 //=======================================================================
98 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
99 :myMesh( theMesh ) // theMesh may be NULL
103 //=======================================================================
107 //=======================================================================
110 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
111 const SMDSAbs_ElementType type,
115 SMDS_MeshElement* e = 0;
116 int nbnode = node.size();
117 SMESHDS_Mesh* mesh = GetMeshDS();
121 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
122 else e = mesh->AddEdge (node[0], node[1] );
123 else if ( nbnode == 3 )
124 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
125 else e = mesh->AddEdge (node[0], node[1], node[2] );
130 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
131 else e = mesh->AddFace (node[0], node[1], node[2] );
132 else if (nbnode == 4)
133 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
134 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
135 else if (nbnode == 6)
136 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
137 node[4], node[5], ID);
138 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
140 else if (nbnode == 8)
141 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
142 node[4], node[5], node[6], node[7], ID);
143 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
144 node[4], node[5], node[6], node[7] );
146 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
147 else e = mesh->AddPolygonalFace (node );
153 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
154 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
155 else if (nbnode == 5)
156 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
158 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
160 else if (nbnode == 6)
161 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
162 node[4], node[5], ID);
163 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
165 else if (nbnode == 8)
166 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
167 node[4], node[5], node[6], node[7], ID);
168 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
169 node[4], node[5], node[6], node[7] );
170 else if (nbnode == 10)
171 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
172 node[4], node[5], node[6], node[7],
173 node[8], node[9], ID);
174 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
175 node[4], node[5], node[6], node[7],
177 else if (nbnode == 13)
178 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 node[4], node[5], node[6], node[7],
180 node[8], node[9], node[10],node[11],
182 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7],
184 node[8], node[9], node[10],node[11],
186 else if (nbnode == 15)
187 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7],
189 node[8], node[9], node[10],node[11],
190 node[12],node[13],node[14],ID);
191 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
193 node[8], node[9], node[10],node[11],
194 node[12],node[13],node[14] );
195 else if (nbnode == 20)
196 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
197 node[4], node[5], node[6], node[7],
198 node[8], node[9], node[10],node[11],
199 node[12],node[13],node[14],node[15],
200 node[16],node[17],node[18],node[19],ID);
201 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
202 node[4], node[5], node[6], node[7],
203 node[8], node[9], node[10],node[11],
204 node[12],node[13],node[14],node[15],
205 node[16],node[17],node[18],node[19] );
211 //=======================================================================
215 //=======================================================================
217 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
218 const SMDSAbs_ElementType type,
222 vector<const SMDS_MeshNode*> nodes;
223 nodes.reserve( nodeIDs.size() );
224 vector<int>::const_iterator id = nodeIDs.begin();
225 while ( id != nodeIDs.end() ) {
226 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
227 nodes.push_back( node );
231 return AddElement( nodes, type, isPoly, ID );
234 //=======================================================================
236 //purpose : Remove a node or an element.
237 // Modify a compute state of sub-meshes which become empty
238 //=======================================================================
240 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
243 myLastCreatedElems.Clear();
244 myLastCreatedNodes.Clear();
246 SMESHDS_Mesh* aMesh = GetMeshDS();
247 set< SMESH_subMesh *> smmap;
249 list<int>::const_iterator it = theIDs.begin();
250 for ( ; it != theIDs.end(); it++ ) {
251 const SMDS_MeshElement * elem;
253 elem = aMesh->FindNode( *it );
255 elem = aMesh->FindElement( *it );
259 // Notify VERTEX sub-meshes about modification
261 const SMDS_MeshNode* node = cast2Node( elem );
262 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
263 if ( int aShapeID = node->GetPosition()->GetShapeId() )
264 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
267 // Find sub-meshes to notify about modification
268 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
269 // while ( nodeIt->more() ) {
270 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
271 // const SMDS_PositionPtr& aPosition = node->GetPosition();
272 // if ( aPosition.get() ) {
273 // if ( int aShapeID = aPosition->GetShapeId() ) {
274 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
275 // smmap.insert( sm );
282 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
284 aMesh->RemoveElement( elem );
287 // Notify sub-meshes about modification
288 if ( !smmap.empty() ) {
289 set< SMESH_subMesh *>::iterator smIt;
290 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
291 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
294 // // Check if the whole mesh becomes empty
295 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
296 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
301 //=======================================================================
302 //function : FindShape
303 //purpose : Return an index of the shape theElem is on
304 // or zero if a shape not found
305 //=======================================================================
307 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
309 myLastCreatedElems.Clear();
310 myLastCreatedNodes.Clear();
312 SMESHDS_Mesh * aMesh = GetMeshDS();
313 if ( aMesh->ShapeToMesh().IsNull() )
316 if ( theElem->GetType() == SMDSAbs_Node ) {
317 const SMDS_PositionPtr& aPosition =
318 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
319 if ( aPosition.get() )
320 return aPosition->GetShapeId();
325 TopoDS_Shape aShape; // the shape a node is on
326 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
327 while ( nodeIt->more() ) {
328 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
329 const SMDS_PositionPtr& aPosition = node->GetPosition();
330 if ( aPosition.get() ) {
331 int aShapeID = aPosition->GetShapeId();
332 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
334 if ( sm->Contains( theElem ))
336 if ( aShape.IsNull() )
337 aShape = aMesh->IndexToShape( aShapeID );
340 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
345 // None of nodes is on a proper shape,
346 // find the shape among ancestors of aShape on which a node is
347 if ( aShape.IsNull() ) {
348 //MESSAGE ("::FindShape() - NONE node is on shape")
351 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
352 for ( ; ancIt.More(); ancIt.Next() ) {
353 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
354 if ( sm && sm->Contains( theElem ))
355 return aMesh->ShapeToIndex( ancIt.Value() );
358 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
362 //=======================================================================
363 //function : IsMedium
365 //=======================================================================
367 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
368 const SMDSAbs_ElementType typeToCheck)
370 bool isMedium = false;
371 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
372 while (it->more() && !isMedium ) {
373 const SMDS_MeshElement* elem = it->next();
374 isMedium = elem->IsMediumNode(node);
379 //=======================================================================
380 //function : ShiftNodesQuadTria
382 // Shift nodes in the array corresponded to quadratic triangle
383 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
384 //=======================================================================
385 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
387 const SMDS_MeshNode* nd1 = aNodes[0];
388 aNodes[0] = aNodes[1];
389 aNodes[1] = aNodes[2];
391 const SMDS_MeshNode* nd2 = aNodes[3];
392 aNodes[3] = aNodes[4];
393 aNodes[4] = aNodes[5];
397 //=======================================================================
398 //function : GetNodesFromTwoTria
400 // Shift nodes in the array corresponded to quadratic triangle
401 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
402 //=======================================================================
403 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
404 const SMDS_MeshElement * theTria2,
405 const SMDS_MeshNode* N1[],
406 const SMDS_MeshNode* N2[])
408 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
411 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
414 if(it->more()) return false;
415 it = theTria2->nodesIterator();
418 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
421 if(it->more()) return false;
423 int sames[3] = {-1,-1,-1};
435 if(nbsames!=2) return false;
437 ShiftNodesQuadTria(N1);
439 ShiftNodesQuadTria(N1);
442 i = sames[0] + sames[1] + sames[2];
444 ShiftNodesQuadTria(N2);
446 // now we receive following N1 and N2 (using numeration as above image)
447 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
448 // i.e. first nodes from both arrays determ new diagonal
452 //=======================================================================
453 //function : InverseDiag
454 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
455 // but having other common link.
456 // Return False if args are improper
457 //=======================================================================
459 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
460 const SMDS_MeshElement * theTria2 )
462 myLastCreatedElems.Clear();
463 myLastCreatedNodes.Clear();
465 if (!theTria1 || !theTria2)
468 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
469 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
472 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
473 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
477 // put nodes in array and find out indices of the same ones
478 const SMDS_MeshNode* aNodes [6];
479 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
481 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
482 while ( it->more() ) {
483 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
485 if ( i > 2 ) // theTria2
486 // find same node of theTria1
487 for ( int j = 0; j < 3; j++ )
488 if ( aNodes[ i ] == aNodes[ j ]) {
497 return false; // theTria1 is not a triangle
498 it = theTria2->nodesIterator();
500 if ( i == 6 && it->more() )
501 return false; // theTria2 is not a triangle
504 // find indices of 1,2 and of A,B in theTria1
505 int iA = 0, iB = 0, i1 = 0, i2 = 0;
506 for ( i = 0; i < 6; i++ ) {
507 if ( sameInd [ i ] == 0 )
514 // nodes 1 and 2 should not be the same
515 if ( aNodes[ i1 ] == aNodes[ i2 ] )
519 aNodes[ iA ] = aNodes[ i2 ];
521 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
523 //MESSAGE( theTria1 << theTria2 );
525 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
526 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
528 //MESSAGE( theTria1 << theTria2 );
532 } // end if(F1 && F2)
534 // check case of quadratic faces
535 const SMDS_QuadraticFaceOfNodes* QF1 =
536 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
537 if(!QF1) return false;
538 const SMDS_QuadraticFaceOfNodes* QF2 =
539 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
540 if(!QF2) return false;
543 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
544 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
552 const SMDS_MeshNode* N1 [6];
553 const SMDS_MeshNode* N2 [6];
554 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
556 // now we receive following N1 and N2 (using numeration as above image)
557 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
558 // i.e. first nodes from both arrays determ new diagonal
560 const SMDS_MeshNode* N1new [6];
561 const SMDS_MeshNode* N2new [6];
574 // replaces nodes in faces
575 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
576 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
581 //=======================================================================
582 //function : findTriangles
583 //purpose : find triangles sharing theNode1-theNode2 link
584 //=======================================================================
586 static bool findTriangles(const SMDS_MeshNode * theNode1,
587 const SMDS_MeshNode * theNode2,
588 const SMDS_MeshElement*& theTria1,
589 const SMDS_MeshElement*& theTria2)
591 if ( !theNode1 || !theNode2 ) return false;
593 theTria1 = theTria2 = 0;
595 set< const SMDS_MeshElement* > emap;
596 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
598 const SMDS_MeshElement* elem = it->next();
599 if ( elem->NbNodes() == 3 )
602 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
604 const SMDS_MeshElement* elem = it->next();
605 if ( emap.find( elem ) != emap.end() )
607 // theTria1 must be element with minimum ID
608 if( theTria1->GetID() < elem->GetID() ) {
621 return ( theTria1 && theTria2 );
624 //=======================================================================
625 //function : InverseDiag
626 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
627 // with ones built on the same 4 nodes but having other common link.
628 // Return false if proper faces not found
629 //=======================================================================
631 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
632 const SMDS_MeshNode * theNode2)
634 myLastCreatedElems.Clear();
635 myLastCreatedNodes.Clear();
637 MESSAGE( "::InverseDiag()" );
639 const SMDS_MeshElement *tr1, *tr2;
640 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
643 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
644 //if (!F1) return false;
645 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
646 //if (!F2) return false;
649 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
650 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
654 // put nodes in array
655 // and find indices of 1,2 and of A in tr1 and of B in tr2
656 int i, iA1 = 0, i1 = 0;
657 const SMDS_MeshNode* aNodes1 [3];
658 SMDS_ElemIteratorPtr it;
659 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
660 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
661 if ( aNodes1[ i ] == theNode1 )
662 iA1 = i; // node A in tr1
663 else if ( aNodes1[ i ] != theNode2 )
667 const SMDS_MeshNode* aNodes2 [3];
668 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
669 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
670 if ( aNodes2[ i ] == theNode2 )
671 iB2 = i; // node B in tr2
672 else if ( aNodes2[ i ] != theNode1 )
676 // nodes 1 and 2 should not be the same
677 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
681 aNodes1[ iA1 ] = aNodes2[ i2 ];
683 aNodes2[ iB2 ] = aNodes1[ i1 ];
685 //MESSAGE( tr1 << tr2 );
687 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
688 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
690 //MESSAGE( tr1 << tr2 );
695 // check case of quadratic faces
696 const SMDS_QuadraticFaceOfNodes* QF1 =
697 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
698 if(!QF1) return false;
699 const SMDS_QuadraticFaceOfNodes* QF2 =
700 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
701 if(!QF2) return false;
702 return InverseDiag(tr1,tr2);
705 //=======================================================================
706 //function : getQuadrangleNodes
707 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
708 // fusion of triangles tr1 and tr2 having shared link on
709 // theNode1 and theNode2
710 //=======================================================================
712 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
713 const SMDS_MeshNode * theNode1,
714 const SMDS_MeshNode * theNode2,
715 const SMDS_MeshElement * tr1,
716 const SMDS_MeshElement * tr2 )
718 if( tr1->NbNodes() != tr2->NbNodes() )
720 // find the 4-th node to insert into tr1
721 const SMDS_MeshNode* n4 = 0;
722 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
724 while ( !n4 && i<3 ) {
725 const SMDS_MeshNode * n = cast2Node( it->next() );
727 bool isDiag = ( n == theNode1 || n == theNode2 );
731 // Make an array of nodes to be in a quadrangle
732 int iNode = 0, iFirstDiag = -1;
733 it = tr1->nodesIterator();
736 const SMDS_MeshNode * n = cast2Node( it->next() );
738 bool isDiag = ( n == theNode1 || n == theNode2 );
740 if ( iFirstDiag < 0 )
742 else if ( iNode - iFirstDiag == 1 )
743 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
745 else if ( n == n4 ) {
746 return false; // tr1 and tr2 should not have all the same nodes
748 theQuadNodes[ iNode++ ] = n;
750 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
751 theQuadNodes[ iNode ] = n4;
756 //=======================================================================
757 //function : DeleteDiag
758 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
759 // with a quadrangle built on the same 4 nodes.
760 // Return false if proper faces not found
761 //=======================================================================
763 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
764 const SMDS_MeshNode * theNode2)
766 myLastCreatedElems.Clear();
767 myLastCreatedNodes.Clear();
769 MESSAGE( "::DeleteDiag()" );
771 const SMDS_MeshElement *tr1, *tr2;
772 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
775 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
776 //if (!F1) return false;
777 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
778 //if (!F2) return false;
781 const SMDS_MeshNode* aNodes [ 4 ];
782 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
785 //MESSAGE( endl << tr1 << tr2 );
787 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
788 myLastCreatedElems.Append(tr1);
789 GetMeshDS()->RemoveElement( tr2 );
791 //MESSAGE( endl << tr1 );
796 // check case of quadratic faces
797 const SMDS_QuadraticFaceOfNodes* QF1 =
798 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
799 if(!QF1) return false;
800 const SMDS_QuadraticFaceOfNodes* QF2 =
801 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
802 if(!QF2) return false;
805 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
806 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
814 const SMDS_MeshNode* N1 [6];
815 const SMDS_MeshNode* N2 [6];
816 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
818 // now we receive following N1 and N2 (using numeration as above image)
819 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
820 // i.e. first nodes from both arrays determ new diagonal
822 const SMDS_MeshNode* aNodes[8];
832 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
833 myLastCreatedElems.Append(tr1);
834 GetMeshDS()->RemoveElement( tr2 );
836 // remove middle node (9)
837 GetMeshDS()->RemoveNode( N1[4] );
842 //=======================================================================
843 //function : Reorient
844 //purpose : Reverse theElement orientation
845 //=======================================================================
847 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
849 myLastCreatedElems.Clear();
850 myLastCreatedNodes.Clear();
854 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
855 if ( !it || !it->more() )
858 switch ( theElem->GetType() ) {
862 if(!theElem->IsQuadratic()) {
863 int i = theElem->NbNodes();
864 vector<const SMDS_MeshNode*> aNodes( i );
866 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
867 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
870 // quadratic elements
871 if(theElem->GetType()==SMDSAbs_Edge) {
872 vector<const SMDS_MeshNode*> aNodes(3);
873 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
874 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
875 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
876 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
879 int nbn = theElem->NbNodes();
880 vector<const SMDS_MeshNode*> aNodes(nbn);
881 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
883 for(; i<nbn/2; i++) {
884 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
886 for(i=0; i<nbn/2; i++) {
887 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
889 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
893 case SMDSAbs_Volume: {
894 if (theElem->IsPoly()) {
895 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
896 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
898 MESSAGE("Warning: bad volumic element");
902 int nbFaces = aPolyedre->NbFaces();
903 vector<const SMDS_MeshNode *> poly_nodes;
904 vector<int> quantities (nbFaces);
906 // reverse each face of the polyedre
907 for (int iface = 1; iface <= nbFaces; iface++) {
908 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
909 quantities[iface - 1] = nbFaceNodes;
911 for (inode = nbFaceNodes; inode >= 1; inode--) {
912 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
913 poly_nodes.push_back(curNode);
917 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
921 SMDS_VolumeTool vTool;
922 if ( !vTool.Set( theElem ))
925 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
934 //=======================================================================
935 //function : getBadRate
937 //=======================================================================
939 static double getBadRate (const SMDS_MeshElement* theElem,
940 SMESH::Controls::NumericalFunctorPtr& theCrit)
942 SMESH::Controls::TSequenceOfXYZ P;
943 if ( !theElem || !theCrit->GetPoints( theElem, P ))
945 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
946 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
949 //=======================================================================
950 //function : QuadToTri
951 //purpose : Cut quadrangles into triangles.
952 // theCrit is used to select a diagonal to cut
953 //=======================================================================
955 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
956 SMESH::Controls::NumericalFunctorPtr theCrit)
958 myLastCreatedElems.Clear();
959 myLastCreatedNodes.Clear();
961 MESSAGE( "::QuadToTri()" );
963 if ( !theCrit.get() )
966 SMESHDS_Mesh * aMesh = GetMeshDS();
968 Handle(Geom_Surface) surface;
969 SMESH_MesherHelper helper( *GetMesh() );
971 TIDSortedElemSet::iterator itElem;
972 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
973 const SMDS_MeshElement* elem = *itElem;
974 if ( !elem || elem->GetType() != SMDSAbs_Face )
976 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
979 // retrieve element nodes
980 const SMDS_MeshNode* aNodes [8];
981 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
983 while ( itN->more() )
984 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
986 // compare two sets of possible triangles
987 double aBadRate1, aBadRate2; // to what extent a set is bad
988 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
989 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
990 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
992 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
993 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
994 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
996 int aShapeId = FindShape( elem );
997 const SMDS_MeshElement* newElem = 0;
999 if( !elem->IsQuadratic() ) {
1001 // split liner quadrangle
1003 if ( aBadRate1 <= aBadRate2 ) {
1004 // tr1 + tr2 is better
1005 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1006 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1009 // tr3 + tr4 is better
1010 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1011 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1016 // split quadratic quadrangle
1018 // get surface elem is on
1019 if ( aShapeId != helper.GetSubShapeID() ) {
1023 shape = aMesh->IndexToShape( aShapeId );
1024 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1025 TopoDS_Face face = TopoDS::Face( shape );
1026 surface = BRep_Tool::Surface( face );
1027 if ( !surface.IsNull() )
1028 helper.SetSubShape( shape );
1032 const SMDS_MeshNode* aNodes [8];
1033 const SMDS_MeshNode* inFaceNode = 0;
1034 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1036 while ( itN->more() ) {
1037 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1038 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1039 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1041 inFaceNode = aNodes[ i-1 ];
1044 // find middle point for (0,1,2,3)
1045 // and create a node in this point;
1047 if ( surface.IsNull() ) {
1049 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1053 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1056 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1058 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1060 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1061 myLastCreatedNodes.Append(newN);
1063 // create a new element
1064 const SMDS_MeshNode* N[6];
1065 if ( aBadRate1 <= aBadRate2 ) {
1072 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1073 aNodes[6], aNodes[7], newN );
1082 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1083 aNodes[7], aNodes[4], newN );
1085 aMesh->ChangeElementNodes( elem, N, 6 );
1089 // care of a new element
1091 myLastCreatedElems.Append(newElem);
1092 AddToSameGroups( newElem, elem, aMesh );
1094 // put a new triangle on the same shape
1096 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1101 //=======================================================================
1102 //function : BestSplit
1103 //purpose : Find better diagonal for cutting.
1104 //=======================================================================
1105 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1106 SMESH::Controls::NumericalFunctorPtr theCrit)
1108 myLastCreatedElems.Clear();
1109 myLastCreatedNodes.Clear();
1114 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1117 if( theQuad->NbNodes()==4 ||
1118 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1120 // retrieve element nodes
1121 const SMDS_MeshNode* aNodes [4];
1122 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1124 //while (itN->more())
1126 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1128 // compare two sets of possible triangles
1129 double aBadRate1, aBadRate2; // to what extent a set is bad
1130 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1131 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1132 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1134 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1135 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1136 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1138 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1139 return 1; // diagonal 1-3
1141 return 2; // diagonal 2-4
1146 //=======================================================================
1147 //function : AddToSameGroups
1148 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1149 //=======================================================================
1151 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1152 const SMDS_MeshElement* elemInGroups,
1153 SMESHDS_Mesh * aMesh)
1155 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1156 if (!groups.empty()) {
1157 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1158 for ( ; grIt != groups.end(); grIt++ ) {
1159 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1160 if ( group && group->Contains( elemInGroups ))
1161 group->SMDSGroup().Add( elemToAdd );
1167 //=======================================================================
1168 //function : RemoveElemFromGroups
1169 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1170 //=======================================================================
1171 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1172 SMESHDS_Mesh * aMesh)
1174 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1175 if (!groups.empty())
1177 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1178 for (; GrIt != groups.end(); GrIt++)
1180 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1181 if (!grp || grp->IsEmpty()) continue;
1182 grp->SMDSGroup().Remove(removeelem);
1187 //=======================================================================
1188 //function : ReplaceElemInGroups
1189 //purpose : replace elemToRm by elemToAdd in the all groups
1190 //=======================================================================
1192 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1193 const SMDS_MeshElement* elemToAdd,
1194 SMESHDS_Mesh * aMesh)
1196 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1197 if (!groups.empty()) {
1198 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1199 for ( ; grIt != groups.end(); grIt++ ) {
1200 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1201 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1202 group->SMDSGroup().Add( elemToAdd );
1207 //=======================================================================
1208 //function : QuadToTri
1209 //purpose : Cut quadrangles into triangles.
1210 // theCrit is used to select a diagonal to cut
1211 //=======================================================================
1213 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1214 const bool the13Diag)
1216 myLastCreatedElems.Clear();
1217 myLastCreatedNodes.Clear();
1219 MESSAGE( "::QuadToTri()" );
1221 SMESHDS_Mesh * aMesh = GetMeshDS();
1223 Handle(Geom_Surface) surface;
1224 SMESH_MesherHelper helper( *GetMesh() );
1226 TIDSortedElemSet::iterator itElem;
1227 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1228 const SMDS_MeshElement* elem = *itElem;
1229 if ( !elem || elem->GetType() != SMDSAbs_Face )
1231 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1232 if(!isquad) continue;
1234 if(elem->NbNodes()==4) {
1235 // retrieve element nodes
1236 const SMDS_MeshNode* aNodes [4];
1237 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1239 while ( itN->more() )
1240 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1242 int aShapeId = FindShape( elem );
1243 const SMDS_MeshElement* newElem = 0;
1245 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1246 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1249 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1250 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1252 myLastCreatedElems.Append(newElem);
1253 // put a new triangle on the same shape and add to the same groups
1255 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1256 AddToSameGroups( newElem, elem, aMesh );
1259 // Quadratic quadrangle
1261 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1263 // get surface elem is on
1264 int aShapeId = FindShape( elem );
1265 if ( aShapeId != helper.GetSubShapeID() ) {
1269 shape = aMesh->IndexToShape( aShapeId );
1270 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1271 TopoDS_Face face = TopoDS::Face( shape );
1272 surface = BRep_Tool::Surface( face );
1273 if ( !surface.IsNull() )
1274 helper.SetSubShape( shape );
1278 const SMDS_MeshNode* aNodes [8];
1279 const SMDS_MeshNode* inFaceNode = 0;
1280 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1282 while ( itN->more() ) {
1283 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1284 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1285 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1287 inFaceNode = aNodes[ i-1 ];
1291 // find middle point for (0,1,2,3)
1292 // and create a node in this point;
1294 if ( surface.IsNull() ) {
1296 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1300 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1303 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1305 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1307 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1308 myLastCreatedNodes.Append(newN);
1310 // create a new element
1311 const SMDS_MeshElement* newElem = 0;
1312 const SMDS_MeshNode* N[6];
1320 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1321 aNodes[6], aNodes[7], newN );
1330 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1331 aNodes[7], aNodes[4], newN );
1333 myLastCreatedElems.Append(newElem);
1334 aMesh->ChangeElementNodes( elem, N, 6 );
1335 // put a new triangle on the same shape and add to the same groups
1337 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1338 AddToSameGroups( newElem, elem, aMesh );
1345 //=======================================================================
1346 //function : getAngle
1348 //=======================================================================
1350 double getAngle(const SMDS_MeshElement * tr1,
1351 const SMDS_MeshElement * tr2,
1352 const SMDS_MeshNode * n1,
1353 const SMDS_MeshNode * n2)
1355 double angle = 2*PI; // bad angle
1358 SMESH::Controls::TSequenceOfXYZ P1, P2;
1359 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1360 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1363 if(!tr1->IsQuadratic())
1364 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1366 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1367 if ( N1.SquareMagnitude() <= gp::Resolution() )
1369 if(!tr2->IsQuadratic())
1370 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1372 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1373 if ( N2.SquareMagnitude() <= gp::Resolution() )
1376 // find the first diagonal node n1 in the triangles:
1377 // take in account a diagonal link orientation
1378 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1379 for ( int t = 0; t < 2; t++ ) {
1380 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1381 int i = 0, iDiag = -1;
1382 while ( it->more()) {
1383 const SMDS_MeshElement *n = it->next();
1384 if ( n == n1 || n == n2 )
1388 if ( i - iDiag == 1 )
1389 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1397 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1400 angle = N1.Angle( N2 );
1405 // =================================================
1406 // class generating a unique ID for a pair of nodes
1407 // and able to return nodes by that ID
1408 // =================================================
1412 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1413 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1416 long GetLinkID (const SMDS_MeshNode * n1,
1417 const SMDS_MeshNode * n2) const
1419 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1422 bool GetNodes (const long theLinkID,
1423 const SMDS_MeshNode* & theNode1,
1424 const SMDS_MeshNode* & theNode2) const
1426 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1427 if ( !theNode1 ) return false;
1428 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1429 if ( !theNode2 ) return false;
1435 const SMESHDS_Mesh* myMesh;
1440 //=======================================================================
1441 //function : TriToQuad
1442 //purpose : Fuse neighbour triangles into quadrangles.
1443 // theCrit is used to select a neighbour to fuse with.
1444 // theMaxAngle is a max angle between element normals at which
1445 // fusion is still performed.
1446 //=======================================================================
1448 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1449 SMESH::Controls::NumericalFunctorPtr theCrit,
1450 const double theMaxAngle)
1452 myLastCreatedElems.Clear();
1453 myLastCreatedNodes.Clear();
1455 MESSAGE( "::TriToQuad()" );
1457 if ( !theCrit.get() )
1460 SMESHDS_Mesh * aMesh = GetMeshDS();
1462 // Prepare data for algo: build
1463 // 1. map of elements with their linkIDs
1464 // 2. map of linkIDs with their elements
1466 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1467 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1468 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1469 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1471 TIDSortedElemSet::iterator itElem;
1472 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1473 const SMDS_MeshElement* elem = *itElem;
1474 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1475 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1476 if(!IsTria) continue;
1478 // retrieve element nodes
1479 const SMDS_MeshNode* aNodes [4];
1480 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1483 aNodes[ i++ ] = cast2Node( itN->next() );
1484 aNodes[ 3 ] = aNodes[ 0 ];
1487 for ( i = 0; i < 3; i++ ) {
1488 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1489 // check if elements sharing a link can be fused
1490 itLE = mapLi_listEl.find( link );
1491 if ( itLE != mapLi_listEl.end() ) {
1492 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1494 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1495 //if ( FindShape( elem ) != FindShape( elem2 ))
1496 // continue; // do not fuse triangles laying on different shapes
1497 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1498 continue; // avoid making badly shaped quads
1499 (*itLE).second.push_back( elem );
1502 mapLi_listEl[ link ].push_back( elem );
1504 mapEl_setLi [ elem ].insert( link );
1507 // Clean the maps from the links shared by a sole element, ie
1508 // links to which only one element is bound in mapLi_listEl
1510 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1511 int nbElems = (*itLE).second.size();
1512 if ( nbElems < 2 ) {
1513 const SMDS_MeshElement* elem = (*itLE).second.front();
1514 SMESH_TLink link = (*itLE).first;
1515 mapEl_setLi[ elem ].erase( link );
1516 if ( mapEl_setLi[ elem ].empty() )
1517 mapEl_setLi.erase( elem );
1521 // Algo: fuse triangles into quadrangles
1523 while ( ! mapEl_setLi.empty() ) {
1524 // Look for the start element:
1525 // the element having the least nb of shared links
1526 const SMDS_MeshElement* startElem = 0;
1528 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1529 int nbLinks = (*itEL).second.size();
1530 if ( nbLinks < minNbLinks ) {
1531 startElem = (*itEL).first;
1532 minNbLinks = nbLinks;
1533 if ( minNbLinks == 1 )
1538 // search elements to fuse starting from startElem or links of elements
1539 // fused earlyer - startLinks
1540 list< SMESH_TLink > startLinks;
1541 while ( startElem || !startLinks.empty() ) {
1542 while ( !startElem && !startLinks.empty() ) {
1543 // Get an element to start, by a link
1544 SMESH_TLink linkId = startLinks.front();
1545 startLinks.pop_front();
1546 itLE = mapLi_listEl.find( linkId );
1547 if ( itLE != mapLi_listEl.end() ) {
1548 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1549 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1550 for ( ; itE != listElem.end() ; itE++ )
1551 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1553 mapLi_listEl.erase( itLE );
1558 // Get candidates to be fused
1559 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1560 const SMESH_TLink *link12, *link13;
1562 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1563 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1564 ASSERT( !setLi.empty() );
1565 set< SMESH_TLink >::iterator itLi;
1566 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1568 const SMESH_TLink & link = (*itLi);
1569 itLE = mapLi_listEl.find( link );
1570 if ( itLE == mapLi_listEl.end() )
1573 const SMDS_MeshElement* elem = (*itLE).second.front();
1575 elem = (*itLE).second.back();
1576 mapLi_listEl.erase( itLE );
1577 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1588 // add other links of elem to list of links to re-start from
1589 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1590 set< SMESH_TLink >::iterator it;
1591 for ( it = links.begin(); it != links.end(); it++ ) {
1592 const SMESH_TLink& link2 = (*it);
1593 if ( link2 != link )
1594 startLinks.push_back( link2 );
1598 // Get nodes of possible quadrangles
1599 const SMDS_MeshNode *n12 [4], *n13 [4];
1600 bool Ok12 = false, Ok13 = false;
1601 const SMDS_MeshNode *linkNode1, *linkNode2;
1603 linkNode1 = link12->first;
1604 linkNode2 = link12->second;
1605 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1609 linkNode1 = link13->first;
1610 linkNode2 = link13->second;
1611 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1615 // Choose a pair to fuse
1616 if ( Ok12 && Ok13 ) {
1617 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1618 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1619 double aBadRate12 = getBadRate( &quad12, theCrit );
1620 double aBadRate13 = getBadRate( &quad13, theCrit );
1621 if ( aBadRate13 < aBadRate12 )
1628 // and remove fused elems and removed links from the maps
1629 mapEl_setLi.erase( tr1 );
1631 mapEl_setLi.erase( tr2 );
1632 mapLi_listEl.erase( *link12 );
1633 if(tr1->NbNodes()==3) {
1634 if( tr1->GetID() < tr2->GetID() ) {
1635 aMesh->ChangeElementNodes( tr1, n12, 4 );
1636 myLastCreatedElems.Append(tr1);
1637 aMesh->RemoveElement( tr2 );
1640 aMesh->ChangeElementNodes( tr2, n12, 4 );
1641 myLastCreatedElems.Append(tr2);
1642 aMesh->RemoveElement( tr1);
1646 const SMDS_MeshNode* N1 [6];
1647 const SMDS_MeshNode* N2 [6];
1648 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1649 // now we receive following N1 and N2 (using numeration as above image)
1650 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1651 // i.e. first nodes from both arrays determ new diagonal
1652 const SMDS_MeshNode* aNodes[8];
1661 if( tr1->GetID() < tr2->GetID() ) {
1662 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1663 myLastCreatedElems.Append(tr1);
1664 GetMeshDS()->RemoveElement( tr2 );
1667 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1668 myLastCreatedElems.Append(tr2);
1669 GetMeshDS()->RemoveElement( tr1 );
1671 // remove middle node (9)
1672 GetMeshDS()->RemoveNode( N1[4] );
1676 mapEl_setLi.erase( tr3 );
1677 mapLi_listEl.erase( *link13 );
1678 if(tr1->NbNodes()==3) {
1679 if( tr1->GetID() < tr2->GetID() ) {
1680 aMesh->ChangeElementNodes( tr1, n13, 4 );
1681 myLastCreatedElems.Append(tr1);
1682 aMesh->RemoveElement( tr3 );
1685 aMesh->ChangeElementNodes( tr3, n13, 4 );
1686 myLastCreatedElems.Append(tr3);
1687 aMesh->RemoveElement( tr1 );
1691 const SMDS_MeshNode* N1 [6];
1692 const SMDS_MeshNode* N2 [6];
1693 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1694 // now we receive following N1 and N2 (using numeration as above image)
1695 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1696 // i.e. first nodes from both arrays determ new diagonal
1697 const SMDS_MeshNode* aNodes[8];
1706 if( tr1->GetID() < tr2->GetID() ) {
1707 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1708 myLastCreatedElems.Append(tr1);
1709 GetMeshDS()->RemoveElement( tr3 );
1712 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1713 myLastCreatedElems.Append(tr3);
1714 GetMeshDS()->RemoveElement( tr1 );
1716 // remove middle node (9)
1717 GetMeshDS()->RemoveNode( N1[4] );
1721 // Next element to fuse: the rejected one
1723 startElem = Ok12 ? tr3 : tr2;
1725 } // if ( startElem )
1726 } // while ( startElem || !startLinks.empty() )
1727 } // while ( ! mapEl_setLi.empty() )
1733 /*#define DUMPSO(txt) \
1734 // cout << txt << endl;
1735 //=============================================================================
1739 //=============================================================================
1740 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1744 int tmp = idNodes[ i1 ];
1745 idNodes[ i1 ] = idNodes[ i2 ];
1746 idNodes[ i2 ] = tmp;
1747 gp_Pnt Ptmp = P[ i1 ];
1750 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1753 //=======================================================================
1754 //function : SortQuadNodes
1755 //purpose : Set 4 nodes of a quadrangle face in a good order.
1756 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1758 //=======================================================================
1760 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1765 for ( i = 0; i < 4; i++ ) {
1766 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1768 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1771 gp_Vec V1(P[0], P[1]);
1772 gp_Vec V2(P[0], P[2]);
1773 gp_Vec V3(P[0], P[3]);
1775 gp_Vec Cross1 = V1 ^ V2;
1776 gp_Vec Cross2 = V2 ^ V3;
1779 if (Cross1.Dot(Cross2) < 0)
1784 if (Cross1.Dot(Cross2) < 0)
1788 swap ( i, i + 1, idNodes, P );
1790 // for ( int ii = 0; ii < 4; ii++ ) {
1791 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1792 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1798 //=======================================================================
1799 //function : SortHexaNodes
1800 //purpose : Set 8 nodes of a hexahedron in a good order.
1801 // Return success status
1802 //=======================================================================
1804 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1809 DUMPSO( "INPUT: ========================================");
1810 for ( i = 0; i < 8; i++ ) {
1811 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1812 if ( !n ) return false;
1813 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1814 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1816 DUMPSO( "========================================");
1819 set<int> faceNodes; // ids of bottom face nodes, to be found
1820 set<int> checkedId1; // ids of tried 2-nd nodes
1821 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1822 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1823 int iMin, iLoop1 = 0;
1825 // Loop to try the 2-nd nodes
1827 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1829 // Find not checked 2-nd node
1830 for ( i = 1; i < 8; i++ )
1831 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1832 int id1 = idNodes[i];
1833 swap ( 1, i, idNodes, P );
1834 checkedId1.insert ( id1 );
1838 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
1839 // ie that all but meybe one (id3 which is on the same face) nodes
1840 // lay on the same side from the triangle plane.
1842 bool manyInPlane = false; // more than 4 nodes lay in plane
1844 while ( ++iLoop2 < 6 ) {
1846 // get 1-2-3 plane coeffs
1847 Standard_Real A, B, C, D;
1848 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1849 if ( N.SquareMagnitude() > gp::Resolution() )
1851 gp_Pln pln ( P[0], N );
1852 pln.Coefficients( A, B, C, D );
1854 // find the node (iMin) closest to pln
1855 Standard_Real dist[ 8 ], minDist = DBL_MAX;
1857 for ( i = 3; i < 8; i++ ) {
1858 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
1859 if ( fabs( dist[i] ) < minDist ) {
1860 minDist = fabs( dist[i] );
1863 if ( fabs( dist[i] ) <= tol )
1864 idInPln.insert( idNodes[i] );
1867 // there should not be more than 4 nodes in bottom plane
1868 if ( idInPln.size() > 1 )
1870 DUMPSO( "### idInPln.size() = " << idInPln.size());
1871 // idInPlane does not contain the first 3 nodes
1872 if ( manyInPlane || idInPln.size() == 5)
1873 return false; // all nodes in one plane
1876 // set the 1-st node to be not in plane
1877 for ( i = 3; i < 8; i++ ) {
1878 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
1879 DUMPSO( "### Reset 0-th node");
1880 swap( 0, i, idNodes, P );
1885 // reset to re-check second nodes
1886 leastDist = DBL_MAX;
1890 break; // from iLoop2;
1893 // check that the other 4 nodes are on the same side
1894 bool sameSide = true;
1895 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
1896 for ( i = 3; sameSide && i < 8; i++ ) {
1898 sameSide = ( isNeg == dist[i] <= 0.);
1901 // keep best solution
1902 if ( sameSide && minDist < leastDist ) {
1903 leastDist = minDist;
1905 faceNodes.insert( idNodes[ 1 ] );
1906 faceNodes.insert( idNodes[ 2 ] );
1907 faceNodes.insert( idNodes[ iMin ] );
1908 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
1909 << " leastDist = " << leastDist);
1910 if ( leastDist <= DBL_MIN )
1915 // set next 3-d node to check
1916 int iNext = 2 + iLoop2;
1918 DUMPSO( "Try 2-nd");
1919 swap ( 2, iNext, idNodes, P );
1921 } // while ( iLoop2 < 6 )
1924 if ( faceNodes.empty() ) return false;
1926 // Put the faceNodes in proper places
1927 for ( i = 4; i < 8; i++ ) {
1928 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
1929 // find a place to put
1931 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
1933 DUMPSO( "Set faceNodes");
1934 swap ( iTo, i, idNodes, P );
1939 // Set nodes of the found bottom face in good order
1940 DUMPSO( " Found bottom face: ");
1941 i = SortQuadNodes( theMesh, idNodes );
1943 gp_Pnt Ptmp = P[ i ];
1948 // for ( int ii = 0; ii < 4; ii++ ) {
1949 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1950 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1953 // Gravity center of the top and bottom faces
1954 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
1955 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
1957 // Get direction from the bottom to the top face
1958 gp_Vec upDir ( aGCb, aGCt );
1959 Standard_Real upDirSize = upDir.Magnitude();
1960 if ( upDirSize <= gp::Resolution() ) return false;
1963 // Assure that the bottom face normal points up
1964 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
1965 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
1966 if ( Nb.Dot( upDir ) < 0 ) {
1967 DUMPSO( "Reverse bottom face");
1968 swap( 1, 3, idNodes, P );
1971 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
1972 Standard_Real minDist = DBL_MAX;
1973 for ( i = 4; i < 8; i++ ) {
1974 // projection of P[i] to the plane defined by P[0] and upDir
1975 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
1976 Standard_Real sqDist = P[0].SquareDistance( Pp );
1977 if ( sqDist < minDist ) {
1982 DUMPSO( "Set 4-th");
1983 swap ( 4, iMin, idNodes, P );
1985 // Set nodes of the top face in good order
1986 DUMPSO( "Sort top face");
1987 i = SortQuadNodes( theMesh, &idNodes[4] );
1990 gp_Pnt Ptmp = P[ i ];
1995 // Assure that direction of the top face normal is from the bottom face
1996 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
1997 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
1998 if ( Nt.Dot( upDir ) < 0 ) {
1999 DUMPSO( "Reverse top face");
2000 swap( 5, 7, idNodes, P );
2003 // DUMPSO( "OUTPUT: ========================================");
2004 // for ( i = 0; i < 8; i++ ) {
2005 // float *p = ugrid->GetPoint(idNodes[i]);
2006 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2012 //================================================================================
2014 * \brief Return nodes linked to the given one
2015 * \param theNode - the node
2016 * \param linkedNodes - the found nodes
2017 * \param type - the type of elements to check
2019 * Medium nodes are ignored
2021 //================================================================================
2023 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2024 TIDSortedElemSet & linkedNodes,
2025 SMDSAbs_ElementType type )
2027 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2028 while ( elemIt->more() )
2030 const SMDS_MeshElement* elem = elemIt->next();
2031 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2032 if ( elem->GetType() == SMDSAbs_Volume )
2034 SMDS_VolumeTool vol( elem );
2035 while ( nodeIt->more() ) {
2036 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2037 if ( theNode != n && vol.IsLinked( theNode, n ))
2038 linkedNodes.insert( n );
2043 for ( int i = 0; nodeIt->more(); ++i ) {
2044 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2045 if ( n == theNode ) {
2046 int iBefore = i - 1;
2048 if ( elem->IsQuadratic() ) {
2049 int nb = elem->NbNodes() / 2;
2050 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2051 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2053 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2054 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2061 //=======================================================================
2062 //function : laplacianSmooth
2063 //purpose : pulls theNode toward the center of surrounding nodes directly
2064 // connected to that node along an element edge
2065 //=======================================================================
2067 void laplacianSmooth(const SMDS_MeshNode* theNode,
2068 const Handle(Geom_Surface)& theSurface,
2069 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2071 // find surrounding nodes
2073 TIDSortedElemSet nodeSet;
2074 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2076 // compute new coodrs
2078 double coord[] = { 0., 0., 0. };
2079 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2080 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2081 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2082 if ( theSurface.IsNull() ) { // smooth in 3D
2083 coord[0] += node->X();
2084 coord[1] += node->Y();
2085 coord[2] += node->Z();
2087 else { // smooth in 2D
2088 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2089 gp_XY* uv = theUVMap[ node ];
2090 coord[0] += uv->X();
2091 coord[1] += uv->Y();
2094 int nbNodes = nodeSet.size();
2097 coord[0] /= nbNodes;
2098 coord[1] /= nbNodes;
2100 if ( !theSurface.IsNull() ) {
2101 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2102 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2103 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2109 coord[2] /= nbNodes;
2113 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2116 //=======================================================================
2117 //function : centroidalSmooth
2118 //purpose : pulls theNode toward the element-area-weighted centroid of the
2119 // surrounding elements
2120 //=======================================================================
2122 void centroidalSmooth(const SMDS_MeshNode* theNode,
2123 const Handle(Geom_Surface)& theSurface,
2124 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2126 gp_XYZ aNewXYZ(0.,0.,0.);
2127 SMESH::Controls::Area anAreaFunc;
2128 double totalArea = 0.;
2133 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2134 while ( elemIt->more() )
2136 const SMDS_MeshElement* elem = elemIt->next();
2139 gp_XYZ elemCenter(0.,0.,0.);
2140 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2141 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2142 int nn = elem->NbNodes();
2143 if(elem->IsQuadratic()) nn = nn/2;
2145 //while ( itN->more() ) {
2147 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2149 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2150 aNodePoints.push_back( aP );
2151 if ( !theSurface.IsNull() ) { // smooth in 2D
2152 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2153 gp_XY* uv = theUVMap[ aNode ];
2154 aP.SetCoord( uv->X(), uv->Y(), 0. );
2158 double elemArea = anAreaFunc.GetValue( aNodePoints );
2159 totalArea += elemArea;
2161 aNewXYZ += elemCenter * elemArea;
2163 aNewXYZ /= totalArea;
2164 if ( !theSurface.IsNull() ) {
2165 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2166 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2171 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2174 //=======================================================================
2175 //function : getClosestUV
2176 //purpose : return UV of closest projection
2177 //=======================================================================
2179 static bool getClosestUV (Extrema_GenExtPS& projector,
2180 const gp_Pnt& point,
2183 projector.Perform( point );
2184 if ( projector.IsDone() ) {
2185 double u, v, minVal = DBL_MAX;
2186 for ( int i = projector.NbExt(); i > 0; i-- )
2187 if ( projector.Value( i ) < minVal ) {
2188 minVal = projector.Value( i );
2189 projector.Point( i ).Parameter( u, v );
2191 result.SetCoord( u, v );
2197 //=======================================================================
2199 //purpose : Smooth theElements during theNbIterations or until a worst
2200 // element has aspect ratio <= theTgtAspectRatio.
2201 // Aspect Ratio varies in range [1.0, inf].
2202 // If theElements is empty, the whole mesh is smoothed.
2203 // theFixedNodes contains additionally fixed nodes. Nodes built
2204 // on edges and boundary nodes are always fixed.
2205 //=======================================================================
2207 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2208 set<const SMDS_MeshNode*> & theFixedNodes,
2209 const SmoothMethod theSmoothMethod,
2210 const int theNbIterations,
2211 double theTgtAspectRatio,
2214 myLastCreatedElems.Clear();
2215 myLastCreatedNodes.Clear();
2217 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2219 if ( theTgtAspectRatio < 1.0 )
2220 theTgtAspectRatio = 1.0;
2222 const double disttol = 1.e-16;
2224 SMESH::Controls::AspectRatio aQualityFunc;
2226 SMESHDS_Mesh* aMesh = GetMeshDS();
2228 if ( theElems.empty() ) {
2229 // add all faces to theElems
2230 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2231 while ( fIt->more() ) {
2232 const SMDS_MeshElement* face = fIt->next();
2233 theElems.insert( face );
2236 // get all face ids theElems are on
2237 set< int > faceIdSet;
2238 TIDSortedElemSet::iterator itElem;
2240 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2241 int fId = FindShape( *itElem );
2242 // check that corresponding submesh exists and a shape is face
2244 faceIdSet.find( fId ) == faceIdSet.end() &&
2245 aMesh->MeshElements( fId )) {
2246 TopoDS_Shape F = aMesh->IndexToShape( fId );
2247 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2248 faceIdSet.insert( fId );
2251 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2253 // ===============================================
2254 // smooth elements on each TopoDS_Face separately
2255 // ===============================================
2257 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2258 for ( ; fId != faceIdSet.rend(); ++fId ) {
2259 // get face surface and submesh
2260 Handle(Geom_Surface) surface;
2261 SMESHDS_SubMesh* faceSubMesh = 0;
2263 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2264 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2265 bool isUPeriodic = false, isVPeriodic = false;
2267 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2268 surface = BRep_Tool::Surface( face );
2269 faceSubMesh = aMesh->MeshElements( *fId );
2270 fToler2 = BRep_Tool::Tolerance( face );
2271 fToler2 *= fToler2 * 10.;
2272 isUPeriodic = surface->IsUPeriodic();
2274 vPeriod = surface->UPeriod();
2275 isVPeriodic = surface->IsVPeriodic();
2277 uPeriod = surface->VPeriod();
2278 surface->Bounds( u1, u2, v1, v2 );
2280 // ---------------------------------------------------------
2281 // for elements on a face, find movable and fixed nodes and
2282 // compute UV for them
2283 // ---------------------------------------------------------
2284 bool checkBoundaryNodes = false;
2285 bool isQuadratic = false;
2286 set<const SMDS_MeshNode*> setMovableNodes;
2287 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2288 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2289 list< const SMDS_MeshElement* > elemsOnFace;
2291 Extrema_GenExtPS projector;
2292 GeomAdaptor_Surface surfAdaptor;
2293 if ( !surface.IsNull() ) {
2294 surfAdaptor.Load( surface );
2295 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2297 int nbElemOnFace = 0;
2298 itElem = theElems.begin();
2299 // loop on not yet smoothed elements: look for elems on a face
2300 while ( itElem != theElems.end() ) {
2301 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2302 break; // all elements found
2304 const SMDS_MeshElement* elem = *itElem;
2305 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2306 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2310 elemsOnFace.push_back( elem );
2311 theElems.erase( itElem++ );
2315 isQuadratic = elem->IsQuadratic();
2317 // get movable nodes of elem
2318 const SMDS_MeshNode* node;
2319 SMDS_TypeOfPosition posType;
2320 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2321 int nn = 0, nbn = elem->NbNodes();
2322 if(elem->IsQuadratic())
2324 while ( nn++ < nbn ) {
2325 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2326 const SMDS_PositionPtr& pos = node->GetPosition();
2327 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2328 if (posType != SMDS_TOP_EDGE &&
2329 posType != SMDS_TOP_VERTEX &&
2330 theFixedNodes.find( node ) == theFixedNodes.end())
2332 // check if all faces around the node are on faceSubMesh
2333 // because a node on edge may be bound to face
2334 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2336 if ( faceSubMesh ) {
2337 while ( eIt->more() && all ) {
2338 const SMDS_MeshElement* e = eIt->next();
2339 all = faceSubMesh->Contains( e );
2343 setMovableNodes.insert( node );
2345 checkBoundaryNodes = true;
2347 if ( posType == SMDS_TOP_3DSPACE )
2348 checkBoundaryNodes = true;
2351 if ( surface.IsNull() )
2354 // get nodes to check UV
2355 list< const SMDS_MeshNode* > uvCheckNodes;
2356 itN = elem->nodesIterator();
2357 nn = 0; nbn = elem->NbNodes();
2358 if(elem->IsQuadratic())
2360 while ( nn++ < nbn ) {
2361 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2362 if ( uvMap.find( node ) == uvMap.end() )
2363 uvCheckNodes.push_back( node );
2364 // add nodes of elems sharing node
2365 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2366 // while ( eIt->more() ) {
2367 // const SMDS_MeshElement* e = eIt->next();
2368 // if ( e != elem ) {
2369 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2370 // while ( nIt->more() ) {
2371 // const SMDS_MeshNode* n =
2372 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2373 // if ( uvMap.find( n ) == uvMap.end() )
2374 // uvCheckNodes.push_back( n );
2380 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2381 for ( ; n != uvCheckNodes.end(); ++n ) {
2384 const SMDS_PositionPtr& pos = node->GetPosition();
2385 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2387 switch ( posType ) {
2388 case SMDS_TOP_FACE: {
2389 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2390 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2393 case SMDS_TOP_EDGE: {
2394 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2395 Handle(Geom2d_Curve) pcurve;
2396 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2397 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2398 if ( !pcurve.IsNull() ) {
2399 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2400 uv = pcurve->Value( u ).XY();
2404 case SMDS_TOP_VERTEX: {
2405 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2406 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2407 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2412 // check existing UV
2413 bool project = true;
2414 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2415 double dist1 = DBL_MAX, dist2 = 0;
2416 if ( posType != SMDS_TOP_3DSPACE ) {
2417 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2418 project = dist1 > fToler2;
2420 if ( project ) { // compute new UV
2422 if ( !getClosestUV( projector, pNode, newUV )) {
2423 MESSAGE("Node Projection Failed " << node);
2427 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2429 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2431 if ( posType != SMDS_TOP_3DSPACE )
2432 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2433 if ( dist2 < dist1 )
2437 // store UV in the map
2438 listUV.push_back( uv );
2439 uvMap.insert( make_pair( node, &listUV.back() ));
2441 } // loop on not yet smoothed elements
2443 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2444 checkBoundaryNodes = true;
2446 // fix nodes on mesh boundary
2448 if ( checkBoundaryNodes ) {
2449 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2450 map< NLink, int >::iterator link_nb;
2451 // put all elements links to linkNbMap
2452 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2453 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2454 const SMDS_MeshElement* elem = (*elemIt);
2455 int nbn = elem->NbNodes();
2456 if(elem->IsQuadratic())
2458 // loop on elem links: insert them in linkNbMap
2459 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2460 for ( int iN = 0; iN < nbn; ++iN ) {
2461 curNode = elem->GetNode( iN );
2463 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2464 else link = make_pair( prevNode , curNode );
2466 link_nb = linkNbMap.find( link );
2467 if ( link_nb == linkNbMap.end() )
2468 linkNbMap.insert( make_pair ( link, 1 ));
2473 // remove nodes that are in links encountered only once from setMovableNodes
2474 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2475 if ( link_nb->second == 1 ) {
2476 setMovableNodes.erase( link_nb->first.first );
2477 setMovableNodes.erase( link_nb->first.second );
2482 // -----------------------------------------------------
2483 // for nodes on seam edge, compute one more UV ( uvMap2 );
2484 // find movable nodes linked to nodes on seam and which
2485 // are to be smoothed using the second UV ( uvMap2 )
2486 // -----------------------------------------------------
2488 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2489 if ( !surface.IsNull() ) {
2490 TopExp_Explorer eExp( face, TopAbs_EDGE );
2491 for ( ; eExp.More(); eExp.Next() ) {
2492 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2493 if ( !BRep_Tool::IsClosed( edge, face ))
2495 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2496 if ( !sm ) continue;
2497 // find out which parameter varies for a node on seam
2500 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2501 if ( pcurve.IsNull() ) continue;
2502 uv1 = pcurve->Value( f );
2504 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2505 if ( pcurve.IsNull() ) continue;
2506 uv2 = pcurve->Value( f );
2507 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2509 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2510 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2512 // get nodes on seam and its vertices
2513 list< const SMDS_MeshNode* > seamNodes;
2514 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2515 while ( nSeamIt->more() ) {
2516 const SMDS_MeshNode* node = nSeamIt->next();
2517 if ( !isQuadratic || !IsMedium( node ))
2518 seamNodes.push_back( node );
2520 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2521 for ( ; vExp.More(); vExp.Next() ) {
2522 sm = aMesh->MeshElements( vExp.Current() );
2524 nSeamIt = sm->GetNodes();
2525 while ( nSeamIt->more() )
2526 seamNodes.push_back( nSeamIt->next() );
2529 // loop on nodes on seam
2530 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2531 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2532 const SMDS_MeshNode* nSeam = *noSeIt;
2533 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2534 if ( n_uv == uvMap.end() )
2537 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2538 // set the second UV
2539 listUV.push_back( *n_uv->second );
2540 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2541 if ( uvMap2.empty() )
2542 uvMap2 = uvMap; // copy the uvMap contents
2543 uvMap2[ nSeam ] = &listUV.back();
2545 // collect movable nodes linked to ones on seam in nodesNearSeam
2546 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2547 while ( eIt->more() ) {
2548 const SMDS_MeshElement* e = eIt->next();
2549 int nbUseMap1 = 0, nbUseMap2 = 0;
2550 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2551 int nn = 0, nbn = e->NbNodes();
2552 if(e->IsQuadratic()) nbn = nbn/2;
2553 while ( nn++ < nbn )
2555 const SMDS_MeshNode* n =
2556 static_cast<const SMDS_MeshNode*>( nIt->next() );
2558 setMovableNodes.find( n ) == setMovableNodes.end() )
2560 // add only nodes being closer to uv2 than to uv1
2561 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2562 0.5 * ( n->Y() + nSeam->Y() ),
2563 0.5 * ( n->Z() + nSeam->Z() ));
2565 getClosestUV( projector, pMid, uv );
2566 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2567 nodesNearSeam.insert( n );
2573 // for centroidalSmooth all element nodes must
2574 // be on one side of a seam
2575 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2576 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2578 while ( nn++ < nbn ) {
2579 const SMDS_MeshNode* n =
2580 static_cast<const SMDS_MeshNode*>( nIt->next() );
2581 setMovableNodes.erase( n );
2585 } // loop on nodes on seam
2586 } // loop on edge of a face
2587 } // if ( !face.IsNull() )
2589 if ( setMovableNodes.empty() ) {
2590 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2591 continue; // goto next face
2599 double maxRatio = -1., maxDisplacement = -1.;
2600 set<const SMDS_MeshNode*>::iterator nodeToMove;
2601 for ( it = 0; it < theNbIterations; it++ ) {
2602 maxDisplacement = 0.;
2603 nodeToMove = setMovableNodes.begin();
2604 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2605 const SMDS_MeshNode* node = (*nodeToMove);
2606 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2609 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2610 if ( theSmoothMethod == LAPLACIAN )
2611 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2613 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2615 // node displacement
2616 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2617 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2618 if ( aDispl > maxDisplacement )
2619 maxDisplacement = aDispl;
2621 // no node movement => exit
2622 //if ( maxDisplacement < 1.e-16 ) {
2623 if ( maxDisplacement < disttol ) {
2624 MESSAGE("-- no node movement --");
2628 // check elements quality
2630 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2631 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2632 const SMDS_MeshElement* elem = (*elemIt);
2633 if ( !elem || elem->GetType() != SMDSAbs_Face )
2635 SMESH::Controls::TSequenceOfXYZ aPoints;
2636 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2637 double aValue = aQualityFunc.GetValue( aPoints );
2638 if ( aValue > maxRatio )
2642 if ( maxRatio <= theTgtAspectRatio ) {
2643 MESSAGE("-- quality achived --");
2646 if (it+1 == theNbIterations) {
2647 MESSAGE("-- Iteration limit exceeded --");
2649 } // smoothing iterations
2651 MESSAGE(" Face id: " << *fId <<
2652 " Nb iterstions: " << it <<
2653 " Displacement: " << maxDisplacement <<
2654 " Aspect Ratio " << maxRatio);
2656 // ---------------------------------------
2657 // new nodes positions are computed,
2658 // record movement in DS and set new UV
2659 // ---------------------------------------
2660 nodeToMove = setMovableNodes.begin();
2661 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2662 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2663 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2664 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2665 if ( node_uv != uvMap.end() ) {
2666 gp_XY* uv = node_uv->second;
2668 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2672 // move medium nodes of quadratic elements
2675 SMESH_MesherHelper helper( *GetMesh() );
2676 if ( !face.IsNull() )
2677 helper.SetSubShape( face );
2678 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2679 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2680 const SMDS_QuadraticFaceOfNodes* QF =
2681 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2683 vector<const SMDS_MeshNode*> Ns;
2684 Ns.reserve(QF->NbNodes()+1);
2685 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2686 while ( anIter->more() )
2687 Ns.push_back( anIter->next() );
2688 Ns.push_back( Ns[0] );
2690 for(int i=0; i<QF->NbNodes(); i=i+2) {
2691 if ( !surface.IsNull() ) {
2692 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2693 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2694 gp_XY uv = ( uv1 + uv2 ) / 2.;
2695 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2696 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2699 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2700 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2701 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2703 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2704 fabs( Ns[i+1]->Y() - y ) > disttol ||
2705 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2706 // we have to move i+1 node
2707 aMesh->MoveNode( Ns[i+1], x, y, z );
2714 } // loop on face ids
2718 //=======================================================================
2719 //function : isReverse
2720 //purpose : Return true if normal of prevNodes is not co-directied with
2721 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2722 // iNotSame is where prevNodes and nextNodes are different
2723 //=======================================================================
2725 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2726 vector<const SMDS_MeshNode*> nextNodes,
2730 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2731 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2733 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2734 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2735 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2736 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2738 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2739 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2740 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2741 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2743 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2745 return (vA ^ vB) * vN < 0.0;
2748 //=======================================================================
2750 * \brief Create elements by sweeping an element
2751 * \param elem - element to sweep
2752 * \param newNodesItVec - nodes generated from each node of the element
2753 * \param newElems - generated elements
2754 * \param nbSteps - number of sweeping steps
2755 * \param srcElements - to append elem for each generated element
2757 //=======================================================================
2759 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2760 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2761 list<const SMDS_MeshElement*>& newElems,
2763 SMESH_SequenceOfElemPtr& srcElements)
2765 SMESHDS_Mesh* aMesh = GetMeshDS();
2767 // Loop on elem nodes:
2768 // find new nodes and detect same nodes indices
2769 int nbNodes = elem->NbNodes();
2770 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2771 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2772 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2773 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2775 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2776 vector<int> sames(nbNodes);
2777 vector<bool> issimple(nbNodes);
2779 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2780 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2781 const SMDS_MeshNode* node = nnIt->first;
2782 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2783 if ( listNewNodes.empty() ) {
2787 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2789 itNN[ iNode ] = listNewNodes.begin();
2790 prevNod[ iNode ] = node;
2791 nextNod[ iNode ] = listNewNodes.front();
2792 if( !elem->IsQuadratic() || !issimple[iNode] ) {
2793 if ( prevNod[ iNode ] != nextNod [ iNode ])
2794 iNotSameNode = iNode;
2798 sames[nbSame++] = iNode;
2803 //cout<<" nbSame = "<<nbSame<<endl;
2804 if ( nbSame == nbNodes || nbSame > 2) {
2805 MESSAGE( " Too many same nodes of element " << elem->GetID() );
2806 //INFOS( " Too many same nodes of element " << elem->GetID() );
2810 // if( elem->IsQuadratic() && nbSame>0 ) {
2811 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2815 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2816 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2818 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2819 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2820 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2824 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2825 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2826 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2827 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2829 // check element orientation
2831 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2832 //MESSAGE("Reversed elem " << elem );
2836 std::swap( iBeforeSame, iAfterSame );
2839 // make new elements
2840 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
2842 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2843 if(issimple[iNode]) {
2844 nextNod[ iNode ] = *itNN[ iNode ];
2848 if( elem->GetType()==SMDSAbs_Node ) {
2849 // we have to use two nodes
2850 midlNod[ iNode ] = *itNN[ iNode ];
2852 nextNod[ iNode ] = *itNN[ iNode ];
2855 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
2856 // we have to use each second node
2858 nextNod[ iNode ] = *itNN[ iNode ];
2862 // we have to use two nodes
2863 midlNod[ iNode ] = *itNN[ iNode ];
2865 nextNod[ iNode ] = *itNN[ iNode ];
2870 SMDS_MeshElement* aNewElem = 0;
2871 if(!elem->IsPoly()) {
2872 switch ( nbNodes ) {
2876 if ( nbSame == 0 ) {
2878 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
2880 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
2886 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2887 nextNod[ 1 ], nextNod[ 0 ] );
2889 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
2890 nextNod[ iNotSameNode ] );
2894 case 3: { // TRIANGLE or quadratic edge
2895 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
2897 if ( nbSame == 0 ) // --- pentahedron
2898 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2899 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
2901 else if ( nbSame == 1 ) // --- pyramid
2902 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2903 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2904 nextNod[ iSameNode ]);
2906 else // 2 same nodes: --- tetrahedron
2907 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
2908 nextNod[ iNotSameNode ]);
2910 else { // quadratic edge
2911 if(nbSame==0) { // quadratic quadrangle
2912 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
2913 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
2915 else if(nbSame==1) { // quadratic triangle
2917 return; // medium node on axis
2919 else if(sames[0]==0) {
2920 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
2921 nextNod[2], midlNod[1], prevNod[2]);
2923 else { // sames[0]==1
2924 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
2925 midlNod[0], nextNod[2], prevNod[2]);
2934 case 4: { // QUADRANGLE
2936 if ( nbSame == 0 ) // --- hexahedron
2937 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
2938 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
2940 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
2941 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
2942 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
2943 nextNod[ iSameNode ]);
2944 newElems.push_back( aNewElem );
2945 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
2946 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
2947 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
2949 else if ( nbSame == 2 ) { // pentahedron
2950 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
2951 // iBeforeSame is same too
2952 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
2953 nextNod[ iOpposSame ], prevNod[ iSameNode ],
2954 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
2956 // iAfterSame is same too
2957 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
2958 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
2959 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
2963 case 6: { // quadratic triangle
2964 // create pentahedron with 15 nodes
2966 if(i0>0) { // reversed case
2967 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
2968 nextNod[0], nextNod[2], nextNod[1],
2969 prevNod[5], prevNod[4], prevNod[3],
2970 nextNod[5], nextNod[4], nextNod[3],
2971 midlNod[0], midlNod[2], midlNod[1]);
2973 else { // not reversed case
2974 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
2975 nextNod[0], nextNod[1], nextNod[2],
2976 prevNod[3], prevNod[4], prevNod[5],
2977 nextNod[3], nextNod[4], nextNod[5],
2978 midlNod[0], midlNod[1], midlNod[2]);
2981 else if(nbSame==1) {
2982 // 2d order pyramid of 13 nodes
2983 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
2984 // int n12,int n23,int n34,int n41,
2985 // int n15,int n25,int n35,int n45, int ID);
2987 int n1,n4,n41,n15,n45;
2988 if(i0>0) { // reversed case
2989 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
2990 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
2996 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
2997 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3002 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3003 nextNod[n4], prevNod[n4], prevNod[n5],
3004 midlNod[n1], nextNod[n41],
3005 midlNod[n4], prevNod[n41],
3006 prevNod[n15], nextNod[n15],
3007 nextNod[n45], prevNod[n45]);
3009 else if(nbSame==2) {
3010 // 2d order tetrahedron of 10 nodes
3011 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3012 // int n12,int n23,int n31,
3013 // int n14,int n24,int n34, int ID);
3014 int n1 = iNotSameNode;
3015 int n2,n3,n12,n23,n31;
3016 if(i0>0) { // reversed case
3017 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3018 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3024 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3025 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3030 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3031 prevNod[n12], prevNod[n23], prevNod[n31],
3032 midlNod[n1], nextNod[n12], nextNod[n31]);
3036 case 8: { // quadratic quadrangle
3038 // create hexahedron with 20 nodes
3039 if(i0>0) { // reversed case
3040 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3041 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3042 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3043 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3044 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3046 else { // not reversed case
3047 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3048 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3049 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3050 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3051 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3054 else if(nbSame==1) {
3055 // --- pyramid + pentahedron - can not be created since it is needed
3056 // additional middle node ot the center of face
3057 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3060 else if(nbSame==2) {
3061 // 2d order Pentahedron with 15 nodes
3062 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3063 // int n12,int n23,int n31,int n45,int n56,int n64,
3064 // int n14,int n25,int n36, int ID);
3066 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3067 // iBeforeSame is same too
3074 // iAfterSame is same too
3080 int n12,n45,n14,n25;
3081 if(i0>0) { //reversed case
3093 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3094 prevNod[n4], prevNod[n5], nextNod[n5],
3095 prevNod[n12], midlNod[n2], nextNod[n12],
3096 prevNod[n45], midlNod[n5], nextNod[n45],
3097 prevNod[n14], prevNod[n25], nextNod[n25]);
3102 // realized for extrusion only
3103 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3104 //vector<int> quantities (nbNodes + 2);
3106 //quantities[0] = nbNodes; // bottom of prism
3107 //for (int inode = 0; inode < nbNodes; inode++) {
3108 // polyedre_nodes[inode] = prevNod[inode];
3111 //quantities[1] = nbNodes; // top of prism
3112 //for (int inode = 0; inode < nbNodes; inode++) {
3113 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3116 //for (int iface = 0; iface < nbNodes; iface++) {
3117 // quantities[iface + 2] = 4;
3118 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3119 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3120 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3121 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3122 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3124 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3131 // realized for extrusion only
3132 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3133 vector<int> quantities (nbNodes + 2);
3135 quantities[0] = nbNodes; // bottom of prism
3136 for (int inode = 0; inode < nbNodes; inode++) {
3137 polyedre_nodes[inode] = prevNod[inode];
3140 quantities[1] = nbNodes; // top of prism
3141 for (int inode = 0; inode < nbNodes; inode++) {
3142 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3145 for (int iface = 0; iface < nbNodes; iface++) {
3146 quantities[iface + 2] = 4;
3147 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3148 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3149 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3150 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3151 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3153 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3157 newElems.push_back( aNewElem );
3158 myLastCreatedElems.Append(aNewElem);
3159 srcElements.Append( elem );
3162 // set new prev nodes
3163 for ( iNode = 0; iNode < nbNodes; iNode++ )
3164 prevNod[ iNode ] = nextNod[ iNode ];
3169 //=======================================================================
3171 * \brief Create 1D and 2D elements around swept elements
3172 * \param mapNewNodes - source nodes and ones generated from them
3173 * \param newElemsMap - source elements and ones generated from them
3174 * \param elemNewNodesMap - nodes generated from each node of each element
3175 * \param elemSet - all swept elements
3176 * \param nbSteps - number of sweeping steps
3177 * \param srcElements - to append elem for each generated element
3179 //=======================================================================
3181 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3182 TElemOfElemListMap & newElemsMap,
3183 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3184 TIDSortedElemSet& elemSet,
3186 SMESH_SequenceOfElemPtr& srcElements)
3188 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3189 SMESHDS_Mesh* aMesh = GetMeshDS();
3191 // Find nodes belonging to only one initial element - sweep them to get edges.
3193 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3194 for ( ; nList != mapNewNodes.end(); nList++ ) {
3195 const SMDS_MeshNode* node =
3196 static_cast<const SMDS_MeshNode*>( nList->first );
3197 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3198 int nbInitElems = 0;
3199 const SMDS_MeshElement* el = 0;
3200 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3201 while ( eIt->more() && nbInitElems < 2 ) {
3203 SMDSAbs_ElementType type = el->GetType();
3204 if ( type == SMDSAbs_Volume || type < highType ) continue;
3205 if ( type > highType ) {
3209 if ( elemSet.find(el) != elemSet.end() )
3212 if ( nbInitElems < 2 ) {
3213 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3214 if(!NotCreateEdge) {
3215 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3216 list<const SMDS_MeshElement*> newEdges;
3217 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3222 // Make a ceiling for each element ie an equal element of last new nodes.
3223 // Find free links of faces - make edges and sweep them into faces.
3225 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3226 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3227 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3228 const SMDS_MeshElement* elem = itElem->first;
3229 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3231 if ( elem->GetType() == SMDSAbs_Edge ) {
3232 // create a ceiling edge
3233 if (!elem->IsQuadratic()) {
3234 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3235 vecNewNodes[ 1 ]->second.back())) {
3236 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3237 vecNewNodes[ 1 ]->second.back()));
3238 srcElements.Append( myLastCreatedElems.Last() );
3242 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3243 vecNewNodes[ 1 ]->second.back(),
3244 vecNewNodes[ 2 ]->second.back())) {
3245 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3246 vecNewNodes[ 1 ]->second.back(),
3247 vecNewNodes[ 2 ]->second.back()));
3248 srcElements.Append( myLastCreatedElems.Last() );
3252 if ( elem->GetType() != SMDSAbs_Face )
3255 if(itElem->second.size()==0) continue;
3257 bool hasFreeLinks = false;
3259 TIDSortedElemSet avoidSet;
3260 avoidSet.insert( elem );
3262 set<const SMDS_MeshNode*> aFaceLastNodes;
3263 int iNode, nbNodes = vecNewNodes.size();
3264 if(!elem->IsQuadratic()) {
3265 // loop on the face nodes
3266 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3267 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3268 // look for free links of the face
3269 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3270 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3271 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3272 // check if a link is free
3273 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3274 hasFreeLinks = true;
3275 // make an edge and a ceiling for a new edge
3276 if ( !aMesh->FindEdge( n1, n2 )) {
3277 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3278 srcElements.Append( myLastCreatedElems.Last() );
3280 n1 = vecNewNodes[ iNode ]->second.back();
3281 n2 = vecNewNodes[ iNext ]->second.back();
3282 if ( !aMesh->FindEdge( n1, n2 )) {
3283 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3284 srcElements.Append( myLastCreatedElems.Last() );
3289 else { // elem is quadratic face
3290 int nbn = nbNodes/2;
3291 for ( iNode = 0; iNode < nbn; iNode++ ) {
3292 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3293 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3294 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3295 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3296 // check if a link is free
3297 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3298 hasFreeLinks = true;
3299 // make an edge and a ceiling for a new edge
3301 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3302 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3303 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3304 srcElements.Append( myLastCreatedElems.Last() );
3306 n1 = vecNewNodes[ iNode ]->second.back();
3307 n2 = vecNewNodes[ iNext ]->second.back();
3308 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3309 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3310 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3311 srcElements.Append( myLastCreatedElems.Last() );
3315 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3316 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3320 // sweep free links into faces
3322 if ( hasFreeLinks ) {
3323 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3324 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3326 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3327 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3328 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3329 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3331 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3332 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3334 while ( iVol++ < volNb ) v++;
3335 // find indices of free faces of a volume and their source edges
3336 list< int > freeInd;
3337 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3338 SMDS_VolumeTool vTool( *v );
3339 int iF, nbF = vTool.NbFaces();
3340 for ( iF = 0; iF < nbF; iF ++ ) {
3341 if (vTool.IsFreeFace( iF ) &&
3342 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3343 initNodeSet != faceNodeSet) // except an initial face
3345 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3347 freeInd.push_back( iF );
3348 // find source edge of a free face iF
3349 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3350 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3351 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3352 initNodeSet.begin(), initNodeSet.end(),
3353 commonNodes.begin());
3354 if ( (*v)->IsQuadratic() )
3355 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3357 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3359 if ( !srcEdges.back() )
3361 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3362 << iF << " of volume #" << vTool.ID() << endl;
3367 if ( freeInd.empty() )
3370 // create faces for all steps;
3371 // if such a face has been already created by sweep of edge,
3372 // assure that its orientation is OK
3373 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3375 vTool.SetExternalNormal();
3376 list< int >::iterator ind = freeInd.begin();
3377 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3378 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3380 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3381 int nbn = vTool.NbFaceNodes( *ind );
3383 case 3: { ///// triangle
3384 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3386 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3387 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3388 aMesh->ChangeElementNodes( f, nodes, nbn );
3391 case 4: { ///// quadrangle
3392 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3394 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3395 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3396 aMesh->ChangeElementNodes( f, nodes, nbn );
3400 if( (*v)->IsQuadratic() ) {
3401 if(nbn==6) { /////// quadratic triangle
3402 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3403 nodes[1], nodes[3], nodes[5] );
3405 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3406 nodes[1], nodes[3], nodes[5]));
3408 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3409 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3410 tmpnodes[0] = nodes[0];
3411 tmpnodes[1] = nodes[2];
3412 tmpnodes[2] = nodes[4];
3413 tmpnodes[3] = nodes[1];
3414 tmpnodes[4] = nodes[3];
3415 tmpnodes[5] = nodes[5];
3416 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3419 else { /////// quadratic quadrangle
3420 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3421 nodes[1], nodes[3], nodes[5], nodes[7] );
3423 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3424 nodes[1], nodes[3], nodes[5], nodes[7]));
3426 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3427 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3428 tmpnodes[0] = nodes[0];
3429 tmpnodes[1] = nodes[2];
3430 tmpnodes[2] = nodes[4];
3431 tmpnodes[3] = nodes[6];
3432 tmpnodes[4] = nodes[1];
3433 tmpnodes[5] = nodes[3];
3434 tmpnodes[6] = nodes[5];
3435 tmpnodes[7] = nodes[7];
3436 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3440 else { //////// polygon
3441 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3442 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3444 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3445 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3446 aMesh->ChangeElementNodes( f, nodes, nbn );
3449 while ( srcElements.Length() < myLastCreatedElems.Length() )
3450 srcElements.Append( *srcEdge );
3452 } // loop on free faces
3454 // go to the next volume
3456 while ( iVol++ < nbVolumesByStep ) v++;
3459 } // sweep free links into faces
3461 // Make a ceiling face with a normal external to a volume
3463 SMDS_VolumeTool lastVol( itElem->second.back() );
3465 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3467 lastVol.SetExternalNormal();
3468 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3469 int nbn = lastVol.NbFaceNodes( iF );
3472 if (!hasFreeLinks ||
3473 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3474 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3477 if (!hasFreeLinks ||
3478 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3479 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3482 if(itElem->second.back()->IsQuadratic()) {
3484 if (!hasFreeLinks ||
3485 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3486 nodes[1], nodes[3], nodes[5]) ) {
3487 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3488 nodes[1], nodes[3], nodes[5]));
3492 if (!hasFreeLinks ||
3493 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3494 nodes[1], nodes[3], nodes[5], nodes[7]) )
3495 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3496 nodes[1], nodes[3], nodes[5], nodes[7]));
3500 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3501 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3502 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3506 while ( srcElements.Length() < myLastCreatedElems.Length() )
3507 srcElements.Append( myLastCreatedElems.Last() );
3509 } // loop on swept elements
3512 //=======================================================================
3513 //function : RotationSweep
3515 //=======================================================================
3517 SMESH_MeshEditor::PGroupIDs
3518 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3519 const gp_Ax1& theAxis,
3520 const double theAngle,
3521 const int theNbSteps,
3522 const double theTol,
3523 const bool theMakeGroups,
3524 const bool theMakeWalls)
3526 myLastCreatedElems.Clear();
3527 myLastCreatedNodes.Clear();
3529 // source elements for each generated one
3530 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3532 MESSAGE( "RotationSweep()");
3534 aTrsf.SetRotation( theAxis, theAngle );
3536 aTrsf2.SetRotation( theAxis, theAngle/2. );
3538 gp_Lin aLine( theAxis );
3539 double aSqTol = theTol * theTol;
3541 SMESHDS_Mesh* aMesh = GetMeshDS();
3543 TNodeOfNodeListMap mapNewNodes;
3544 TElemOfVecOfNnlmiMap mapElemNewNodes;
3545 TElemOfElemListMap newElemsMap;
3548 TIDSortedElemSet::iterator itElem;
3549 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3550 const SMDS_MeshElement* elem = *itElem;
3551 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3553 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3554 newNodesItVec.reserve( elem->NbNodes() );
3556 // loop on elem nodes
3557 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3558 while ( itN->more() ) {
3559 // check if a node has been already sweeped
3560 const SMDS_MeshNode* node = cast2Node( itN->next() );
3562 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3564 aXYZ.Coord( coord[0], coord[1], coord[2] );
3565 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3567 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3568 if ( nIt == mapNewNodes.end() ) {
3569 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3570 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3573 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3575 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3576 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3577 const SMDS_MeshNode * newNode = node;
3578 for ( int i = 0; i < theNbSteps; i++ ) {
3580 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3582 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3583 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3584 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3585 myLastCreatedNodes.Append(newNode);
3586 srcNodes.Append( node );
3587 listNewNodes.push_back( newNode );
3588 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3589 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3592 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3594 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3595 myLastCreatedNodes.Append(newNode);
3596 srcNodes.Append( node );
3597 listNewNodes.push_back( newNode );
3600 listNewNodes.push_back( newNode );
3601 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3602 listNewNodes.push_back( newNode );
3609 // if current elem is quadratic and current node is not medium
3610 // we have to check - may be it is needed to insert additional nodes
3611 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3612 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3613 if(listNewNodes.size()==theNbSteps) {
3614 listNewNodes.clear();
3616 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3618 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3619 const SMDS_MeshNode * newNode = node;
3621 for(int i = 0; i<theNbSteps; i++) {
3622 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3623 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3624 cout<<" 3 AddNode: "<<newNode;
3625 myLastCreatedNodes.Append(newNode);
3626 listNewNodes.push_back( newNode );
3627 srcNodes.Append( node );
3628 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3629 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3630 cout<<" 4 AddNode: "<<newNode;
3631 myLastCreatedNodes.Append(newNode);
3632 srcNodes.Append( node );
3633 listNewNodes.push_back( newNode );
3637 listNewNodes.push_back( newNode );
3643 newNodesItVec.push_back( nIt );
3645 // make new elements
3646 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3650 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3652 PGroupIDs newGroupIDs;
3653 if ( theMakeGroups )
3654 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3660 //=======================================================================
3661 //function : CreateNode
3663 //=======================================================================
3664 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3667 const double tolnode,
3668 SMESH_SequenceOfNode& aNodes)
3670 myLastCreatedElems.Clear();
3671 myLastCreatedNodes.Clear();
3674 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3676 // try to search in sequence of existing nodes
3677 // if aNodes.Length()>0 we 'nave to use given sequence
3678 // else - use all nodes of mesh
3679 if(aNodes.Length()>0) {
3681 for(i=1; i<=aNodes.Length(); i++) {
3682 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3683 if(P1.Distance(P2)<tolnode)
3684 return aNodes.Value(i);
3688 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3689 while(itn->more()) {
3690 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3691 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3692 if(P1.Distance(P2)<tolnode)
3697 // create new node and return it
3698 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3699 myLastCreatedNodes.Append(NewNode);
3704 //=======================================================================
3705 //function : ExtrusionSweep
3707 //=======================================================================
3709 SMESH_MeshEditor::PGroupIDs
3710 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3711 const gp_Vec& theStep,
3712 const int theNbSteps,
3713 TElemOfElemListMap& newElemsMap,
3714 const bool theMakeGroups,
3716 const double theTolerance)
3718 ExtrusParam aParams;
3719 aParams.myDir = gp_Dir(theStep);
3720 aParams.myNodes.Clear();
3721 aParams.mySteps = new TColStd_HSequenceOfReal;
3723 for(i=1; i<=theNbSteps; i++)
3724 aParams.mySteps->Append(theStep.Magnitude());
3727 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3731 //=======================================================================
3732 //function : ExtrusionSweep
3734 //=======================================================================
3736 SMESH_MeshEditor::PGroupIDs
3737 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3738 ExtrusParam& theParams,
3739 TElemOfElemListMap& newElemsMap,
3740 const bool theMakeGroups,
3742 const double theTolerance)
3744 myLastCreatedElems.Clear();
3745 myLastCreatedNodes.Clear();
3747 // source elements for each generated one
3748 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3750 SMESHDS_Mesh* aMesh = GetMeshDS();
3752 int nbsteps = theParams.mySteps->Length();
3754 TNodeOfNodeListMap mapNewNodes;
3755 //TNodeOfNodeVecMap mapNewNodes;
3756 TElemOfVecOfNnlmiMap mapElemNewNodes;
3757 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3760 TIDSortedElemSet::iterator itElem;
3761 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3762 // check element type
3763 const SMDS_MeshElement* elem = *itElem;
3764 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3767 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3768 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3769 newNodesItVec.reserve( elem->NbNodes() );
3771 // loop on elem nodes
3772 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3773 while ( itN->more() )
3775 // check if a node has been already sweeped
3776 const SMDS_MeshNode* node = cast2Node( itN->next() );
3777 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3778 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3779 if ( nIt == mapNewNodes.end() ) {
3780 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3781 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3782 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3783 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3784 //vecNewNodes.reserve(nbsteps);
3787 double coord[] = { node->X(), node->Y(), node->Z() };
3788 //int nbsteps = theParams.mySteps->Length();
3789 for ( int i = 0; i < nbsteps; i++ ) {
3790 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3791 // create additional node
3792 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3793 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3794 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3795 if( theFlags & EXTRUSION_FLAG_SEW ) {
3796 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3797 theTolerance, theParams.myNodes);
3798 listNewNodes.push_back( newNode );
3801 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3802 myLastCreatedNodes.Append(newNode);
3803 srcNodes.Append( node );
3804 listNewNodes.push_back( newNode );
3807 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3808 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3809 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3810 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3811 if( theFlags & EXTRUSION_FLAG_SEW ) {
3812 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3813 theTolerance, theParams.myNodes);
3814 listNewNodes.push_back( newNode );
3815 //vecNewNodes[i]=newNode;
3818 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3819 myLastCreatedNodes.Append(newNode);
3820 srcNodes.Append( node );
3821 listNewNodes.push_back( newNode );
3822 //vecNewNodes[i]=newNode;
3827 // if current elem is quadratic and current node is not medium
3828 // we have to check - may be it is needed to insert additional nodes
3829 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3830 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3831 if(listNewNodes.size()==nbsteps) {
3832 listNewNodes.clear();
3833 double coord[] = { node->X(), node->Y(), node->Z() };
3834 for ( int i = 0; i < nbsteps; i++ ) {
3835 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3836 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3837 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3838 if( theFlags & EXTRUSION_FLAG_SEW ) {
3839 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3840 theTolerance, theParams.myNodes);
3841 listNewNodes.push_back( newNode );
3844 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3845 myLastCreatedNodes.Append(newNode);
3846 srcNodes.Append( node );
3847 listNewNodes.push_back( newNode );
3849 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3850 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3851 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3852 if( theFlags & EXTRUSION_FLAG_SEW ) {
3853 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3854 theTolerance, theParams.myNodes);
3855 listNewNodes.push_back( newNode );
3858 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3859 myLastCreatedNodes.Append(newNode);
3860 srcNodes.Append( node );
3861 listNewNodes.push_back( newNode );
3867 newNodesItVec.push_back( nIt );
3869 // make new elements
3870 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
3873 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
3874 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
3876 PGroupIDs newGroupIDs;
3877 if ( theMakeGroups )
3878 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
3884 //=======================================================================
3885 //class : SMESH_MeshEditor_PathPoint
3886 //purpose : auxiliary class
3887 //=======================================================================
3888 class SMESH_MeshEditor_PathPoint {
3890 SMESH_MeshEditor_PathPoint() {
3891 myPnt.SetCoord(99., 99., 99.);
3892 myTgt.SetCoord(1.,0.,0.);
3896 void SetPnt(const gp_Pnt& aP3D){
3899 void SetTangent(const gp_Dir& aTgt){
3902 void SetAngle(const double& aBeta){
3905 void SetParameter(const double& aPrm){
3908 const gp_Pnt& Pnt()const{
3911 const gp_Dir& Tangent()const{
3914 double Angle()const{
3917 double Parameter()const{
3929 //=======================================================================
3930 //function : ExtrusionAlongTrack
3932 //=======================================================================
3933 SMESH_MeshEditor::Extrusion_Error
3934 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
3935 SMESH_subMesh* theTrack,
3936 const SMDS_MeshNode* theN1,
3937 const bool theHasAngles,
3938 list<double>& theAngles,
3939 const bool theLinearVariation,
3940 const bool theHasRefPoint,
3941 const gp_Pnt& theRefPoint,
3942 const bool theMakeGroups)
3944 myLastCreatedElems.Clear();
3945 myLastCreatedNodes.Clear();
3948 std::list<double> aPrms;
3949 TIDSortedElemSet::iterator itElem;
3952 TopoDS_Edge aTrackEdge;
3953 TopoDS_Vertex aV1, aV2;
3955 SMDS_ElemIteratorPtr aItE;
3956 SMDS_NodeIteratorPtr aItN;
3957 SMDSAbs_ElementType aTypeE;
3959 TNodeOfNodeListMap mapNewNodes;
3962 aNbE = theElements.size();
3965 return EXTR_NO_ELEMENTS;
3967 // 1.1 Track Pattern
3970 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
3972 aItE = pSubMeshDS->GetElements();
3973 while ( aItE->more() ) {
3974 const SMDS_MeshElement* pE = aItE->next();
3975 aTypeE = pE->GetType();
3976 // Pattern must contain links only
3977 if ( aTypeE != SMDSAbs_Edge )
3978 return EXTR_PATH_NOT_EDGE;
3981 list<SMESH_MeshEditor_PathPoint> fullList;
3983 const TopoDS_Shape& aS = theTrack->GetSubShape();
3984 // Sub shape for the Pattern must be an Edge or Wire
3985 if( aS.ShapeType() == TopAbs_EDGE ) {
3986 aTrackEdge = TopoDS::Edge( aS );
3987 // the Edge must not be degenerated
3988 if ( BRep_Tool::Degenerated( aTrackEdge ) )
3989 return EXTR_BAD_PATH_SHAPE;
3990 TopExp::Vertices( aTrackEdge, aV1, aV2 );
3991 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
3992 const SMDS_MeshNode* aN1 = aItN->next();
3993 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
3994 const SMDS_MeshNode* aN2 = aItN->next();
3995 // starting node must be aN1 or aN2
3996 if ( !( aN1 == theN1 || aN2 == theN1 ) )
3997 return EXTR_BAD_STARTING_NODE;
3998 aItN = pSubMeshDS->GetNodes();
3999 while ( aItN->more() ) {
4000 const SMDS_MeshNode* pNode = aItN->next();
4001 const SMDS_EdgePosition* pEPos =
4002 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4003 double aT = pEPos->GetUParameter();
4004 aPrms.push_back( aT );
4006 //Extrusion_Error err =
4007 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4009 else if( aS.ShapeType() == TopAbs_WIRE ) {
4010 list< SMESH_subMesh* > LSM;
4011 TopTools_SequenceOfShape Edges;
4012 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4013 while(itSM->more()) {
4014 SMESH_subMesh* SM = itSM->next();
4016 const TopoDS_Shape& aS = SM->GetSubShape();
4019 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4020 int startNid = theN1->GetID();
4021 TColStd_MapOfInteger UsedNums;
4022 int NbEdges = Edges.Length();
4024 for(; i<=NbEdges; i++) {
4026 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4027 for(; itLSM!=LSM.end(); itLSM++) {
4029 if(UsedNums.Contains(k)) continue;
4030 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4031 SMESH_subMesh* locTrack = *itLSM;
4032 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4033 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4034 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4035 const SMDS_MeshNode* aN1 = aItN->next();
4036 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4037 const SMDS_MeshNode* aN2 = aItN->next();
4038 // starting node must be aN1 or aN2
4039 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4040 // 2. Collect parameters on the track edge
4042 aItN = locMeshDS->GetNodes();
4043 while ( aItN->more() ) {
4044 const SMDS_MeshNode* pNode = aItN->next();
4045 const SMDS_EdgePosition* pEPos =
4046 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4047 double aT = pEPos->GetUParameter();
4048 aPrms.push_back( aT );
4050 list<SMESH_MeshEditor_PathPoint> LPP;
4051 //Extrusion_Error err =
4052 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4053 LLPPs.push_back(LPP);
4055 // update startN for search following egde
4056 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4057 else startNid = aN1->GetID();
4061 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4062 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4063 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4064 for(; itPP!=firstList.end(); itPP++) {
4065 fullList.push_back( *itPP );
4067 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4068 fullList.pop_back();
4070 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4071 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4072 itPP = currList.begin();
4073 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4074 gp_Dir D1 = PP1.Tangent();
4075 gp_Dir D2 = PP2.Tangent();
4076 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4077 (D1.Z()+D2.Z())/2 ) );
4078 PP1.SetTangent(Dnew);
4079 fullList.push_back(PP1);
4081 for(; itPP!=firstList.end(); itPP++) {
4082 fullList.push_back( *itPP );
4084 PP1 = fullList.back();
4085 fullList.pop_back();
4087 // if wire not closed
4088 fullList.push_back(PP1);
4092 return EXTR_BAD_PATH_SHAPE;
4095 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4096 theHasRefPoint, theRefPoint, theMakeGroups);
4100 //=======================================================================
4101 //function : ExtrusionAlongTrack
4103 //=======================================================================
4104 SMESH_MeshEditor::Extrusion_Error
4105 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4106 SMESH_Mesh* theTrack,
4107 const SMDS_MeshNode* theN1,
4108 const bool theHasAngles,
4109 list<double>& theAngles,
4110 const bool theLinearVariation,
4111 const bool theHasRefPoint,
4112 const gp_Pnt& theRefPoint,
4113 const bool theMakeGroups)
4115 myLastCreatedElems.Clear();
4116 myLastCreatedNodes.Clear();
4119 std::list<double> aPrms;
4120 TIDSortedElemSet::iterator itElem;
4123 TopoDS_Edge aTrackEdge;
4124 TopoDS_Vertex aV1, aV2;
4126 SMDS_ElemIteratorPtr aItE;
4127 SMDS_NodeIteratorPtr aItN;
4128 SMDSAbs_ElementType aTypeE;
4130 TNodeOfNodeListMap mapNewNodes;
4133 aNbE = theElements.size();
4136 return EXTR_NO_ELEMENTS;
4138 // 1.1 Track Pattern
4141 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4143 aItE = pMeshDS->elementsIterator();
4144 while ( aItE->more() ) {
4145 const SMDS_MeshElement* pE = aItE->next();
4146 aTypeE = pE->GetType();
4147 // Pattern must contain links only
4148 if ( aTypeE != SMDSAbs_Edge )
4149 return EXTR_PATH_NOT_EDGE;
4152 list<SMESH_MeshEditor_PathPoint> fullList;
4154 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4155 // Sub shape for the Pattern must be an Edge or Wire
4156 if( aS.ShapeType() == TopAbs_EDGE ) {
4157 aTrackEdge = TopoDS::Edge( aS );
4158 // the Edge must not be degenerated
4159 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4160 return EXTR_BAD_PATH_SHAPE;
4161 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4162 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4163 const SMDS_MeshNode* aN1 = aItN->next();
4164 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4165 const SMDS_MeshNode* aN2 = aItN->next();
4166 // starting node must be aN1 or aN2
4167 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4168 return EXTR_BAD_STARTING_NODE;
4169 aItN = pMeshDS->nodesIterator();
4170 while ( aItN->more() ) {
4171 const SMDS_MeshNode* pNode = aItN->next();
4172 if( pNode==aN1 || pNode==aN2 ) continue;
4173 const SMDS_EdgePosition* pEPos =
4174 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4175 double aT = pEPos->GetUParameter();
4176 aPrms.push_back( aT );
4178 //Extrusion_Error err =
4179 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4181 else if( aS.ShapeType() == TopAbs_WIRE ) {
4182 list< SMESH_subMesh* > LSM;
4183 TopTools_SequenceOfShape Edges;
4184 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4185 for(; eExp.More(); eExp.Next()) {
4186 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4187 if( BRep_Tool::Degenerated(E) ) continue;
4188 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4194 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4195 int startNid = theN1->GetID();
4196 TColStd_MapOfInteger UsedNums;
4197 int NbEdges = Edges.Length();
4199 for(; i<=NbEdges; i++) {
4201 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4202 for(; itLSM!=LSM.end(); itLSM++) {
4204 if(UsedNums.Contains(k)) continue;
4205 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4206 SMESH_subMesh* locTrack = *itLSM;
4207 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4208 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4209 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4210 const SMDS_MeshNode* aN1 = aItN->next();
4211 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4212 const SMDS_MeshNode* aN2 = aItN->next();
4213 // starting node must be aN1 or aN2
4214 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4215 // 2. Collect parameters on the track edge
4217 aItN = locMeshDS->GetNodes();
4218 while ( aItN->more() ) {
4219 const SMDS_MeshNode* pNode = aItN->next();
4220 const SMDS_EdgePosition* pEPos =
4221 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4222 double aT = pEPos->GetUParameter();
4223 aPrms.push_back( aT );
4225 list<SMESH_MeshEditor_PathPoint> LPP;
4226 //Extrusion_Error err =
4227 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4228 LLPPs.push_back(LPP);
4230 // update startN for search following egde
4231 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4232 else startNid = aN1->GetID();
4236 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4237 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4238 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4239 for(; itPP!=firstList.end(); itPP++) {
4240 fullList.push_back( *itPP );
4242 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4243 fullList.pop_back();
4245 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4246 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4247 itPP = currList.begin();
4248 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4249 gp_Pnt P1 = PP1.Pnt();
4250 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4251 gp_Pnt P2 = PP2.Pnt();
4252 gp_Dir D1 = PP1.Tangent();
4253 gp_Dir D2 = PP2.Tangent();
4254 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4255 (D1.Z()+D2.Z())/2 ) );
4256 PP1.SetTangent(Dnew);
4257 fullList.push_back(PP1);
4259 for(; itPP!=currList.end(); itPP++) {
4260 fullList.push_back( *itPP );
4262 PP1 = fullList.back();
4263 fullList.pop_back();
4265 // if wire not closed
4266 fullList.push_back(PP1);
4270 return EXTR_BAD_PATH_SHAPE;
4273 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4274 theHasRefPoint, theRefPoint, theMakeGroups);
4278 //=======================================================================
4279 //function : MakeEdgePathPoints
4280 //purpose : auxilary for ExtrusionAlongTrack
4281 //=======================================================================
4282 SMESH_MeshEditor::Extrusion_Error
4283 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4284 const TopoDS_Edge& aTrackEdge,
4286 list<SMESH_MeshEditor_PathPoint>& LPP)
4288 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4290 aTolVec2=aTolVec*aTolVec;
4292 TopoDS_Vertex aV1, aV2;
4293 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4294 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4295 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4296 // 2. Collect parameters on the track edge
4297 aPrms.push_front( aT1 );
4298 aPrms.push_back( aT2 );
4301 if( FirstIsStart ) {
4312 SMESH_MeshEditor_PathPoint aPP;
4313 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4314 std::list<double>::iterator aItD = aPrms.begin();
4315 for(; aItD != aPrms.end(); ++aItD) {
4319 aC3D->D1( aT, aP3D, aVec );
4320 aL2 = aVec.SquareMagnitude();
4321 if ( aL2 < aTolVec2 )
4322 return EXTR_CANT_GET_TANGENT;
4323 gp_Dir aTgt( aVec );
4325 aPP.SetTangent( aTgt );
4326 aPP.SetParameter( aT );
4333 //=======================================================================
4334 //function : MakeExtrElements
4335 //purpose : auxilary for ExtrusionAlongTrack
4336 //=======================================================================
4337 SMESH_MeshEditor::Extrusion_Error
4338 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4339 list<SMESH_MeshEditor_PathPoint>& fullList,
4340 const bool theHasAngles,
4341 list<double>& theAngles,
4342 const bool theLinearVariation,
4343 const bool theHasRefPoint,
4344 const gp_Pnt& theRefPoint,
4345 const bool theMakeGroups)
4347 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4348 int aNbTP = fullList.size();
4349 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4351 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4352 LinearAngleVariation(aNbTP-1, theAngles);
4354 vector<double> aAngles( aNbTP );
4356 for(; j<aNbTP; ++j) {
4359 if ( theHasAngles ) {
4361 std::list<double>::iterator aItD = theAngles.begin();
4362 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4364 aAngles[j] = anAngle;
4367 // fill vector of path points with angles
4368 //aPPs.resize(fullList.size());
4370 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4371 for(; itPP!=fullList.end(); itPP++) {
4373 SMESH_MeshEditor_PathPoint PP = *itPP;
4374 PP.SetAngle(aAngles[j]);
4378 TNodeOfNodeListMap mapNewNodes;
4379 TElemOfVecOfNnlmiMap mapElemNewNodes;
4380 TElemOfElemListMap newElemsMap;
4381 TIDSortedElemSet::iterator itElem;
4384 SMDSAbs_ElementType aTypeE;
4385 // source elements for each generated one
4386 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4388 // 3. Center of rotation aV0
4389 gp_Pnt aV0 = theRefPoint;
4391 if ( !theHasRefPoint ) {
4393 aGC.SetCoord( 0.,0.,0. );
4395 itElem = theElements.begin();
4396 for ( ; itElem != theElements.end(); itElem++ ) {
4397 const SMDS_MeshElement* elem = *itElem;
4399 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4400 while ( itN->more() ) {
4401 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4406 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4407 list<const SMDS_MeshNode*> aLNx;
4408 mapNewNodes[node] = aLNx;
4410 gp_XYZ aXYZ( aX, aY, aZ );
4418 } // if (!theHasRefPoint) {
4419 mapNewNodes.clear();
4421 // 4. Processing the elements
4422 SMESHDS_Mesh* aMesh = GetMeshDS();
4424 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4425 // check element type
4426 const SMDS_MeshElement* elem = *itElem;
4427 aTypeE = elem->GetType();
4428 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4431 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4432 newNodesItVec.reserve( elem->NbNodes() );
4434 // loop on elem nodes
4436 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4437 while ( itN->more() )
4440 // check if a node has been already processed
4441 const SMDS_MeshNode* node =
4442 static_cast<const SMDS_MeshNode*>( itN->next() );
4443 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4444 if ( nIt == mapNewNodes.end() ) {
4445 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4446 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4449 aX = node->X(); aY = node->Y(); aZ = node->Z();
4451 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4452 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4453 gp_Ax1 anAx1, anAxT1T0;
4454 gp_Dir aDT1x, aDT0x, aDT1T0;
4459 aPN0.SetCoord(aX, aY, aZ);
4461 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4463 aDT0x= aPP0.Tangent();
4464 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4466 for ( j = 1; j < aNbTP; ++j ) {
4467 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4469 aDT1x = aPP1.Tangent();
4470 aAngle1x = aPP1.Angle();
4472 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4474 gp_Vec aV01x( aP0x, aP1x );
4475 aTrsf.SetTranslation( aV01x );
4478 aV1x = aV0x.Transformed( aTrsf );
4479 aPN1 = aPN0.Transformed( aTrsf );
4481 // rotation 1 [ T1,T0 ]
4482 aAngleT1T0=-aDT1x.Angle( aDT0x );
4483 if (fabs(aAngleT1T0) > aTolAng) {
4485 anAxT1T0.SetLocation( aV1x );
4486 anAxT1T0.SetDirection( aDT1T0 );
4487 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4489 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4493 if ( theHasAngles ) {
4494 anAx1.SetLocation( aV1x );
4495 anAx1.SetDirection( aDT1x );
4496 aTrsfRot.SetRotation( anAx1, aAngle1x );
4498 aPN1 = aPN1.Transformed( aTrsfRot );
4502 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4503 // create additional node
4504 double x = ( aPN1.X() + aPN0.X() )/2.;
4505 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4506 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4507 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4508 myLastCreatedNodes.Append(newNode);
4509 srcNodes.Append( node );
4510 listNewNodes.push_back( newNode );
4515 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4516 myLastCreatedNodes.Append(newNode);
4517 srcNodes.Append( node );
4518 listNewNodes.push_back( newNode );
4528 // if current elem is quadratic and current node is not medium
4529 // we have to check - may be it is needed to insert additional nodes
4530 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4531 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4532 if(listNewNodes.size()==aNbTP-1) {
4533 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4534 gp_XYZ P(node->X(), node->Y(), node->Z());
4535 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4537 for(i=0; i<aNbTP-1; i++) {
4538 const SMDS_MeshNode* N = *it;
4539 double x = ( N->X() + P.X() )/2.;
4540 double y = ( N->Y() + P.Y() )/2.;
4541 double z = ( N->Z() + P.Z() )/2.;
4542 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4543 srcNodes.Append( node );
4544 myLastCreatedNodes.Append(newN);
4547 P = gp_XYZ(N->X(),N->Y(),N->Z());
4549 listNewNodes.clear();
4550 for(i=0; i<2*(aNbTP-1); i++) {
4551 listNewNodes.push_back(aNodes[i]);
4557 newNodesItVec.push_back( nIt );
4559 // make new elements
4560 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4561 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4562 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4565 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4567 if ( theMakeGroups )
4568 generateGroups( srcNodes, srcElems, "extruded");
4574 //=======================================================================
4575 //function : LinearAngleVariation
4576 //purpose : auxilary for ExtrusionAlongTrack
4577 //=======================================================================
4578 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4579 list<double>& Angles)
4581 int nbAngles = Angles.size();
4582 if( nbSteps > nbAngles ) {
4583 vector<double> theAngles(nbAngles);
4584 list<double>::iterator it = Angles.begin();
4586 for(; it!=Angles.end(); it++) {
4588 theAngles[i] = (*it);
4591 double rAn2St = double( nbAngles ) / double( nbSteps );
4592 double angPrev = 0, angle;
4593 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4594 double angCur = rAn2St * ( iSt+1 );
4595 double angCurFloor = floor( angCur );
4596 double angPrevFloor = floor( angPrev );
4597 if ( angPrevFloor == angCurFloor )
4598 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4600 int iP = int( angPrevFloor );
4601 double angPrevCeil = ceil(angPrev);
4602 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4604 int iC = int( angCurFloor );
4605 if ( iC < nbAngles )
4606 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4608 iP = int( angPrevCeil );
4610 angle += theAngles[ iC ];
4612 res.push_back(angle);
4617 for(; it!=res.end(); it++)
4618 Angles.push_back( *it );
4623 //=======================================================================
4624 //function : Transform
4626 //=======================================================================
4628 SMESH_MeshEditor::PGroupIDs
4629 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4630 const gp_Trsf& theTrsf,
4632 const bool theMakeGroups,
4633 SMESH_Mesh* theTargetMesh)
4635 myLastCreatedElems.Clear();
4636 myLastCreatedNodes.Clear();
4638 bool needReverse = false;
4639 string groupPostfix;
4640 switch ( theTrsf.Form() ) {
4645 groupPostfix = "mirrored";
4648 groupPostfix = "rotated";
4650 case gp_Translation:
4651 groupPostfix = "translated";
4654 groupPostfix = "scaled";
4657 needReverse = false;
4658 groupPostfix = "transformed";
4661 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4662 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4663 SMESHDS_Mesh* aMesh = GetMeshDS();
4666 // map old node to new one
4667 TNodeNodeMap nodeMap;
4669 // elements sharing moved nodes; those of them which have all
4670 // nodes mirrored but are not in theElems are to be reversed
4671 TIDSortedElemSet inverseElemSet;
4673 // source elements for each generated one
4674 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4677 TIDSortedElemSet::iterator itElem;
4678 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4679 const SMDS_MeshElement* elem = *itElem;
4683 // loop on elem nodes
4684 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4685 while ( itN->more() ) {
4687 // check if a node has been already transformed
4688 const SMDS_MeshNode* node = cast2Node( itN->next() );
4689 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4690 nodeMap.insert( make_pair ( node, node ));
4691 if ( !n2n_isnew.second )
4695 coord[0] = node->X();
4696 coord[1] = node->Y();
4697 coord[2] = node->Z();
4698 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4699 if ( theTargetMesh ) {
4700 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4701 n2n_isnew.first->second = newNode;
4702 myLastCreatedNodes.Append(newNode);
4703 srcNodes.Append( node );
4705 else if ( theCopy ) {
4706 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4707 n2n_isnew.first->second = newNode;
4708 myLastCreatedNodes.Append(newNode);
4709 srcNodes.Append( node );
4712 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4713 // node position on shape becomes invalid
4714 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4715 ( SMDS_SpacePosition::originSpacePosition() );
4718 // keep inverse elements
4719 if ( !theCopy && !theTargetMesh && needReverse ) {
4720 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4721 while ( invElemIt->more() ) {
4722 const SMDS_MeshElement* iel = invElemIt->next();
4723 inverseElemSet.insert( iel );
4729 // either create new elements or reverse mirrored ones
4730 if ( !theCopy && !needReverse && !theTargetMesh )
4733 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4734 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4735 theElems.insert( *invElemIt );
4737 // replicate or reverse elements
4740 REV_TETRA = 0, // = nbNodes - 4
4741 REV_PYRAMID = 1, // = nbNodes - 4
4742 REV_PENTA = 2, // = nbNodes - 4
4744 REV_HEXA = 4, // = nbNodes - 4
4748 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4749 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4750 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4751 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4752 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4753 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4756 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4758 const SMDS_MeshElement* elem = *itElem;
4759 if ( !elem || elem->GetType() == SMDSAbs_Node )
4762 int nbNodes = elem->NbNodes();
4763 int elemType = elem->GetType();
4765 if (elem->IsPoly()) {
4766 // Polygon or Polyhedral Volume
4767 switch ( elemType ) {
4770 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4772 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4773 while (itN->more()) {
4774 const SMDS_MeshNode* node =
4775 static_cast<const SMDS_MeshNode*>(itN->next());
4776 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4777 if (nodeMapIt == nodeMap.end())
4778 break; // not all nodes transformed
4780 // reverse mirrored faces and volumes
4781 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4783 poly_nodes[iNode] = (*nodeMapIt).second;
4787 if ( iNode != nbNodes )
4788 continue; // not all nodes transformed
4790 if ( theTargetMesh ) {
4791 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4792 srcElems.Append( elem );
4794 else if ( theCopy ) {
4795 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4796 srcElems.Append( elem );
4799 aMesh->ChangePolygonNodes(elem, poly_nodes);
4803 case SMDSAbs_Volume:
4805 // ATTENTION: Reversing is not yet done!!!
4806 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4807 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4809 MESSAGE("Warning: bad volumic element");
4813 vector<const SMDS_MeshNode*> poly_nodes;
4814 vector<int> quantities;
4816 bool allTransformed = true;
4817 int nbFaces = aPolyedre->NbFaces();
4818 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4819 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4820 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4821 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4822 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4823 if (nodeMapIt == nodeMap.end()) {
4824 allTransformed = false; // not all nodes transformed
4826 poly_nodes.push_back((*nodeMapIt).second);
4829 quantities.push_back(nbFaceNodes);
4831 if ( !allTransformed )
4832 continue; // not all nodes transformed
4834 if ( theTargetMesh ) {
4835 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
4836 srcElems.Append( elem );
4838 else if ( theCopy ) {
4839 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
4840 srcElems.Append( elem );
4843 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
4853 int* i = index[ FORWARD ];
4854 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
4855 if ( elemType == SMDSAbs_Face )
4856 i = index[ REV_FACE ];
4858 i = index[ nbNodes - 4 ];
4860 if(elem->IsQuadratic()) {
4861 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
4864 if(nbNodes==3) { // quadratic edge
4865 static int anIds[] = {1,0,2};
4868 else if(nbNodes==6) { // quadratic triangle
4869 static int anIds[] = {0,2,1,5,4,3};
4872 else if(nbNodes==8) { // quadratic quadrangle
4873 static int anIds[] = {0,3,2,1,7,6,5,4};
4876 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
4877 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
4880 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
4881 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
4884 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
4885 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
4888 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
4889 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
4895 // find transformed nodes
4896 vector<const SMDS_MeshNode*> nodes(nbNodes);
4898 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4899 while ( itN->more() ) {
4900 const SMDS_MeshNode* node =
4901 static_cast<const SMDS_MeshNode*>( itN->next() );
4902 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
4903 if ( nodeMapIt == nodeMap.end() )
4904 break; // not all nodes transformed
4905 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
4907 if ( iNode != nbNodes )
4908 continue; // not all nodes transformed
4910 if ( theTargetMesh ) {
4911 if ( SMDS_MeshElement* copy =
4912 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4913 myLastCreatedElems.Append( copy );
4914 srcElems.Append( elem );
4917 else if ( theCopy ) {
4918 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
4919 myLastCreatedElems.Append( copy );
4920 srcElems.Append( elem );
4924 // reverse element as it was reversed by transformation
4926 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
4930 PGroupIDs newGroupIDs;
4932 if ( theMakeGroups && theCopy ||
4933 theMakeGroups && theTargetMesh )
4934 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
4939 //=======================================================================
4941 * \brief Create groups of elements made during transformation
4942 * \param nodeGens - nodes making corresponding myLastCreatedNodes
4943 * \param elemGens - elements making corresponding myLastCreatedElems
4944 * \param postfix - to append to names of new groups
4946 //=======================================================================
4948 SMESH_MeshEditor::PGroupIDs
4949 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
4950 const SMESH_SequenceOfElemPtr& elemGens,
4951 const std::string& postfix,
4952 SMESH_Mesh* targetMesh)
4954 PGroupIDs newGroupIDs( new list<int> );
4955 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
4957 // Sort existing groups by types and collect their names
4959 // to store an old group and a generated new one
4960 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
4961 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
4963 set< string > groupNames;
4965 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
4966 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
4967 while ( groupIt->more() ) {
4968 SMESH_Group * group = groupIt->next();
4969 if ( !group ) continue;
4970 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
4971 if ( !groupDS || groupDS->IsEmpty() ) continue;
4972 groupNames.insert( group->GetName() );
4973 groupDS->SetStoreName( group->GetName() );
4974 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
4979 // loop on nodes and elements
4980 for ( int isNodes = 0; isNodes < 2; ++isNodes )
4982 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
4983 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
4984 if ( gens.Length() != elems.Length() )
4985 throw SALOME_Exception(LOCALIZED("invalid args"));
4987 // loop on created elements
4988 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
4990 const SMDS_MeshElement* sourceElem = gens( iElem );
4991 if ( !sourceElem ) {
4992 MESSAGE("generateGroups(): NULL source element");
4995 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
4996 if ( groupsOldNew.empty() ) {
4997 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
4998 ++iElem; // skip all elements made by sourceElem
5001 // collect all elements made by sourceElem
5002 list< const SMDS_MeshElement* > resultElems;
5003 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5004 if ( resElem != sourceElem )
5005 resultElems.push_back( resElem );
5006 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5007 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5008 if ( resElem != sourceElem )
5009 resultElems.push_back( resElem );
5010 // do not generate element groups from node ones
5011 if ( sourceElem->GetType() == SMDSAbs_Node &&
5012 elems( iElem )->GetType() != SMDSAbs_Node )
5015 // add resultElems to groups made by ones the sourceElem belongs to
5016 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5017 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5019 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5020 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5022 SMDS_MeshGroup* & newGroup = gOldNew->second;
5023 if ( !newGroup )// create a new group
5026 string name = oldGroup->GetStoreName();
5027 if ( !targetMesh ) {
5031 while ( !groupNames.insert( name ).second ) // name exists
5037 TCollection_AsciiString nbStr(nb+1);
5038 name.resize( name.rfind('_')+1 );
5039 name += nbStr.ToCString();
5046 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5048 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5049 newGroup = & groupDS->SMDSGroup();
5050 newGroupIDs->push_back( id );
5053 // fill in a new group
5054 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5055 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5056 newGroup->Add( *resElemIt );
5059 } // loop on created elements
5060 }// loop on nodes and elements
5065 //================================================================================
5067 * \brief Return list of group of nodes close to each other within theTolerance
5068 * Search among theNodes or in the whole mesh if theNodes is empty using
5069 * an Octree algorithm
5071 //================================================================================
5073 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5074 const double theTolerance,
5075 TListOfListOfNodes & theGroupsOfNodes)
5077 myLastCreatedElems.Clear();
5078 myLastCreatedNodes.Clear();
5080 set<const SMDS_MeshNode*> nodes;
5081 if ( theNodes.empty() )
5082 { // get all nodes in the mesh
5083 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5084 while ( nIt->more() )
5085 nodes.insert( nodes.end(),nIt->next());
5090 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5094 //=======================================================================
5096 * \brief Implementation of search for the node closest to point
5098 //=======================================================================
5100 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5102 //---------------------------------------------------------------------
5104 * \brief Constructor
5106 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5108 myMesh = ( SMESHDS_Mesh* ) theMesh;
5110 set<const SMDS_MeshNode*> nodes;
5112 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5113 while ( nIt->more() )
5114 nodes.insert( nodes.end(), nIt->next() );
5116 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5118 // get max size of a leaf box
5119 SMESH_OctreeNode* tree = myOctreeNode;
5120 while ( !tree->isLeaf() )
5122 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5126 myHalfLeafSize = tree->maxSize() / 2.;
5129 //---------------------------------------------------------------------
5131 * \brief Move node and update myOctreeNode accordingly
5133 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5135 myOctreeNode->UpdateByMoveNode( node, toPnt );
5136 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5139 //---------------------------------------------------------------------
5141 * \brief Do it's job
5143 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5145 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5146 map<double, const SMDS_MeshNode*> dist2Nodes;
5147 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5148 if ( !dist2Nodes.empty() )
5149 return dist2Nodes.begin()->second;
5150 list<const SMDS_MeshNode*> nodes;
5151 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5153 double minSqDist = DBL_MAX;
5154 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5156 // sort leafs by their distance from thePnt
5157 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5158 TDistTreeMap treeMap;
5159 list< SMESH_OctreeNode* > treeList;
5160 list< SMESH_OctreeNode* >::iterator trIt;
5161 treeList.push_back( myOctreeNode );
5163 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5164 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5166 SMESH_OctreeNode* tree = *trIt;
5167 if ( !tree->isLeaf() ) // put children to the queue
5169 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5170 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5171 while ( cIt->more() )
5172 treeList.push_back( cIt->next() );
5174 else if ( tree->NbNodes() ) // put a tree to the treeMap
5176 const Bnd_B3d& box = tree->getBox();
5177 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5178 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5179 if ( !it_in.second ) // not unique distance to box center
5180 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5183 // find distance after which there is no sense to check tree's
5184 double sqLimit = DBL_MAX;
5185 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5186 if ( treeMap.size() > 5 ) {
5187 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5188 const Bnd_B3d& box = closestTree->getBox();
5189 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5190 sqLimit = limit * limit;
5192 // get all nodes from trees
5193 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5194 if ( sqDist_tree->first > sqLimit )
5196 SMESH_OctreeNode* tree = sqDist_tree->second;
5197 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5200 // find closest among nodes
5201 minSqDist = DBL_MAX;
5202 const SMDS_MeshNode* closestNode = 0;
5203 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5204 for ( ; nIt != nodes.end(); ++nIt ) {
5205 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5206 if ( minSqDist > sqDist ) {
5214 //---------------------------------------------------------------------
5218 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5220 //---------------------------------------------------------------------
5222 * \brief Return the node tree
5224 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5227 SMESH_OctreeNode* myOctreeNode;
5228 SMESHDS_Mesh* myMesh;
5229 double myHalfLeafSize; // max size of a leaf box
5232 //=======================================================================
5234 * \brief Return SMESH_NodeSearcher
5236 //=======================================================================
5238 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5240 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5243 // ========================================================================
5244 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5246 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5247 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5248 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5250 //=======================================================================
5252 * \brief Octal tree of bounding boxes of elements
5254 //=======================================================================
5256 class ElementBndBoxTree : public SMESH_Octree
5260 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5261 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5262 ~ElementBndBoxTree();
5265 ElementBndBoxTree() {}
5266 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5267 void buildChildrenData();
5268 Bnd_B3d* buildRootBox();
5270 //!< Bounding box of element
5271 struct ElementBox : public Bnd_B3d
5273 const SMDS_MeshElement* _element;
5274 int _refCount; // an ElementBox can be included in several tree branches
5275 ElementBox(const SMDS_MeshElement* elem);
5277 vector< ElementBox* > _elements;
5280 //================================================================================
5282 * \brief ElementBndBoxTree creation
5284 //================================================================================
5286 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5287 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5289 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5290 _elements.reserve( nbElems );
5292 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5293 while ( elemIt->more() )
5294 _elements.push_back( new ElementBox( elemIt->next() ));
5296 if ( _elements.size() > MaxNbElemsInLeaf )
5302 //================================================================================
5306 //================================================================================
5308 ElementBndBoxTree::~ElementBndBoxTree()
5310 for ( int i = 0; i < _elements.size(); ++i )
5311 if ( --_elements[i]->_refCount <= 0 )
5312 delete _elements[i];
5315 //================================================================================
5317 * \brief Return the maximal box
5319 //================================================================================
5321 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5323 Bnd_B3d* box = new Bnd_B3d;
5324 for ( int i = 0; i < _elements.size(); ++i )
5325 box->Add( *_elements[i] );
5329 //================================================================================
5331 * \brief Redistrubute element boxes among children
5333 //================================================================================
5335 void ElementBndBoxTree::buildChildrenData()
5337 for ( int i = 0; i < _elements.size(); ++i )
5339 for (int j = 0; j < 8; j++)
5341 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5343 _elements[i]->_refCount++;
5344 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5347 _elements[i]->_refCount--;
5351 for (int j = 0; j < 8; j++)
5353 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5354 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5355 child->myIsLeaf = true;
5357 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5358 child->_elements.resize( child->_elements.size() ); // compact
5362 //================================================================================
5364 * \brief Return elements which can include the point
5366 //================================================================================
5368 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5369 TIDSortedElemSet& foundElems)
5371 if ( level() && getBox().IsOut( point.XYZ() ))
5376 for ( int i = 0; i < _elements.size(); ++i )
5377 if ( !_elements[i]->IsOut( point.XYZ() ))
5378 foundElems.insert( _elements[i]->_element );
5382 for (int i = 0; i < 8; i++)
5383 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5387 //================================================================================
5389 * \brief Construct the element box
5391 //================================================================================
5393 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5397 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5398 while ( nIt->more() )
5399 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5400 Enlarge( NodeRadius );
5405 //=======================================================================
5407 * \brief Implementation of search for the elements by point
5409 //=======================================================================
5411 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5413 SMESHDS_Mesh* _mesh;
5414 ElementBndBoxTree* _ebbTree;
5415 SMESH_NodeSearcherImpl* _nodeSearcher;
5416 SMDSAbs_ElementType _elementType;
5418 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ): _mesh(&mesh),_ebbTree(0),_nodeSearcher(0) {}
5419 ~SMESH_ElementSearcherImpl()
5421 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5422 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5426 * \brief Find elements of given type where the given point is IN or ON.
5427 * Returns nb of found elements and elements them-selves.
5429 * 'ALL' type means elements of any type excluding nodes and 0D elements
5431 int FindElementsByPoint(const gp_Pnt& point,
5432 SMDSAbs_ElementType type,
5433 vector< const SMDS_MeshElement* >& foundElements)
5435 foundElements.clear();
5437 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5439 // -----------------
5441 // -----------------
5442 double tolerance = 0;
5443 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5445 double boxSize = _nodeSearcher->getTree()->maxSize();
5446 tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5448 else if ( _ebbTree && meshInfo.NbElements() > 0 )
5450 double boxSize = _ebbTree->maxSize();
5451 tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5453 if ( tolerance == 0 )
5455 // define tolerance by size of a most complex element
5456 int complexType = SMDSAbs_Volume;
5457 while ( complexType > SMDSAbs_All &&
5458 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5460 if ( complexType == SMDSAbs_All ) return foundElements.size(); // empty mesh
5463 if ( complexType == int( SMDSAbs_Node ))
5465 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
5467 if ( meshInfo.NbNodes() > 2 )
5468 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
5472 const SMDS_MeshElement* elem =
5473 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
5474 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
5475 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
5476 while ( nodeIt->more() )
5478 double dist = n1.Distance( cast2Node( nodeIt->next() ));
5479 elemSize = max( dist, elemSize );
5482 tolerance = 1e-6 * elemSize;
5485 // =================================================================================
5486 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
5488 if ( !_nodeSearcher )
5489 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
5491 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
5492 if ( !closeNode ) return foundElements.size();
5494 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
5495 return foundElements.size(); // to far from any node
5497 if ( type == SMDSAbs_Node )
5499 foundElements.push_back( closeNode );
5503 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
5504 while ( elemIt->more() )
5505 foundElements.push_back( elemIt->next() );
5508 // =================================================================================
5509 else // elements more complex than 0D
5511 if ( !_ebbTree || _elementType != type )
5513 if ( _ebbTree ) delete _ebbTree;
5514 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
5516 TIDSortedElemSet suspectElems;
5517 _ebbTree->getElementsNearPoint( point, suspectElems );
5518 TIDSortedElemSet::iterator elem = suspectElems.begin();
5519 for ( ; elem != suspectElems.end(); ++elem )
5520 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
5521 foundElements.push_back( *elem );
5523 return foundElements.size();
5525 }; // struct SMESH_ElementSearcherImpl
5527 //=======================================================================
5529 * \brief Return SMESH_ElementSearcher
5531 //=======================================================================
5533 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
5535 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
5538 //=======================================================================
5540 * \brief Return true if the point is IN or ON of the element
5542 //=======================================================================
5544 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
5546 if ( element->GetType() == SMDSAbs_Volume)
5548 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
5551 // get ordered nodes
5553 vector< gp_XYZ > xyz;
5555 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
5556 if ( element->IsQuadratic() )
5557 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
5558 nodeIt = f->interlacedNodesElemIterator();
5559 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
5560 nodeIt = e->interlacedNodesElemIterator();
5562 while ( nodeIt->more() )
5563 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
5565 int i, nbNodes = element->NbNodes();
5567 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5569 // compute face normal
5570 gp_Vec faceNorm(0,0,0);
5571 xyz.push_back( xyz.front() );
5572 for ( i = 0; i < nbNodes; ++i )
5574 gp_Vec edge1( xyz[i+1], xyz[i]);
5575 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
5576 faceNorm += edge1 ^ edge2;
5578 double normSize = faceNorm.Magnitude();
5579 if ( normSize <= tol )
5581 // degenerated face: point is out if it is out of all face edges
5582 for ( i = 0; i < nbNodes; ++i )
5584 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
5585 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
5586 SMDS_MeshEdge edge( &n1, &n2 );
5587 if ( !isOut( &edge, point, tol ))
5592 faceNorm /= normSize;
5594 // check if the point lays on face plane
5595 gp_Vec n2p( xyz[0], point );
5596 if ( fabs( n2p * faceNorm ) > tol )
5597 return true; // not on face plane
5599 // check if point is out of face boundary:
5600 // define it by closest transition of a ray point->infinity through face boundary
5601 // on the face plane.
5602 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
5603 // to find intersections of the ray with the boundary.
5605 gp_Vec plnNorm = ray ^ faceNorm;
5606 normSize = plnNorm.Magnitude();
5607 if ( normSize <= tol ) return false; // point coincides with the first node
5608 plnNorm /= normSize;
5609 // for each node of the face, compute its signed distance to the plane
5610 vector<double> dist( nbNodes + 1);
5611 for ( i = 0; i < nbNodes; ++i )
5613 gp_Vec n2p( xyz[i], point );
5614 dist[i] = n2p * plnNorm;
5616 dist.back() = dist.front();
5617 // find the closest intersection
5619 double rClosest, distClosest = 1e100;;
5621 for ( i = 0; i < nbNodes; ++i )
5624 if ( fabs( dist[i]) < tol )
5626 else if ( fabs( dist[i+1]) < tol )
5628 else if ( dist[i] * dist[i+1] < 0 )
5629 r = dist[i] / ( dist[i] - dist[i+1] );
5631 continue; // no intersection
5632 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
5633 gp_Vec p2int ( point, pInt);
5634 if ( p2int * ray > -tol ) // right half-space
5636 double intDist = p2int.SquareMagnitude();
5637 if ( intDist < distClosest )
5642 distClosest = intDist;
5647 return true; // no intesections - out
5649 // analyse transition
5650 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
5651 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
5652 gp_Vec p2int ( point, pClosest );
5653 bool out = (edgeNorm * p2int) < -tol;
5654 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
5657 // ray pass through a face node; analyze transition through an adjacent edge
5658 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
5659 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
5660 gp_Vec edgeAdjacent( p1, p2 );
5661 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
5662 bool out2 = (edgeNorm2 * p2int) < -tol;
5664 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
5665 return covexCorner ? (out || out2) : (out && out2);
5667 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5669 // point is out of edge if it is NOT ON any straight part of edge
5670 // (we consider quadratic edge as being composed of two straight parts)
5671 for ( i = 1; i < nbNodes; ++i )
5673 gp_Vec edge( xyz[i-1], xyz[i]);
5674 gp_Vec n1p ( xyz[i-1], point);
5675 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
5678 gp_Vec n2p( xyz[i], point );
5679 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
5681 return false; // point is ON this part
5685 // Node or 0D element -------------------------------------------------------------------------
5687 gp_Vec n2p ( xyz[0], point );
5688 return n2p.Magnitude() <= tol;
5693 //=======================================================================
5694 //function : SimplifyFace
5696 //=======================================================================
5697 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
5698 vector<const SMDS_MeshNode *>& poly_nodes,
5699 vector<int>& quantities) const
5701 int nbNodes = faceNodes.size();
5706 set<const SMDS_MeshNode*> nodeSet;
5708 // get simple seq of nodes
5709 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
5710 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
5711 int iSimple = 0, nbUnique = 0;
5713 simpleNodes[iSimple++] = faceNodes[0];
5715 for (int iCur = 1; iCur < nbNodes; iCur++) {
5716 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
5717 simpleNodes[iSimple++] = faceNodes[iCur];
5718 if (nodeSet.insert( faceNodes[iCur] ).second)
5722 int nbSimple = iSimple;
5723 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
5733 bool foundLoop = (nbSimple > nbUnique);
5736 set<const SMDS_MeshNode*> loopSet;
5737 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
5738 const SMDS_MeshNode* n = simpleNodes[iSimple];
5739 if (!loopSet.insert( n ).second) {
5743 int iC = 0, curLast = iSimple;
5744 for (; iC < curLast; iC++) {
5745 if (simpleNodes[iC] == n) break;
5747 int loopLen = curLast - iC;
5749 // create sub-element
5751 quantities.push_back(loopLen);
5752 for (; iC < curLast; iC++) {
5753 poly_nodes.push_back(simpleNodes[iC]);
5756 // shift the rest nodes (place from the first loop position)
5757 for (iC = curLast + 1; iC < nbSimple; iC++) {
5758 simpleNodes[iC - loopLen] = simpleNodes[iC];
5760 nbSimple -= loopLen;
5763 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
5764 } // while (foundLoop)
5768 quantities.push_back(iSimple);
5769 for (int i = 0; i < iSimple; i++)
5770 poly_nodes.push_back(simpleNodes[i]);
5776 //=======================================================================
5777 //function : MergeNodes
5778 //purpose : In each group, the cdr of nodes are substituted by the first one
5780 //=======================================================================
5782 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
5784 myLastCreatedElems.Clear();
5785 myLastCreatedNodes.Clear();
5787 SMESHDS_Mesh* aMesh = GetMeshDS();
5789 TNodeNodeMap nodeNodeMap; // node to replace - new node
5790 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
5791 list< int > rmElemIds, rmNodeIds;
5793 // Fill nodeNodeMap and elems
5795 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
5796 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
5797 list<const SMDS_MeshNode*>& nodes = *grIt;
5798 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5799 const SMDS_MeshNode* nToKeep = *nIt;
5800 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
5801 const SMDS_MeshNode* nToRemove = *nIt;
5802 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
5803 if ( nToRemove != nToKeep ) {
5804 rmNodeIds.push_back( nToRemove->GetID() );
5805 AddToSameGroups( nToKeep, nToRemove, aMesh );
5808 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
5809 while ( invElemIt->more() ) {
5810 const SMDS_MeshElement* elem = invElemIt->next();
5815 // Change element nodes or remove an element
5817 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
5818 for ( ; eIt != elems.end(); eIt++ ) {
5819 const SMDS_MeshElement* elem = *eIt;
5820 int nbNodes = elem->NbNodes();
5821 int aShapeId = FindShape( elem );
5823 set<const SMDS_MeshNode*> nodeSet;
5824 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
5825 int iUnique = 0, iCur = 0, nbRepl = 0;
5826 vector<int> iRepl( nbNodes );
5828 // get new seq of nodes
5829 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5830 while ( itN->more() ) {
5831 const SMDS_MeshNode* n =
5832 static_cast<const SMDS_MeshNode*>( itN->next() );
5834 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
5835 if ( nnIt != nodeNodeMap.end() ) { // n sticks
5837 // BUG 0020185: begin
5839 bool stopRecur = false;
5840 set<const SMDS_MeshNode*> nodesRecur;
5841 nodesRecur.insert(n);
5842 while (!stopRecur) {
5843 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
5844 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
5845 n = (*nnIt_i).second;
5846 if (!nodesRecur.insert(n).second) {
5847 // error: recursive dependancy
5856 iRepl[ nbRepl++ ] = iCur;
5858 curNodes[ iCur ] = n;
5859 bool isUnique = nodeSet.insert( n ).second;
5861 uniqueNodes[ iUnique++ ] = n;
5865 // Analyse element topology after replacement
5868 int nbUniqueNodes = nodeSet.size();
5869 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
5870 // Polygons and Polyhedral volumes
5871 if (elem->IsPoly()) {
5873 if (elem->GetType() == SMDSAbs_Face) {
5875 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
5877 for (; inode < nbNodes; inode++) {
5878 face_nodes[inode] = curNodes[inode];
5881 vector<const SMDS_MeshNode *> polygons_nodes;
5882 vector<int> quantities;
5883 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
5887 for (int iface = 0; iface < nbNew - 1; iface++) {
5888 int nbNodes = quantities[iface];
5889 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
5890 for (int ii = 0; ii < nbNodes; ii++, inode++) {
5891 poly_nodes[ii] = polygons_nodes[inode];
5893 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
5894 myLastCreatedElems.Append(newElem);
5896 aMesh->SetMeshElementOnShape(newElem, aShapeId);
5898 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
5901 rmElemIds.push_back(elem->GetID());
5905 else if (elem->GetType() == SMDSAbs_Volume) {
5906 // Polyhedral volume
5907 if (nbUniqueNodes < 4) {
5908 rmElemIds.push_back(elem->GetID());
5911 // each face has to be analized in order to check volume validity
5912 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5913 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5915 int nbFaces = aPolyedre->NbFaces();
5917 vector<const SMDS_MeshNode *> poly_nodes;
5918 vector<int> quantities;
5920 for (int iface = 1; iface <= nbFaces; iface++) {
5921 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5922 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
5924 for (int inode = 1; inode <= nbFaceNodes; inode++) {
5925 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
5926 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
5927 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
5928 faceNode = (*nnIt).second;
5930 faceNodes[inode - 1] = faceNode;
5933 SimplifyFace(faceNodes, poly_nodes, quantities);
5936 if (quantities.size() > 3) {
5937 // to be done: remove coincident faces
5940 if (quantities.size() > 3)
5941 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5943 rmElemIds.push_back(elem->GetID());
5947 rmElemIds.push_back(elem->GetID());
5958 switch ( nbNodes ) {
5959 case 2: ///////////////////////////////////// EDGE
5960 isOk = false; break;
5961 case 3: ///////////////////////////////////// TRIANGLE
5962 isOk = false; break;
5964 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
5966 else { //////////////////////////////////// QUADRANGLE
5967 if ( nbUniqueNodes < 3 )
5969 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
5970 isOk = false; // opposite nodes stick
5973 case 6: ///////////////////////////////////// PENTAHEDRON
5974 if ( nbUniqueNodes == 4 ) {
5975 // ---------------------------------> tetrahedron
5977 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
5978 // all top nodes stick: reverse a bottom
5979 uniqueNodes[ 0 ] = curNodes [ 1 ];
5980 uniqueNodes[ 1 ] = curNodes [ 0 ];
5982 else if (nbRepl == 3 &&
5983 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
5984 // all bottom nodes stick: set a top before
5985 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
5986 uniqueNodes[ 0 ] = curNodes [ 3 ];
5987 uniqueNodes[ 1 ] = curNodes [ 4 ];
5988 uniqueNodes[ 2 ] = curNodes [ 5 ];
5990 else if (nbRepl == 4 &&
5991 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
5992 // a lateral face turns into a line: reverse a bottom
5993 uniqueNodes[ 0 ] = curNodes [ 1 ];
5994 uniqueNodes[ 1 ] = curNodes [ 0 ];
5999 else if ( nbUniqueNodes == 5 ) {
6000 // PENTAHEDRON --------------------> 2 tetrahedrons
6001 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6002 // a bottom node sticks with a linked top one
6004 SMDS_MeshElement* newElem =
6005 aMesh->AddVolume(curNodes[ 3 ],
6008 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6009 myLastCreatedElems.Append(newElem);
6011 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6012 // 2. : reverse a bottom
6013 uniqueNodes[ 0 ] = curNodes [ 1 ];
6014 uniqueNodes[ 1 ] = curNodes [ 0 ];
6024 if(elem->IsQuadratic()) { // Quadratic quadrangle
6037 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6038 uniqueNodes[0] = curNodes[0];
6039 uniqueNodes[1] = curNodes[2];
6040 uniqueNodes[2] = curNodes[3];
6041 uniqueNodes[3] = curNodes[5];
6042 uniqueNodes[4] = curNodes[6];
6043 uniqueNodes[5] = curNodes[7];
6046 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6047 uniqueNodes[0] = curNodes[0];
6048 uniqueNodes[1] = curNodes[1];
6049 uniqueNodes[2] = curNodes[2];
6050 uniqueNodes[3] = curNodes[4];
6051 uniqueNodes[4] = curNodes[5];
6052 uniqueNodes[5] = curNodes[6];
6055 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6056 uniqueNodes[0] = curNodes[1];
6057 uniqueNodes[1] = curNodes[2];
6058 uniqueNodes[2] = curNodes[3];
6059 uniqueNodes[3] = curNodes[5];
6060 uniqueNodes[4] = curNodes[6];
6061 uniqueNodes[5] = curNodes[0];
6064 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6065 uniqueNodes[0] = curNodes[0];
6066 uniqueNodes[1] = curNodes[1];
6067 uniqueNodes[2] = curNodes[3];
6068 uniqueNodes[3] = curNodes[4];
6069 uniqueNodes[4] = curNodes[6];
6070 uniqueNodes[5] = curNodes[7];
6073 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6074 uniqueNodes[0] = curNodes[0];
6075 uniqueNodes[1] = curNodes[2];
6076 uniqueNodes[2] = curNodes[3];
6077 uniqueNodes[3] = curNodes[1];
6078 uniqueNodes[4] = curNodes[6];
6079 uniqueNodes[5] = curNodes[7];
6082 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6083 uniqueNodes[0] = curNodes[0];
6084 uniqueNodes[1] = curNodes[1];
6085 uniqueNodes[2] = curNodes[2];
6086 uniqueNodes[3] = curNodes[4];
6087 uniqueNodes[4] = curNodes[5];
6088 uniqueNodes[5] = curNodes[7];
6091 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6092 uniqueNodes[0] = curNodes[0];
6093 uniqueNodes[1] = curNodes[1];
6094 uniqueNodes[2] = curNodes[3];
6095 uniqueNodes[3] = curNodes[4];
6096 uniqueNodes[4] = curNodes[2];
6097 uniqueNodes[5] = curNodes[7];
6100 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6101 uniqueNodes[0] = curNodes[0];
6102 uniqueNodes[1] = curNodes[1];
6103 uniqueNodes[2] = curNodes[2];
6104 uniqueNodes[3] = curNodes[4];
6105 uniqueNodes[4] = curNodes[5];
6106 uniqueNodes[5] = curNodes[3];
6112 //////////////////////////////////// HEXAHEDRON
6114 SMDS_VolumeTool hexa (elem);
6115 hexa.SetExternalNormal();
6116 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6117 //////////////////////// ---> tetrahedron
6118 for ( int iFace = 0; iFace < 6; iFace++ ) {
6119 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6120 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6121 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6122 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6123 // one face turns into a point ...
6124 int iOppFace = hexa.GetOppFaceIndex( iFace );
6125 ind = hexa.GetFaceNodesIndices( iOppFace );
6127 iUnique = 2; // reverse a tetrahedron bottom
6128 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6129 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6131 else if ( iUnique >= 0 )
6132 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6134 if ( nbStick == 1 ) {
6135 // ... and the opposite one - into a triangle.
6137 ind = hexa.GetFaceNodesIndices( iFace );
6138 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6145 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6146 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6147 for ( int iFace = 0; iFace < 6; iFace++ ) {
6148 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6149 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6150 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6151 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6152 // one face turns into a point ...
6153 int iOppFace = hexa.GetOppFaceIndex( iFace );
6154 ind = hexa.GetFaceNodesIndices( iOppFace );
6156 iUnique = 2; // reverse a tetrahedron 1 bottom
6157 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6158 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6160 else if ( iUnique >= 0 )
6161 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6163 if ( nbStick == 0 ) {
6164 // ... and the opposite one is a quadrangle
6166 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6167 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6170 SMDS_MeshElement* newElem =
6171 aMesh->AddVolume(curNodes[ind[ 0 ]],
6174 curNodes[indTop[ 0 ]]);
6175 myLastCreatedElems.Append(newElem);
6177 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6184 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6185 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6186 // find indices of quad and tri faces
6187 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6188 for ( iFace = 0; iFace < 6; iFace++ ) {
6189 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6191 for ( iCur = 0; iCur < 4; iCur++ )
6192 nodeSet.insert( curNodes[ind[ iCur ]] );
6193 nbUniqueNodes = nodeSet.size();
6194 if ( nbUniqueNodes == 3 )
6195 iTriFace[ nbTri++ ] = iFace;
6196 else if ( nbUniqueNodes == 4 )
6197 iQuadFace[ nbQuad++ ] = iFace;
6199 if (nbQuad == 2 && nbTri == 4 &&
6200 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6201 // 2 opposite quadrangles stuck with a diagonal;
6202 // sample groups of merged indices: (0-4)(2-6)
6203 // --------------------------------------------> 2 tetrahedrons
6204 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6205 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6206 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6207 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6208 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6209 // stuck with 0-2 diagonal
6217 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6218 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6219 // stuck with 1-3 diagonal
6231 uniqueNodes[ 0 ] = curNodes [ i0 ];
6232 uniqueNodes[ 1 ] = curNodes [ i1d ];
6233 uniqueNodes[ 2 ] = curNodes [ i3d ];
6234 uniqueNodes[ 3 ] = curNodes [ i0t ];
6237 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6241 myLastCreatedElems.Append(newElem);
6243 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6246 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6247 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6248 // --------------------------------------------> prism
6249 // find 2 opposite triangles
6251 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6252 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6253 // find indices of kept and replaced nodes
6254 // and fill unique nodes of 2 opposite triangles
6255 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6256 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6257 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6258 // fill unique nodes
6261 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6262 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6263 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6265 // iCur of a linked node of the opposite face (make normals co-directed):
6266 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6267 // check that correspondent corners of triangles are linked
6268 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6271 uniqueNodes[ iUnique ] = n;
6272 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6281 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6287 } // switch ( nbNodes )
6289 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6292 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6293 // Change nodes of polyedre
6294 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6295 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6297 int nbFaces = aPolyedre->NbFaces();
6299 vector<const SMDS_MeshNode *> poly_nodes;
6300 vector<int> quantities (nbFaces);
6302 for (int iface = 1; iface <= nbFaces; iface++) {
6303 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6304 quantities[iface - 1] = nbFaceNodes;
6306 for (inode = 1; inode <= nbFaceNodes; inode++) {
6307 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6309 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6310 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6311 curNode = (*nnIt).second;
6313 poly_nodes.push_back(curNode);
6316 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6320 // Change regular element or polygon
6321 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6325 // Remove invalid regular element or invalid polygon
6326 rmElemIds.push_back( elem->GetID() );
6329 } // loop on elements
6331 // Remove equal nodes and bad elements
6333 Remove( rmNodeIds, true );
6334 Remove( rmElemIds, false );
6339 // ========================================================
6340 // class : SortableElement
6341 // purpose : allow sorting elements basing on their nodes
6342 // ========================================================
6343 class SortableElement : public set <const SMDS_MeshElement*>
6347 SortableElement( const SMDS_MeshElement* theElem )
6350 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6351 while ( nodeIt->more() )
6352 this->insert( nodeIt->next() );
6355 const SMDS_MeshElement* Get() const
6358 void Set(const SMDS_MeshElement* e) const
6363 mutable const SMDS_MeshElement* myElem;
6366 //=======================================================================
6367 //function : FindEqualElements
6368 //purpose : Return list of group of elements built on the same nodes.
6369 // Search among theElements or in the whole mesh if theElements is empty
6370 //=======================================================================
6371 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6372 TListOfListOfElementsID & theGroupsOfElementsID)
6374 myLastCreatedElems.Clear();
6375 myLastCreatedNodes.Clear();
6377 typedef set<const SMDS_MeshElement*> TElemsSet;
6378 typedef map< SortableElement, int > TMapOfNodeSet;
6379 typedef list<int> TGroupOfElems;
6382 if ( theElements.empty() )
6383 { // get all elements in the mesh
6384 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6385 while ( eIt->more() )
6386 elems.insert( elems.end(), eIt->next());
6389 elems = theElements;
6391 vector< TGroupOfElems > arrayOfGroups;
6392 TGroupOfElems groupOfElems;
6393 TMapOfNodeSet mapOfNodeSet;
6395 TElemsSet::iterator elemIt = elems.begin();
6396 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6397 const SMDS_MeshElement* curElem = *elemIt;
6398 SortableElement SE(curElem);
6401 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6402 if( !(pp.second) ) {
6403 TMapOfNodeSet::iterator& itSE = pp.first;
6404 ind = (*itSE).second;
6405 arrayOfGroups[ind].push_back(curElem->GetID());
6408 groupOfElems.clear();
6409 groupOfElems.push_back(curElem->GetID());
6410 arrayOfGroups.push_back(groupOfElems);
6415 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6416 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6417 groupOfElems = *groupIt;
6418 if ( groupOfElems.size() > 1 ) {
6419 groupOfElems.sort();
6420 theGroupsOfElementsID.push_back(groupOfElems);
6425 //=======================================================================
6426 //function : MergeElements
6427 //purpose : In each given group, substitute all elements by the first one.
6428 //=======================================================================
6430 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6432 myLastCreatedElems.Clear();
6433 myLastCreatedNodes.Clear();
6435 typedef list<int> TListOfIDs;
6436 TListOfIDs rmElemIds; // IDs of elems to remove
6438 SMESHDS_Mesh* aMesh = GetMeshDS();
6440 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6441 while ( groupsIt != theGroupsOfElementsID.end() ) {
6442 TListOfIDs& aGroupOfElemID = *groupsIt;
6443 aGroupOfElemID.sort();
6444 int elemIDToKeep = aGroupOfElemID.front();
6445 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6446 aGroupOfElemID.pop_front();
6447 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6448 while ( idIt != aGroupOfElemID.end() ) {
6449 int elemIDToRemove = *idIt;
6450 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6451 // add the kept element in groups of removed one (PAL15188)
6452 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6453 rmElemIds.push_back( elemIDToRemove );
6459 Remove( rmElemIds, false );
6462 //=======================================================================
6463 //function : MergeEqualElements
6464 //purpose : Remove all but one of elements built on the same nodes.
6465 //=======================================================================
6467 void SMESH_MeshEditor::MergeEqualElements()
6469 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6470 to merge equal elements in the whole mesh */
6471 TListOfListOfElementsID aGroupsOfElementsID;
6472 FindEqualElements(aMeshElements, aGroupsOfElementsID);
6473 MergeElements(aGroupsOfElementsID);
6476 //=======================================================================
6477 //function : FindFaceInSet
6478 //purpose : Return a face having linked nodes n1 and n2 and which is
6479 // - not in avoidSet,
6480 // - in elemSet provided that !elemSet.empty()
6481 // i1 and i2 optionally returns indices of n1 and n2
6482 //=======================================================================
6484 const SMDS_MeshElement*
6485 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
6486 const SMDS_MeshNode* n2,
6487 const TIDSortedElemSet& elemSet,
6488 const TIDSortedElemSet& avoidSet,
6494 const SMDS_MeshElement* face = 0;
6496 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6497 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
6499 const SMDS_MeshElement* elem = invElemIt->next();
6500 if (avoidSet.count( elem ))
6502 if ( !elemSet.empty() && !elemSet.count( elem ))
6505 i1 = elem->GetNodeIndex( n1 );
6506 // find a n2 linked to n1
6507 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
6508 for ( int di = -1; di < 2 && !face; di += 2 )
6510 i2 = (i1+di+nbN) % nbN;
6511 if ( elem->GetNode( i2 ) == n2 )
6514 if ( !face && elem->IsQuadratic())
6516 // analysis for quadratic elements using all nodes
6517 const SMDS_QuadraticFaceOfNodes* F =
6518 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6519 // use special nodes iterator
6520 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6521 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
6522 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
6524 const SMDS_MeshNode* n = cast2Node( anIter->next() );
6525 if ( n1 == prevN && n2 == n )
6529 else if ( n2 == prevN && n1 == n )
6531 face = elem; swap( i1, i2 );
6537 if ( n1ind ) *n1ind = i1;
6538 if ( n2ind ) *n2ind = i2;
6542 //=======================================================================
6543 //function : findAdjacentFace
6545 //=======================================================================
6547 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6548 const SMDS_MeshNode* n2,
6549 const SMDS_MeshElement* elem)
6551 TIDSortedElemSet elemSet, avoidSet;
6553 avoidSet.insert ( elem );
6554 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6557 //=======================================================================
6558 //function : FindFreeBorder
6560 //=======================================================================
6562 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6564 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6565 const SMDS_MeshNode* theSecondNode,
6566 const SMDS_MeshNode* theLastNode,
6567 list< const SMDS_MeshNode* > & theNodes,
6568 list< const SMDS_MeshElement* >& theFaces)
6570 if ( !theFirstNode || !theSecondNode )
6572 // find border face between theFirstNode and theSecondNode
6573 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6577 theFaces.push_back( curElem );
6578 theNodes.push_back( theFirstNode );
6579 theNodes.push_back( theSecondNode );
6581 //vector<const SMDS_MeshNode*> nodes;
6582 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6583 TIDSortedElemSet foundElems;
6584 bool needTheLast = ( theLastNode != 0 );
6586 while ( nStart != theLastNode ) {
6587 if ( nStart == theFirstNode )
6588 return !needTheLast;
6590 // find all free border faces sharing form nStart
6592 list< const SMDS_MeshElement* > curElemList;
6593 list< const SMDS_MeshNode* > nStartList;
6594 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6595 while ( invElemIt->more() ) {
6596 const SMDS_MeshElement* e = invElemIt->next();
6597 if ( e == curElem || foundElems.insert( e ).second ) {
6599 int iNode = 0, nbNodes = e->NbNodes();
6600 //const SMDS_MeshNode* nodes[nbNodes+1];
6601 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6603 if(e->IsQuadratic()) {
6604 const SMDS_QuadraticFaceOfNodes* F =
6605 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6606 // use special nodes iterator
6607 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6608 while( anIter->more() ) {
6609 nodes[ iNode++ ] = anIter->next();
6613 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6614 while ( nIt->more() )
6615 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6617 nodes[ iNode ] = nodes[ 0 ];
6619 for ( iNode = 0; iNode < nbNodes; iNode++ )
6620 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6621 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6622 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6624 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6625 curElemList.push_back( e );
6629 // analyse the found
6631 int nbNewBorders = curElemList.size();
6632 if ( nbNewBorders == 0 ) {
6633 // no free border furthermore
6634 return !needTheLast;
6636 else if ( nbNewBorders == 1 ) {
6637 // one more element found
6639 nStart = nStartList.front();
6640 curElem = curElemList.front();
6641 theFaces.push_back( curElem );
6642 theNodes.push_back( nStart );
6645 // several continuations found
6646 list< const SMDS_MeshElement* >::iterator curElemIt;
6647 list< const SMDS_MeshNode* >::iterator nStartIt;
6648 // check if one of them reached the last node
6649 if ( needTheLast ) {
6650 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6651 curElemIt!= curElemList.end();
6652 curElemIt++, nStartIt++ )
6653 if ( *nStartIt == theLastNode ) {
6654 theFaces.push_back( *curElemIt );
6655 theNodes.push_back( *nStartIt );
6659 // find the best free border by the continuations
6660 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6661 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6662 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6663 curElemIt!= curElemList.end();
6664 curElemIt++, nStartIt++ )
6666 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6667 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6668 // find one more free border
6669 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6673 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6674 // choice: clear a worse one
6675 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
6676 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
6677 contNodes[ iWorse ].clear();
6678 contFaces[ iWorse ].clear();
6681 if ( contNodes[0].empty() && contNodes[1].empty() )
6684 // append the best free border
6685 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
6686 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
6687 theNodes.pop_back(); // remove nIgnore
6688 theNodes.pop_back(); // remove nStart
6689 theFaces.pop_back(); // remove curElem
6690 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
6691 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
6692 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
6693 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
6696 } // several continuations found
6697 } // while ( nStart != theLastNode )
6702 //=======================================================================
6703 //function : CheckFreeBorderNodes
6704 //purpose : Return true if the tree nodes are on a free border
6705 //=======================================================================
6707 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
6708 const SMDS_MeshNode* theNode2,
6709 const SMDS_MeshNode* theNode3)
6711 list< const SMDS_MeshNode* > nodes;
6712 list< const SMDS_MeshElement* > faces;
6713 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
6716 //=======================================================================
6717 //function : SewFreeBorder
6719 //=======================================================================
6721 SMESH_MeshEditor::Sew_Error
6722 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
6723 const SMDS_MeshNode* theBordSecondNode,
6724 const SMDS_MeshNode* theBordLastNode,
6725 const SMDS_MeshNode* theSideFirstNode,
6726 const SMDS_MeshNode* theSideSecondNode,
6727 const SMDS_MeshNode* theSideThirdNode,
6728 const bool theSideIsFreeBorder,
6729 const bool toCreatePolygons,
6730 const bool toCreatePolyedrs)
6732 myLastCreatedElems.Clear();
6733 myLastCreatedNodes.Clear();
6735 MESSAGE("::SewFreeBorder()");
6736 Sew_Error aResult = SEW_OK;
6738 // ====================================
6739 // find side nodes and elements
6740 // ====================================
6742 list< const SMDS_MeshNode* > nSide[ 2 ];
6743 list< const SMDS_MeshElement* > eSide[ 2 ];
6744 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
6745 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
6749 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
6750 nSide[0], eSide[0])) {
6751 MESSAGE(" Free Border 1 not found " );
6752 aResult = SEW_BORDER1_NOT_FOUND;
6754 if (theSideIsFreeBorder) {
6757 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
6758 nSide[1], eSide[1])) {
6759 MESSAGE(" Free Border 2 not found " );
6760 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
6763 if ( aResult != SEW_OK )
6766 if (!theSideIsFreeBorder) {
6770 // -------------------------------------------------------------------------
6772 // 1. If nodes to merge are not coincident, move nodes of the free border
6773 // from the coord sys defined by the direction from the first to last
6774 // nodes of the border to the correspondent sys of the side 2
6775 // 2. On the side 2, find the links most co-directed with the correspondent
6776 // links of the free border
6777 // -------------------------------------------------------------------------
6779 // 1. Since sewing may brake if there are volumes to split on the side 2,
6780 // we wont move nodes but just compute new coordinates for them
6781 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
6782 TNodeXYZMap nBordXYZ;
6783 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
6784 list< const SMDS_MeshNode* >::iterator nBordIt;
6786 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
6787 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
6788 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
6789 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
6790 double tol2 = 1.e-8;
6791 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
6792 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
6793 // Need node movement.
6795 // find X and Z axes to create trsf
6796 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
6798 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
6800 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
6803 gp_Ax3 toBordAx( Pb1, Zb, X );
6804 gp_Ax3 fromSideAx( Ps1, Zs, X );
6805 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
6807 gp_Trsf toBordSys, fromSide2Sys;
6808 toBordSys.SetTransformation( toBordAx );
6809 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
6810 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
6813 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6814 const SMDS_MeshNode* n = *nBordIt;
6815 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
6816 toBordSys.Transforms( xyz );
6817 fromSide2Sys.Transforms( xyz );
6818 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
6822 // just insert nodes XYZ in the nBordXYZ map
6823 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
6824 const SMDS_MeshNode* n = *nBordIt;
6825 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
6829 // 2. On the side 2, find the links most co-directed with the correspondent
6830 // links of the free border
6832 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
6833 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
6834 sideNodes.push_back( theSideFirstNode );
6836 bool hasVolumes = false;
6837 LinkID_Gen aLinkID_Gen( GetMeshDS() );
6838 set<long> foundSideLinkIDs, checkedLinkIDs;
6839 SMDS_VolumeTool volume;
6840 //const SMDS_MeshNode* faceNodes[ 4 ];
6842 const SMDS_MeshNode* sideNode;
6843 const SMDS_MeshElement* sideElem;
6844 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
6845 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
6846 nBordIt = bordNodes.begin();
6848 // border node position and border link direction to compare with
6849 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
6850 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
6851 // choose next side node by link direction or by closeness to
6852 // the current border node:
6853 bool searchByDir = ( *nBordIt != theBordLastNode );
6855 // find the next node on the Side 2
6857 double maxDot = -DBL_MAX, minDist = DBL_MAX;
6859 checkedLinkIDs.clear();
6860 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
6862 // loop on inverse elements of current node (prevSideNode) on the Side 2
6863 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
6864 while ( invElemIt->more() )
6866 const SMDS_MeshElement* elem = invElemIt->next();
6867 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
6868 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
6869 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
6870 bool isVolume = volume.Set( elem );
6871 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
6872 if ( isVolume ) // --volume
6874 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
6875 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
6876 if(elem->IsQuadratic()) {
6877 const SMDS_QuadraticFaceOfNodes* F =
6878 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6879 // use special nodes iterator
6880 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6881 while( anIter->more() ) {
6882 nodes[ iNode ] = anIter->next();
6883 if ( nodes[ iNode++ ] == prevSideNode )
6884 iPrevNode = iNode - 1;
6888 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6889 while ( nIt->more() ) {
6890 nodes[ iNode ] = cast2Node( nIt->next() );
6891 if ( nodes[ iNode++ ] == prevSideNode )
6892 iPrevNode = iNode - 1;
6895 // there are 2 links to check
6900 // loop on links, to be precise, on the second node of links
6901 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
6902 const SMDS_MeshNode* n = nodes[ iNode ];
6904 if ( !volume.IsLinked( n, prevSideNode ))
6908 if ( iNode ) // a node before prevSideNode
6909 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
6910 else // a node after prevSideNode
6911 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
6913 // check if this link was already used
6914 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
6915 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
6916 if (!isJustChecked &&
6917 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
6919 // test a link geometrically
6920 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
6921 bool linkIsBetter = false;
6922 double dot = 0.0, dist = 0.0;
6923 if ( searchByDir ) { // choose most co-directed link
6924 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
6925 linkIsBetter = ( dot > maxDot );
6927 else { // choose link with the node closest to bordPos
6928 dist = ( nextXYZ - bordPos ).SquareModulus();
6929 linkIsBetter = ( dist < minDist );
6931 if ( linkIsBetter ) {
6940 } // loop on inverse elements of prevSideNode
6943 MESSAGE(" Cant find path by links of the Side 2 ");
6944 return SEW_BAD_SIDE_NODES;
6946 sideNodes.push_back( sideNode );
6947 sideElems.push_back( sideElem );
6948 foundSideLinkIDs.insert ( linkID );
6949 prevSideNode = sideNode;
6951 if ( *nBordIt == theBordLastNode )
6952 searchByDir = false;
6954 // find the next border link to compare with
6955 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
6956 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6957 // move to next border node if sideNode is before forward border node (bordPos)
6958 while ( *nBordIt != theBordLastNode && !searchByDir ) {
6959 prevBordNode = *nBordIt;
6961 bordPos = nBordXYZ[ *nBordIt ];
6962 bordDir = bordPos - nBordXYZ[ prevBordNode ];
6963 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
6967 while ( sideNode != theSideSecondNode );
6969 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
6970 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
6971 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
6973 } // end nodes search on the side 2
6975 // ============================
6976 // sew the border to the side 2
6977 // ============================
6979 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
6980 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
6982 TListOfListOfNodes nodeGroupsToMerge;
6983 if ( nbNodes[0] == nbNodes[1] ||
6984 ( theSideIsFreeBorder && !theSideThirdNode)) {
6986 // all nodes are to be merged
6988 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
6989 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
6990 nIt[0]++, nIt[1]++ )
6992 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
6993 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
6994 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
6999 // insert new nodes into the border and the side to get equal nb of segments
7001 // get normalized parameters of nodes on the borders
7002 //double param[ 2 ][ maxNbNodes ];
7004 param[0] = new double [ maxNbNodes ];
7005 param[1] = new double [ maxNbNodes ];
7007 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7008 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7009 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7010 const SMDS_MeshNode* nPrev = *nIt;
7011 double bordLength = 0;
7012 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7013 const SMDS_MeshNode* nCur = *nIt;
7014 gp_XYZ segment (nCur->X() - nPrev->X(),
7015 nCur->Y() - nPrev->Y(),
7016 nCur->Z() - nPrev->Z());
7017 double segmentLen = segment.Modulus();
7018 bordLength += segmentLen;
7019 param[ iBord ][ iNode ] = bordLength;
7022 // normalize within [0,1]
7023 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7024 param[ iBord ][ iNode ] /= bordLength;
7028 // loop on border segments
7029 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7030 int i[ 2 ] = { 0, 0 };
7031 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7032 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7034 TElemOfNodeListMap insertMap;
7035 TElemOfNodeListMap::iterator insertMapIt;
7037 // key: elem to insert nodes into
7038 // value: 2 nodes to insert between + nodes to be inserted
7040 bool next[ 2 ] = { false, false };
7042 // find min adjacent segment length after sewing
7043 double nextParam = 10., prevParam = 0;
7044 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7045 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7046 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7047 if ( i[ iBord ] > 0 )
7048 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7050 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7051 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7052 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7054 // choose to insert or to merge nodes
7055 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7056 if ( Abs( du ) <= minSegLen * 0.2 ) {
7059 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7060 const SMDS_MeshNode* n0 = *nIt[0];
7061 const SMDS_MeshNode* n1 = *nIt[1];
7062 nodeGroupsToMerge.back().push_back( n1 );
7063 nodeGroupsToMerge.back().push_back( n0 );
7064 // position of node of the border changes due to merge
7065 param[ 0 ][ i[0] ] += du;
7066 // move n1 for the sake of elem shape evaluation during insertion.
7067 // n1 will be removed by MergeNodes() anyway
7068 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7069 next[0] = next[1] = true;
7074 int intoBord = ( du < 0 ) ? 0 : 1;
7075 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7076 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7077 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7078 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7079 if ( intoBord == 1 ) {
7080 // move node of the border to be on a link of elem of the side
7081 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7082 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7083 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7084 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7085 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7087 insertMapIt = insertMap.find( elem );
7088 bool notFound = ( insertMapIt == insertMap.end() );
7089 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7091 // insert into another link of the same element:
7092 // 1. perform insertion into the other link of the elem
7093 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7094 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7095 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7096 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7097 // 2. perform insertion into the link of adjacent faces
7099 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7101 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7105 if (toCreatePolyedrs) {
7106 // perform insertion into the links of adjacent volumes
7107 UpdateVolumes(n12, n22, nodeList);
7109 // 3. find an element appeared on n1 and n2 after the insertion
7110 insertMap.erase( elem );
7111 elem = findAdjacentFace( n1, n2, 0 );
7113 if ( notFound || otherLink ) {
7114 // add element and nodes of the side into the insertMap
7115 insertMapIt = insertMap.insert
7116 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7117 (*insertMapIt).second.push_back( n1 );
7118 (*insertMapIt).second.push_back( n2 );
7120 // add node to be inserted into elem
7121 (*insertMapIt).second.push_back( nIns );
7122 next[ 1 - intoBord ] = true;
7125 // go to the next segment
7126 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7127 if ( next[ iBord ] ) {
7128 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7130 nPrev[ iBord ] = *nIt[ iBord ];
7131 nIt[ iBord ]++; i[ iBord ]++;
7135 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7137 // perform insertion of nodes into elements
7139 for (insertMapIt = insertMap.begin();
7140 insertMapIt != insertMap.end();
7143 const SMDS_MeshElement* elem = (*insertMapIt).first;
7144 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7145 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7146 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7148 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7150 if ( !theSideIsFreeBorder ) {
7151 // look for and insert nodes into the faces adjacent to elem
7153 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7155 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7160 if (toCreatePolyedrs) {
7161 // perform insertion into the links of adjacent volumes
7162 UpdateVolumes(n1, n2, nodeList);
7168 } // end: insert new nodes
7170 MergeNodes ( nodeGroupsToMerge );
7175 //=======================================================================
7176 //function : InsertNodesIntoLink
7177 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7178 // and theBetweenNode2 and split theElement
7179 //=======================================================================
7181 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7182 const SMDS_MeshNode* theBetweenNode1,
7183 const SMDS_MeshNode* theBetweenNode2,
7184 list<const SMDS_MeshNode*>& theNodesToInsert,
7185 const bool toCreatePoly)
7187 if ( theFace->GetType() != SMDSAbs_Face ) return;
7189 // find indices of 2 link nodes and of the rest nodes
7190 int iNode = 0, il1, il2, i3, i4;
7191 il1 = il2 = i3 = i4 = -1;
7192 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7193 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7195 if(theFace->IsQuadratic()) {
7196 const SMDS_QuadraticFaceOfNodes* F =
7197 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7198 // use special nodes iterator
7199 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7200 while( anIter->more() ) {
7201 const SMDS_MeshNode* n = anIter->next();
7202 if ( n == theBetweenNode1 )
7204 else if ( n == theBetweenNode2 )
7210 nodes[ iNode++ ] = n;
7214 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7215 while ( nodeIt->more() ) {
7216 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7217 if ( n == theBetweenNode1 )
7219 else if ( n == theBetweenNode2 )
7225 nodes[ iNode++ ] = n;
7228 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7231 // arrange link nodes to go one after another regarding the face orientation
7232 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7233 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7238 aNodesToInsert.reverse();
7240 // check that not link nodes of a quadrangles are in good order
7241 int nbFaceNodes = theFace->NbNodes();
7242 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7248 if (toCreatePoly || theFace->IsPoly()) {
7251 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7253 // add nodes of face up to first node of link
7256 if(theFace->IsQuadratic()) {
7257 const SMDS_QuadraticFaceOfNodes* F =
7258 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7259 // use special nodes iterator
7260 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7261 while( anIter->more() && !isFLN ) {
7262 const SMDS_MeshNode* n = anIter->next();
7263 poly_nodes[iNode++] = n;
7264 if (n == nodes[il1]) {
7268 // add nodes to insert
7269 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7270 for (; nIt != aNodesToInsert.end(); nIt++) {
7271 poly_nodes[iNode++] = *nIt;
7273 // add nodes of face starting from last node of link
7274 while ( anIter->more() ) {
7275 poly_nodes[iNode++] = anIter->next();
7279 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7280 while ( nodeIt->more() && !isFLN ) {
7281 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7282 poly_nodes[iNode++] = n;
7283 if (n == nodes[il1]) {
7287 // add nodes to insert
7288 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7289 for (; nIt != aNodesToInsert.end(); nIt++) {
7290 poly_nodes[iNode++] = *nIt;
7292 // add nodes of face starting from last node of link
7293 while ( nodeIt->more() ) {
7294 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7295 poly_nodes[iNode++] = n;
7299 // edit or replace the face
7300 SMESHDS_Mesh *aMesh = GetMeshDS();
7302 if (theFace->IsPoly()) {
7303 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7306 int aShapeId = FindShape( theFace );
7308 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7309 myLastCreatedElems.Append(newElem);
7310 if ( aShapeId && newElem )
7311 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7313 aMesh->RemoveElement(theFace);
7318 if( !theFace->IsQuadratic() ) {
7320 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7321 int nbLinkNodes = 2 + aNodesToInsert.size();
7322 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7323 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7324 linkNodes[ 0 ] = nodes[ il1 ];
7325 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7326 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7327 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7328 linkNodes[ iNode++ ] = *nIt;
7330 // decide how to split a quadrangle: compare possible variants
7331 // and choose which of splits to be a quadrangle
7332 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7333 if ( nbFaceNodes == 3 ) {
7334 iBestQuad = nbSplits;
7337 else if ( nbFaceNodes == 4 ) {
7338 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7339 double aBestRate = DBL_MAX;
7340 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7342 double aBadRate = 0;
7343 // evaluate elements quality
7344 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7345 if ( iSplit == iQuad ) {
7346 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7350 aBadRate += getBadRate( &quad, aCrit );
7353 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7355 nodes[ iSplit < iQuad ? i4 : i3 ]);
7356 aBadRate += getBadRate( &tria, aCrit );
7360 if ( aBadRate < aBestRate ) {
7362 aBestRate = aBadRate;
7367 // create new elements
7368 SMESHDS_Mesh *aMesh = GetMeshDS();
7369 int aShapeId = FindShape( theFace );
7372 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7373 SMDS_MeshElement* newElem = 0;
7374 if ( iSplit == iBestQuad )
7375 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7380 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7382 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7383 myLastCreatedElems.Append(newElem);
7384 if ( aShapeId && newElem )
7385 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7388 // change nodes of theFace
7389 const SMDS_MeshNode* newNodes[ 4 ];
7390 newNodes[ 0 ] = linkNodes[ i1 ];
7391 newNodes[ 1 ] = linkNodes[ i2 ];
7392 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7393 newNodes[ 3 ] = nodes[ i4 ];
7394 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7395 } // end if(!theFace->IsQuadratic())
7396 else { // theFace is quadratic
7397 // we have to split theFace on simple triangles and one simple quadrangle
7399 int nbshift = tmp*2;
7400 // shift nodes in nodes[] by nbshift
7402 for(i=0; i<nbshift; i++) {
7403 const SMDS_MeshNode* n = nodes[0];
7404 for(j=0; j<nbFaceNodes-1; j++) {
7405 nodes[j] = nodes[j+1];
7407 nodes[nbFaceNodes-1] = n;
7409 il1 = il1 - nbshift;
7410 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7411 // n0 n1 n2 n0 n1 n2
7412 // +-----+-----+ +-----+-----+
7421 // create new elements
7422 SMESHDS_Mesh *aMesh = GetMeshDS();
7423 int aShapeId = FindShape( theFace );
7426 if(nbFaceNodes==6) { // quadratic triangle
7427 SMDS_MeshElement* newElem =
7428 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7429 myLastCreatedElems.Append(newElem);
7430 if ( aShapeId && newElem )
7431 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7432 if(theFace->IsMediumNode(nodes[il1])) {
7433 // create quadrangle
7434 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7435 myLastCreatedElems.Append(newElem);
7436 if ( aShapeId && newElem )
7437 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7443 // create quadrangle
7444 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7445 myLastCreatedElems.Append(newElem);
7446 if ( aShapeId && newElem )
7447 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7453 else { // nbFaceNodes==8 - quadratic quadrangle
7454 SMDS_MeshElement* newElem =
7455 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7456 myLastCreatedElems.Append(newElem);
7457 if ( aShapeId && newElem )
7458 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7459 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7460 myLastCreatedElems.Append(newElem);
7461 if ( aShapeId && newElem )
7462 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7463 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7464 myLastCreatedElems.Append(newElem);
7465 if ( aShapeId && newElem )
7466 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7467 if(theFace->IsMediumNode(nodes[il1])) {
7468 // create quadrangle
7469 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7470 myLastCreatedElems.Append(newElem);
7471 if ( aShapeId && newElem )
7472 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7478 // create quadrangle
7479 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7480 myLastCreatedElems.Append(newElem);
7481 if ( aShapeId && newElem )
7482 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7488 // create needed triangles using n1,n2,n3 and inserted nodes
7489 int nbn = 2 + aNodesToInsert.size();
7490 //const SMDS_MeshNode* aNodes[nbn];
7491 vector<const SMDS_MeshNode*> aNodes(nbn);
7492 aNodes[0] = nodes[n1];
7493 aNodes[nbn-1] = nodes[n2];
7494 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7495 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7496 aNodes[iNode++] = *nIt;
7498 for(i=1; i<nbn; i++) {
7499 SMDS_MeshElement* newElem =
7500 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7501 myLastCreatedElems.Append(newElem);
7502 if ( aShapeId && newElem )
7503 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7505 // remove old quadratic face
7506 aMesh->RemoveElement(theFace);
7510 //=======================================================================
7511 //function : UpdateVolumes
7513 //=======================================================================
7514 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7515 const SMDS_MeshNode* theBetweenNode2,
7516 list<const SMDS_MeshNode*>& theNodesToInsert)
7518 myLastCreatedElems.Clear();
7519 myLastCreatedNodes.Clear();
7521 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7522 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7523 const SMDS_MeshElement* elem = invElemIt->next();
7525 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7526 SMDS_VolumeTool aVolume (elem);
7527 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7530 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7531 int iface, nbFaces = aVolume.NbFaces();
7532 vector<const SMDS_MeshNode *> poly_nodes;
7533 vector<int> quantities (nbFaces);
7535 for (iface = 0; iface < nbFaces; iface++) {
7536 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7537 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7538 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7540 for (int inode = 0; inode < nbFaceNodes; inode++) {
7541 poly_nodes.push_back(faceNodes[inode]);
7543 if (nbInserted == 0) {
7544 if (faceNodes[inode] == theBetweenNode1) {
7545 if (faceNodes[inode + 1] == theBetweenNode2) {
7546 nbInserted = theNodesToInsert.size();
7548 // add nodes to insert
7549 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7550 for (; nIt != theNodesToInsert.end(); nIt++) {
7551 poly_nodes.push_back(*nIt);
7555 else if (faceNodes[inode] == theBetweenNode2) {
7556 if (faceNodes[inode + 1] == theBetweenNode1) {
7557 nbInserted = theNodesToInsert.size();
7559 // add nodes to insert in reversed order
7560 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7562 for (; nIt != theNodesToInsert.begin(); nIt--) {
7563 poly_nodes.push_back(*nIt);
7565 poly_nodes.push_back(*nIt);
7572 quantities[iface] = nbFaceNodes + nbInserted;
7575 // Replace or update the volume
7576 SMESHDS_Mesh *aMesh = GetMeshDS();
7578 if (elem->IsPoly()) {
7579 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7583 int aShapeId = FindShape( elem );
7585 SMDS_MeshElement* newElem =
7586 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7587 myLastCreatedElems.Append(newElem);
7588 if (aShapeId && newElem)
7589 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7591 aMesh->RemoveElement(elem);
7596 //=======================================================================
7598 * \brief Convert elements contained in a submesh to quadratic
7599 * \retval int - nb of checked elements
7601 //=======================================================================
7603 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7604 SMESH_MesherHelper& theHelper,
7605 const bool theForce3d)
7608 if( !theSm ) return nbElem;
7610 const bool notFromGroups = false;
7611 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7612 while(ElemItr->more())
7615 const SMDS_MeshElement* elem = ElemItr->next();
7616 if( !elem || elem->IsQuadratic() ) continue;
7618 int id = elem->GetID();
7619 int nbNodes = elem->NbNodes();
7620 vector<const SMDS_MeshNode *> aNds (nbNodes);
7622 for(int i = 0; i < nbNodes; i++)
7624 aNds[i] = elem->GetNode(i);
7626 SMDSAbs_ElementType aType = elem->GetType();
7628 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7630 const SMDS_MeshElement* NewElem = 0;
7636 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7644 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7647 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7654 case SMDSAbs_Volume :
7659 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7662 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
7665 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7668 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7669 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7679 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
7681 theSm->AddElement( NewElem );
7686 //=======================================================================
7687 //function : ConvertToQuadratic
7689 //=======================================================================
7690 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
7692 SMESHDS_Mesh* meshDS = GetMeshDS();
7694 SMESH_MesherHelper aHelper(*myMesh);
7695 aHelper.SetIsQuadratic( true );
7696 const bool notFromGroups = false;
7698 int nbCheckedElems = 0;
7699 if ( myMesh->HasShapeToMesh() )
7701 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7703 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7704 while ( smIt->more() ) {
7705 SMESH_subMesh* sm = smIt->next();
7706 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
7707 aHelper.SetSubShape( sm->GetSubShape() );
7708 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
7713 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
7714 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7716 SMESHDS_SubMesh *smDS = 0;
7717 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
7718 while(aEdgeItr->more())
7720 const SMDS_MeshEdge* edge = aEdgeItr->next();
7721 if(edge && !edge->IsQuadratic())
7723 int id = edge->GetID();
7724 const SMDS_MeshNode* n1 = edge->GetNode(0);
7725 const SMDS_MeshNode* n2 = edge->GetNode(1);
7727 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
7729 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
7730 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
7733 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
7734 while(aFaceItr->more())
7736 const SMDS_MeshFace* face = aFaceItr->next();
7737 if(!face || face->IsQuadratic() ) continue;
7739 int id = face->GetID();
7740 int nbNodes = face->NbNodes();
7741 vector<const SMDS_MeshNode *> aNds (nbNodes);
7743 for(int i = 0; i < nbNodes; i++)
7745 aNds[i] = face->GetNode(i);
7748 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
7750 SMDS_MeshFace * NewFace = 0;
7754 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7757 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7762 ReplaceElemInGroups( face, NewFace, GetMeshDS());
7764 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
7765 while(aVolumeItr->more())
7767 const SMDS_MeshVolume* volume = aVolumeItr->next();
7768 if(!volume || volume->IsQuadratic() ) continue;
7770 int id = volume->GetID();
7771 int nbNodes = volume->NbNodes();
7772 vector<const SMDS_MeshNode *> aNds (nbNodes);
7774 for(int i = 0; i < nbNodes; i++)
7776 aNds[i] = volume->GetNode(i);
7779 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
7781 SMDS_MeshVolume * NewVolume = 0;
7785 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7786 aNds[3], id, theForce3d );
7789 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7790 aNds[3], aNds[4], id, theForce3d);
7793 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
7794 aNds[3], aNds[4], aNds[5], id, theForce3d);
7797 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7798 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
7803 ReplaceElemInGroups(volume, NewVolume, meshDS);
7806 if ( !theForce3d ) {
7807 aHelper.SetSubShape(0); // apply to the whole mesh
7808 aHelper.FixQuadraticElements();
7812 //=======================================================================
7814 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
7815 * \retval int - nb of checked elements
7817 //=======================================================================
7819 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
7820 SMDS_ElemIteratorPtr theItr,
7821 const int theShapeID)
7824 SMESHDS_Mesh* meshDS = GetMeshDS();
7825 const bool notFromGroups = false;
7827 while( theItr->more() )
7829 const SMDS_MeshElement* elem = theItr->next();
7831 if( elem && elem->IsQuadratic())
7833 int id = elem->GetID();
7834 int nbNodes = elem->NbNodes();
7835 vector<const SMDS_MeshNode *> aNds, mediumNodes;
7836 aNds.reserve( nbNodes );
7837 mediumNodes.reserve( nbNodes );
7839 for(int i = 0; i < nbNodes; i++)
7841 const SMDS_MeshNode* n = elem->GetNode(i);
7843 if( elem->IsMediumNode( n ) )
7844 mediumNodes.push_back( n );
7846 aNds.push_back( n );
7848 if( aNds.empty() ) continue;
7849 SMDSAbs_ElementType aType = elem->GetType();
7851 //remove old quadratic element
7852 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
7854 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
7855 ReplaceElemInGroups(elem, NewElem, meshDS);
7856 if( theSm && NewElem )
7857 theSm->AddElement( NewElem );
7859 // remove medium nodes
7860 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
7861 for ( ; nIt != mediumNodes.end(); ++nIt ) {
7862 const SMDS_MeshNode* n = *nIt;
7863 if ( n->NbInverseElements() == 0 ) {
7864 if ( n->GetPosition()->GetShapeId() != theShapeID )
7865 meshDS->RemoveFreeNode( n, meshDS->MeshElements
7866 ( n->GetPosition()->GetShapeId() ));
7868 meshDS->RemoveFreeNode( n, theSm );
7876 //=======================================================================
7877 //function : ConvertFromQuadratic
7879 //=======================================================================
7880 bool SMESH_MeshEditor::ConvertFromQuadratic()
7882 int nbCheckedElems = 0;
7883 if ( myMesh->HasShapeToMesh() )
7885 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
7887 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
7888 while ( smIt->more() ) {
7889 SMESH_subMesh* sm = smIt->next();
7890 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
7891 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
7897 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
7898 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
7900 SMESHDS_SubMesh *aSM = 0;
7901 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
7907 //=======================================================================
7908 //function : SewSideElements
7910 //=======================================================================
7912 SMESH_MeshEditor::Sew_Error
7913 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
7914 TIDSortedElemSet& theSide2,
7915 const SMDS_MeshNode* theFirstNode1,
7916 const SMDS_MeshNode* theFirstNode2,
7917 const SMDS_MeshNode* theSecondNode1,
7918 const SMDS_MeshNode* theSecondNode2)
7920 myLastCreatedElems.Clear();
7921 myLastCreatedNodes.Clear();
7923 MESSAGE ("::::SewSideElements()");
7924 if ( theSide1.size() != theSide2.size() )
7925 return SEW_DIFF_NB_OF_ELEMENTS;
7927 Sew_Error aResult = SEW_OK;
7929 // 1. Build set of faces representing each side
7930 // 2. Find which nodes of the side 1 to merge with ones on the side 2
7931 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
7933 // =======================================================================
7934 // 1. Build set of faces representing each side:
7935 // =======================================================================
7936 // a. build set of nodes belonging to faces
7937 // b. complete set of faces: find missing fices whose nodes are in set of nodes
7938 // c. create temporary faces representing side of volumes if correspondent
7939 // face does not exist
7941 SMESHDS_Mesh* aMesh = GetMeshDS();
7942 SMDS_Mesh aTmpFacesMesh;
7943 set<const SMDS_MeshElement*> faceSet1, faceSet2;
7944 set<const SMDS_MeshElement*> volSet1, volSet2;
7945 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
7946 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
7947 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
7948 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
7949 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
7950 int iSide, iFace, iNode;
7952 for ( iSide = 0; iSide < 2; iSide++ ) {
7953 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
7954 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
7955 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
7956 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
7957 set<const SMDS_MeshElement*>::iterator vIt;
7958 TIDSortedElemSet::iterator eIt;
7959 set<const SMDS_MeshNode*>::iterator nIt;
7961 // check that given nodes belong to given elements
7962 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
7963 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
7964 int firstIndex = -1, secondIndex = -1;
7965 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7966 const SMDS_MeshElement* elem = *eIt;
7967 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
7968 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
7969 if ( firstIndex > -1 && secondIndex > -1 ) break;
7971 if ( firstIndex < 0 || secondIndex < 0 ) {
7972 // we can simply return until temporary faces created
7973 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
7976 // -----------------------------------------------------------
7977 // 1a. Collect nodes of existing faces
7978 // and build set of face nodes in order to detect missing
7979 // faces corresponing to sides of volumes
7980 // -----------------------------------------------------------
7982 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
7984 // loop on the given element of a side
7985 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
7986 //const SMDS_MeshElement* elem = *eIt;
7987 const SMDS_MeshElement* elem = *eIt;
7988 if ( elem->GetType() == SMDSAbs_Face ) {
7989 faceSet->insert( elem );
7990 set <const SMDS_MeshNode*> faceNodeSet;
7991 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
7992 while ( nodeIt->more() ) {
7993 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7994 nodeSet->insert( n );
7995 faceNodeSet.insert( n );
7997 setOfFaceNodeSet.insert( faceNodeSet );
7999 else if ( elem->GetType() == SMDSAbs_Volume )
8000 volSet->insert( elem );
8002 // ------------------------------------------------------------------------------
8003 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8004 // ------------------------------------------------------------------------------
8006 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8007 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8008 while ( fIt->more() ) { // loop on faces sharing a node
8009 const SMDS_MeshElement* f = fIt->next();
8010 if ( faceSet->find( f ) == faceSet->end() ) {
8011 // check if all nodes are in nodeSet and
8012 // complete setOfFaceNodeSet if they are
8013 set <const SMDS_MeshNode*> faceNodeSet;
8014 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8015 bool allInSet = true;
8016 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8017 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8018 if ( nodeSet->find( n ) == nodeSet->end() )
8021 faceNodeSet.insert( n );
8024 faceSet->insert( f );
8025 setOfFaceNodeSet.insert( faceNodeSet );
8031 // -------------------------------------------------------------------------
8032 // 1c. Create temporary faces representing sides of volumes if correspondent
8033 // face does not exist
8034 // -------------------------------------------------------------------------
8036 if ( !volSet->empty() ) {
8037 //int nodeSetSize = nodeSet->size();
8039 // loop on given volumes
8040 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8041 SMDS_VolumeTool vol (*vIt);
8042 // loop on volume faces: find free faces
8043 // --------------------------------------
8044 list<const SMDS_MeshElement* > freeFaceList;
8045 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8046 if ( !vol.IsFreeFace( iFace ))
8048 // check if there is already a face with same nodes in a face set
8049 const SMDS_MeshElement* aFreeFace = 0;
8050 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8051 int nbNodes = vol.NbFaceNodes( iFace );
8052 set <const SMDS_MeshNode*> faceNodeSet;
8053 vol.GetFaceNodes( iFace, faceNodeSet );
8054 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8056 // no such a face is given but it still can exist, check it
8057 if ( nbNodes == 3 ) {
8058 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8060 else if ( nbNodes == 4 ) {
8061 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8064 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8065 aFreeFace = aMesh->FindFace(poly_nodes);
8069 // create a temporary face
8070 if ( nbNodes == 3 ) {
8071 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8073 else if ( nbNodes == 4 ) {
8074 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8077 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8078 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8082 freeFaceList.push_back( aFreeFace );
8084 } // loop on faces of a volume
8086 // choose one of several free faces
8087 // --------------------------------------
8088 if ( freeFaceList.size() > 1 ) {
8089 // choose a face having max nb of nodes shared by other elems of a side
8090 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8091 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8092 while ( fIt != freeFaceList.end() ) { // loop on free faces
8093 int nbSharedNodes = 0;
8094 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8095 while ( nodeIt->more() ) { // loop on free face nodes
8096 const SMDS_MeshNode* n =
8097 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8098 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8099 while ( invElemIt->more() ) {
8100 const SMDS_MeshElement* e = invElemIt->next();
8101 if ( faceSet->find( e ) != faceSet->end() )
8103 if ( elemSet->find( e ) != elemSet->end() )
8107 if ( nbSharedNodes >= maxNbNodes ) {
8108 maxNbNodes = nbSharedNodes;
8112 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8114 if ( freeFaceList.size() > 1 )
8116 // could not choose one face, use another way
8117 // choose a face most close to the bary center of the opposite side
8118 gp_XYZ aBC( 0., 0., 0. );
8119 set <const SMDS_MeshNode*> addedNodes;
8120 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8121 eIt = elemSet2->begin();
8122 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8123 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8124 while ( nodeIt->more() ) { // loop on free face nodes
8125 const SMDS_MeshNode* n =
8126 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8127 if ( addedNodes.insert( n ).second )
8128 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8131 aBC /= addedNodes.size();
8132 double minDist = DBL_MAX;
8133 fIt = freeFaceList.begin();
8134 while ( fIt != freeFaceList.end() ) { // loop on free faces
8136 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8137 while ( nodeIt->more() ) { // loop on free face nodes
8138 const SMDS_MeshNode* n =
8139 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8140 gp_XYZ p( n->X(),n->Y(),n->Z() );
8141 dist += ( aBC - p ).SquareModulus();
8143 if ( dist < minDist ) {
8145 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8148 fIt = freeFaceList.erase( fIt++ );
8151 } // choose one of several free faces of a volume
8153 if ( freeFaceList.size() == 1 ) {
8154 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8155 faceSet->insert( aFreeFace );
8156 // complete a node set with nodes of a found free face
8157 // for ( iNode = 0; iNode < ; iNode++ )
8158 // nodeSet->insert( fNodes[ iNode ] );
8161 } // loop on volumes of a side
8163 // // complete a set of faces if new nodes in a nodeSet appeared
8164 // // ----------------------------------------------------------
8165 // if ( nodeSetSize != nodeSet->size() ) {
8166 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8167 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8168 // while ( fIt->more() ) { // loop on faces sharing a node
8169 // const SMDS_MeshElement* f = fIt->next();
8170 // if ( faceSet->find( f ) == faceSet->end() ) {
8171 // // check if all nodes are in nodeSet and
8172 // // complete setOfFaceNodeSet if they are
8173 // set <const SMDS_MeshNode*> faceNodeSet;
8174 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8175 // bool allInSet = true;
8176 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8177 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8178 // if ( nodeSet->find( n ) == nodeSet->end() )
8179 // allInSet = false;
8181 // faceNodeSet.insert( n );
8183 // if ( allInSet ) {
8184 // faceSet->insert( f );
8185 // setOfFaceNodeSet.insert( faceNodeSet );
8191 } // Create temporary faces, if there are volumes given
8194 if ( faceSet1.size() != faceSet2.size() ) {
8195 // delete temporary faces: they are in reverseElements of actual nodes
8196 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8197 while ( tmpFaceIt->more() )
8198 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8199 MESSAGE("Diff nb of faces");
8200 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8203 // ============================================================
8204 // 2. Find nodes to merge:
8205 // bind a node to remove to a node to put instead
8206 // ============================================================
8208 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8209 if ( theFirstNode1 != theFirstNode2 )
8210 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8211 if ( theSecondNode1 != theSecondNode2 )
8212 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8214 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8215 set< long > linkIdSet; // links to process
8216 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8218 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8219 list< NLink > linkList[2];
8220 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8221 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8222 // loop on links in linkList; find faces by links and append links
8223 // of the found faces to linkList
8224 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8225 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8226 NLink link[] = { *linkIt[0], *linkIt[1] };
8227 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8228 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8231 // by links, find faces in the face sets,
8232 // and find indices of link nodes in the found faces;
8233 // in a face set, there is only one or no face sharing a link
8234 // ---------------------------------------------------------------
8236 const SMDS_MeshElement* face[] = { 0, 0 };
8237 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8238 vector<const SMDS_MeshNode*> fnodes1(9);
8239 vector<const SMDS_MeshNode*> fnodes2(9);
8240 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8241 vector<const SMDS_MeshNode*> notLinkNodes1(6);
8242 vector<const SMDS_MeshNode*> notLinkNodes2(6);
8243 int iLinkNode[2][2];
8244 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8245 const SMDS_MeshNode* n1 = link[iSide].first;
8246 const SMDS_MeshNode* n2 = link[iSide].second;
8247 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8248 set< const SMDS_MeshElement* > fMap;
8249 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8250 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8251 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8252 while ( fIt->more() ) { // loop on faces sharing a node
8253 const SMDS_MeshElement* f = fIt->next();
8254 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8255 ! fMap.insert( f ).second ) // f encounters twice
8257 if ( face[ iSide ] ) {
8258 MESSAGE( "2 faces per link " );
8259 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8263 faceSet->erase( f );
8264 // get face nodes and find ones of a link
8269 fnodes1.resize(f->NbNodes()+1);
8270 notLinkNodes1.resize(f->NbNodes()-2);
8273 fnodes2.resize(f->NbNodes()+1);
8274 notLinkNodes2.resize(f->NbNodes()-2);
8277 if(!f->IsQuadratic()) {
8278 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8279 while ( nIt->more() ) {
8280 const SMDS_MeshNode* n =
8281 static_cast<const SMDS_MeshNode*>( nIt->next() );
8283 iLinkNode[ iSide ][ 0 ] = iNode;
8285 else if ( n == n2 ) {
8286 iLinkNode[ iSide ][ 1 ] = iNode;
8288 //else if ( notLinkNodes[ iSide ][ 0 ] )
8289 // notLinkNodes[ iSide ][ 1 ] = n;
8291 // notLinkNodes[ iSide ][ 0 ] = n;
8295 notLinkNodes1[nbl] = n;
8296 //notLinkNodes1.push_back(n);
8298 notLinkNodes2[nbl] = n;
8299 //notLinkNodes2.push_back(n);
8301 //faceNodes[ iSide ][ iNode++ ] = n;
8303 fnodes1[iNode++] = n;
8306 fnodes2[iNode++] = n;
8310 else { // f->IsQuadratic()
8311 const SMDS_QuadraticFaceOfNodes* F =
8312 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8313 // use special nodes iterator
8314 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8315 while ( anIter->more() ) {
8316 const SMDS_MeshNode* n =
8317 static_cast<const SMDS_MeshNode*>( anIter->next() );
8319 iLinkNode[ iSide ][ 0 ] = iNode;
8321 else if ( n == n2 ) {
8322 iLinkNode[ iSide ][ 1 ] = iNode;
8327 notLinkNodes1[nbl] = n;
8330 notLinkNodes2[nbl] = n;
8334 fnodes1[iNode++] = n;
8337 fnodes2[iNode++] = n;
8341 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8343 fnodes1[iNode] = fnodes1[0];
8346 fnodes2[iNode] = fnodes1[0];
8353 // check similarity of elements of the sides
8354 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8355 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8356 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8357 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8360 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8362 break; // do not return because it s necessary to remove tmp faces
8365 // set nodes to merge
8366 // -------------------
8368 if ( face[0] && face[1] ) {
8369 int nbNodes = face[0]->NbNodes();
8370 if ( nbNodes != face[1]->NbNodes() ) {
8371 MESSAGE("Diff nb of face nodes");
8372 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8373 break; // do not return because it s necessary to remove tmp faces
8375 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8376 if ( nbNodes == 3 ) {
8377 //nReplaceMap.insert( TNodeNodeMap::value_type
8378 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8379 nReplaceMap.insert( TNodeNodeMap::value_type
8380 ( notLinkNodes1[0], notLinkNodes2[0] ));
8383 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8384 // analyse link orientation in faces
8385 int i1 = iLinkNode[ iSide ][ 0 ];
8386 int i2 = iLinkNode[ iSide ][ 1 ];
8387 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8388 // if notLinkNodes are the first and the last ones, then
8389 // their order does not correspond to the link orientation
8390 if (( i1 == 1 && i2 == 2 ) ||
8391 ( i1 == 2 && i2 == 1 ))
8392 reverse[ iSide ] = !reverse[ iSide ];
8394 if ( reverse[0] == reverse[1] ) {
8395 //nReplaceMap.insert( TNodeNodeMap::value_type
8396 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8397 //nReplaceMap.insert( TNodeNodeMap::value_type
8398 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8399 for(int nn=0; nn<nbNodes-2; nn++) {
8400 nReplaceMap.insert( TNodeNodeMap::value_type
8401 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8405 //nReplaceMap.insert( TNodeNodeMap::value_type
8406 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8407 //nReplaceMap.insert( TNodeNodeMap::value_type
8408 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8409 for(int nn=0; nn<nbNodes-2; nn++) {
8410 nReplaceMap.insert( TNodeNodeMap::value_type
8411 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8416 // add other links of the faces to linkList
8417 // -----------------------------------------
8419 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8420 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8421 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8422 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8423 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8424 if ( !iter_isnew.second ) { // already in a set: no need to process
8425 linkIdSet.erase( iter_isnew.first );
8427 else // new in set == encountered for the first time: add
8429 //const SMDS_MeshNode* n1 = nodes[ iNode ];
8430 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8431 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8432 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8433 linkList[0].push_back ( NLink( n1, n2 ));
8434 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8438 } // loop on link lists
8440 if ( aResult == SEW_OK &&
8441 ( linkIt[0] != linkList[0].end() ||
8442 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8443 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8444 " " << (faceSetPtr[1]->empty()));
8445 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8448 // ====================================================================
8449 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8450 // ====================================================================
8452 // delete temporary faces: they are in reverseElements of actual nodes
8453 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8454 while ( tmpFaceIt->more() )
8455 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8457 if ( aResult != SEW_OK)
8460 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8461 // loop on nodes replacement map
8462 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8463 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8464 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8465 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8466 nodeIDsToRemove.push_back( nToRemove->GetID() );
8467 // loop on elements sharing nToRemove
8468 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8469 while ( invElemIt->more() ) {
8470 const SMDS_MeshElement* e = invElemIt->next();
8471 // get a new suite of nodes: make replacement
8472 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8473 vector< const SMDS_MeshNode*> nodes( nbNodes );
8474 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8475 while ( nIt->more() ) {
8476 const SMDS_MeshNode* n =
8477 static_cast<const SMDS_MeshNode*>( nIt->next() );
8478 nnIt = nReplaceMap.find( n );
8479 if ( nnIt != nReplaceMap.end() ) {
8485 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8486 // elemIDsToRemove.push_back( e->GetID() );
8489 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8493 Remove( nodeIDsToRemove, true );
8498 //================================================================================
8500 * \brief Find corresponding nodes in two sets of faces
8501 * \param theSide1 - first face set
8502 * \param theSide2 - second first face
8503 * \param theFirstNode1 - a boundary node of set 1
8504 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8505 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8506 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8507 * \param nReplaceMap - output map of corresponding nodes
8508 * \retval bool - is a success or not
8510 //================================================================================
8513 //#define DEBUG_MATCHING_NODES
8516 SMESH_MeshEditor::Sew_Error
8517 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8518 set<const SMDS_MeshElement*>& theSide2,
8519 const SMDS_MeshNode* theFirstNode1,
8520 const SMDS_MeshNode* theFirstNode2,
8521 const SMDS_MeshNode* theSecondNode1,
8522 const SMDS_MeshNode* theSecondNode2,
8523 TNodeNodeMap & nReplaceMap)
8525 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8527 nReplaceMap.clear();
8528 if ( theFirstNode1 != theFirstNode2 )
8529 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8530 if ( theSecondNode1 != theSecondNode2 )
8531 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8533 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8534 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8536 list< NLink > linkList[2];
8537 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8538 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8540 // loop on links in linkList; find faces by links and append links
8541 // of the found faces to linkList
8542 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8543 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8544 NLink link[] = { *linkIt[0], *linkIt[1] };
8545 if ( linkSet.find( link[0] ) == linkSet.end() )
8548 // by links, find faces in the face sets,
8549 // and find indices of link nodes in the found faces;
8550 // in a face set, there is only one or no face sharing a link
8551 // ---------------------------------------------------------------
8553 const SMDS_MeshElement* face[] = { 0, 0 };
8554 list<const SMDS_MeshNode*> notLinkNodes[2];
8555 //bool reverse[] = { false, false }; // order of notLinkNodes
8557 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8559 const SMDS_MeshNode* n1 = link[iSide].first;
8560 const SMDS_MeshNode* n2 = link[iSide].second;
8561 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8562 set< const SMDS_MeshElement* > facesOfNode1;
8563 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8565 // during a loop of the first node, we find all faces around n1,
8566 // during a loop of the second node, we find one face sharing both n1 and n2
8567 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8568 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8569 while ( fIt->more() ) { // loop on faces sharing a node
8570 const SMDS_MeshElement* f = fIt->next();
8571 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8572 ! facesOfNode1.insert( f ).second ) // f encounters twice
8574 if ( face[ iSide ] ) {
8575 MESSAGE( "2 faces per link " );
8576 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8579 faceSet->erase( f );
8581 // get not link nodes
8582 int nbN = f->NbNodes();
8583 if ( f->IsQuadratic() )
8585 nbNodes[ iSide ] = nbN;
8586 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8587 int i1 = f->GetNodeIndex( n1 );
8588 int i2 = f->GetNodeIndex( n2 );
8589 int iEnd = nbN, iBeg = -1, iDelta = 1;
8590 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8592 std::swap( iEnd, iBeg ); iDelta = -1;
8597 if ( i == iEnd ) i = iBeg + iDelta;
8598 if ( i == i1 ) break;
8599 nodes.push_back ( f->GetNode( i ) );
8605 // check similarity of elements of the sides
8606 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8607 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8608 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8609 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8612 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8616 // set nodes to merge
8617 // -------------------
8619 if ( face[0] && face[1] ) {
8620 if ( nbNodes[0] != nbNodes[1] ) {
8621 MESSAGE("Diff nb of face nodes");
8622 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8624 #ifdef DEBUG_MATCHING_NODES
8625 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8626 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8627 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8629 int nbN = nbNodes[0];
8631 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8632 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8633 for ( int i = 0 ; i < nbN - 2; ++i ) {
8634 #ifdef DEBUG_MATCHING_NODES
8635 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8637 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8641 // add other links of the face 1 to linkList
8642 // -----------------------------------------
8644 const SMDS_MeshElement* f0 = face[0];
8645 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8646 for ( int i = 0; i < nbN; i++ )
8648 const SMDS_MeshNode* n2 = f0->GetNode( i );
8649 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8650 linkSet.insert( SMESH_TLink( n1, n2 ));
8651 if ( !iter_isnew.second ) { // already in a set: no need to process
8652 linkSet.erase( iter_isnew.first );
8654 else // new in set == encountered for the first time: add
8656 #ifdef DEBUG_MATCHING_NODES
8657 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8658 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8660 linkList[0].push_back ( NLink( n1, n2 ));
8661 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8666 } // loop on link lists
8671 //================================================================================
8673 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8674 \param theElems - the list of elements (edges or faces) to be replicated
8675 The nodes for duplication could be found from these elements
8676 \param theNodesNot - list of nodes to NOT replicate
8677 \param theAffectedElems - the list of elements (cells and edges) to which the
8678 replicated nodes should be associated to.
8679 \return TRUE if operation has been completed successfully, FALSE otherwise
8681 //================================================================================
8683 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
8684 const TIDSortedElemSet& theNodesNot,
8685 const TIDSortedElemSet& theAffectedElems )
8687 myLastCreatedElems.Clear();
8688 myLastCreatedNodes.Clear();
8690 if ( theElems.size() == 0 )
8693 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8698 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8699 // duplicate elements and nodes
8700 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
8701 // replce nodes by duplications
8702 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
8706 //================================================================================
8708 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8709 \param theMeshDS - mesh instance
8710 \param theElems - the elements replicated or modified (nodes should be changed)
8711 \param theNodesNot - nodes to NOT replicate
8712 \param theNodeNodeMap - relation of old node to new created node
8713 \param theIsDoubleElem - flag os to replicate element or modify
8714 \return TRUE if operation has been completed successfully, FALSE otherwise
8716 //================================================================================
8718 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
8719 const TIDSortedElemSet& theElems,
8720 const TIDSortedElemSet& theNodesNot,
8721 std::map< const SMDS_MeshNode*,
8722 const SMDS_MeshNode* >& theNodeNodeMap,
8723 const bool theIsDoubleElem )
8725 // iterate on through element and duplicate them (by nodes duplication)
8727 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8728 for ( ; elemItr != theElems.end(); ++elemItr )
8730 const SMDS_MeshElement* anElem = *elemItr;
8734 bool isDuplicate = false;
8735 // duplicate nodes to duplicate element
8736 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
8737 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8739 while ( anIter->more() )
8742 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8743 SMDS_MeshNode* aNewNode = aCurrNode;
8744 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
8745 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
8746 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
8749 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
8750 theNodeNodeMap[ aCurrNode ] = aNewNode;
8751 myLastCreatedNodes.Append( aNewNode );
8753 isDuplicate |= (aCurrNode != aNewNode);
8754 newNodes[ ind++ ] = aNewNode;
8759 if ( theIsDoubleElem )
8760 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
8762 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
8769 //================================================================================
8771 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8772 \param theNodes - identifiers of nodes to be doubled
8773 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
8774 nodes. If list of element identifiers is empty then nodes are doubled but
8775 they not assigned to elements
8776 \return TRUE if operation has been completed successfully, FALSE otherwise
8778 //================================================================================
8780 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
8781 const std::list< int >& theListOfModifiedElems )
8783 myLastCreatedElems.Clear();
8784 myLastCreatedNodes.Clear();
8786 if ( theListOfNodes.size() == 0 )
8789 SMESHDS_Mesh* aMeshDS = GetMeshDS();
8793 // iterate through nodes and duplicate them
8795 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
8797 std::list< int >::const_iterator aNodeIter;
8798 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
8800 int aCurr = *aNodeIter;
8801 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
8807 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
8810 anOldNodeToNewNode[ aNode ] = aNewNode;
8811 myLastCreatedNodes.Append( aNewNode );
8815 // Create map of new nodes for modified elements
8817 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
8819 std::list< int >::const_iterator anElemIter;
8820 for ( anElemIter = theListOfModifiedElems.begin();
8821 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
8823 int aCurr = *anElemIter;
8824 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
8828 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
8830 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
8832 while ( anIter->more() )
8834 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
8835 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
8837 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
8838 aNodeArr[ ind++ ] = aNewNode;
8841 aNodeArr[ ind++ ] = aCurrNode;
8843 anElemToNodes[ anElem ] = aNodeArr;
8846 // Change nodes of elements
8848 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
8849 anElemToNodesIter = anElemToNodes.begin();
8850 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
8852 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
8853 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
8855 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
8863 //================================================================================
8865 \brief Check if element located inside shape
8866 \return TRUE if IN or ON shape, FALSE otherwise
8868 //================================================================================
8870 template<class Classifier>
8871 bool isInside(const SMDS_MeshElement* theElem,
8872 Classifier& theClassifier,
8873 const double theTol)
8875 gp_XYZ centerXYZ (0, 0, 0);
8876 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
8877 while (aNodeItr->more())
8878 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
8880 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
8881 theClassifier.Perform(aPnt, theTol);
8882 TopAbs_State aState = theClassifier.State();
8883 return (aState == TopAbs_IN || aState == TopAbs_ON );
8886 //================================================================================
8888 * \brief Classifier of the 3D point on the TopoDS_Face
8889 * with interaface suitable for isInside()
8891 //================================================================================
8893 struct _FaceClassifier
8895 Extrema_ExtPS _extremum;
8896 BRepAdaptor_Surface _surface;
8897 TopAbs_State _state;
8899 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
8901 _extremum.Initialize( _surface,
8902 _surface.FirstUParameter(), _surface.LastUParameter(),
8903 _surface.FirstVParameter(), _surface.LastVParameter(),
8904 _surface.Tolerance(), _surface.Tolerance() );
8906 void Perform(const gp_Pnt& aPnt, double theTol)
8908 _state = TopAbs_OUT;
8909 _extremum.Perform(aPnt);
8910 if ( _extremum.IsDone() )
8911 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
8912 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
8914 TopAbs_State State() const
8921 //================================================================================
8923 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8924 \param theElems - group of of elements (edges or faces) to be replicated
8925 \param theNodesNot - group of nodes not to replicate
8926 \param theShape - shape to detect affected elements (element which geometric center
8927 located on or inside shape).
8928 The replicated nodes should be associated to affected elements.
8929 \return TRUE if operation has been completed successfully, FALSE otherwise
8931 //================================================================================
8933 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
8934 const TIDSortedElemSet& theNodesNot,
8935 const TopoDS_Shape& theShape )
8937 if ( theShape.IsNull() )
8940 const double aTol = Precision::Confusion();
8941 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
8942 auto_ptr<_FaceClassifier> aFaceClassifier;
8943 if ( theShape.ShapeType() == TopAbs_SOLID )
8945 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
8946 bsc3d->PerformInfinitePoint(aTol);
8948 else if (theShape.ShapeType() == TopAbs_FACE )
8950 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
8953 // iterates on indicated elements and get elements by back references from their nodes
8954 TIDSortedElemSet anAffected;
8955 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
8956 for ( ; elemItr != theElems.end(); ++elemItr )
8958 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
8962 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
8963 while ( nodeItr->more() )
8965 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
8966 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
8968 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
8969 while ( backElemItr->more() )
8971 const SMDS_MeshElement* curElem = backElemItr->next();
8972 if ( curElem && theElems.find(curElem) == theElems.end() &&
8974 isInside( curElem, *bsc3d, aTol ) :
8975 isInside( curElem, *aFaceClassifier, aTol )))
8976 anAffected.insert( curElem );
8980 return DoubleNodes( theElems, theNodesNot, anAffected );
8983 //================================================================================
8985 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
8986 * The created 2D mesh elements based on nodes of free faces of boundary volumes
8987 * \return TRUE if operation has been completed successfully, FALSE otherwise
8989 //================================================================================
8991 bool SMESH_MeshEditor::Make2DMeshFrom3D()
8993 // iterates on volume elements and detect all free faces on them
8994 SMESHDS_Mesh* aMesh = GetMeshDS();
8998 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9001 const SMDS_MeshVolume* volume = vIt->next();
9002 SMDS_VolumeTool vTool( volume );
9003 vTool.SetExternalNormal();
9004 const bool isPoly = volume->IsPoly();
9005 const bool isQuad = volume->IsQuadratic();
9006 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9008 if (!vTool.IsFreeFace(iface))
9010 vector<const SMDS_MeshNode *> nodes;
9011 int nbFaceNodes = vTool.NbFaceNodes(iface);
9012 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9014 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9015 nodes.push_back(faceNodes[inode]);
9017 for ( inode = 1; inode < nbFaceNodes; inode += 2)
9018 nodes.push_back(faceNodes[inode]);
9020 // add new face based on volume nodes
9021 if (aMesh->FindFace( nodes ) )
9022 continue; // face already exsist
9023 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );