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 );
4940 //=======================================================================
4943 //=======================================================================
4945 SMESH_MeshEditor::PGroupIDs
4946 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
4947 const gp_Pnt& thePoint,
4948 const std::list<double>& theScaleFact,
4950 const bool theMakeGroups,
4951 SMESH_Mesh* theTargetMesh)
4953 myLastCreatedElems.Clear();
4954 myLastCreatedNodes.Clear();
4956 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4957 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4958 SMESHDS_Mesh* aMesh = GetMeshDS();
4960 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
4961 std::list<double>::const_iterator itS = theScaleFact.begin();
4963 if(theScaleFact.size()==1) {
4967 if(theScaleFact.size()==2) {
4972 if(theScaleFact.size()>2) {
4979 // map old node to new one
4980 TNodeNodeMap nodeMap;
4982 // elements sharing moved nodes; those of them which have all
4983 // nodes mirrored but are not in theElems are to be reversed
4984 TIDSortedElemSet inverseElemSet;
4986 // source elements for each generated one
4987 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4990 TIDSortedElemSet::iterator itElem;
4991 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4992 const SMDS_MeshElement* elem = *itElem;
4996 // loop on elem nodes
4997 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4998 while ( itN->more() ) {
5000 // check if a node has been already transformed
5001 const SMDS_MeshNode* node = cast2Node( itN->next() );
5002 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5003 nodeMap.insert( make_pair ( node, node ));
5004 if ( !n2n_isnew.second )
5008 //coord[0] = node->X();
5009 //coord[1] = node->Y();
5010 //coord[2] = node->Z();
5011 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5012 double dx = (node->X() - thePoint.X()) * scaleX;
5013 double dy = (node->Y() - thePoint.Y()) * scaleY;
5014 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5015 if ( theTargetMesh ) {
5016 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5017 const SMDS_MeshNode * newNode =
5018 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5019 n2n_isnew.first->second = newNode;
5020 myLastCreatedNodes.Append(newNode);
5021 srcNodes.Append( node );
5023 else if ( theCopy ) {
5024 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5025 const SMDS_MeshNode * newNode =
5026 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5027 n2n_isnew.first->second = newNode;
5028 myLastCreatedNodes.Append(newNode);
5029 srcNodes.Append( node );
5032 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5033 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5034 // node position on shape becomes invalid
5035 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5036 ( SMDS_SpacePosition::originSpacePosition() );
5039 // keep inverse elements
5040 //if ( !theCopy && !theTargetMesh && needReverse ) {
5041 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5042 // while ( invElemIt->more() ) {
5043 // const SMDS_MeshElement* iel = invElemIt->next();
5044 // inverseElemSet.insert( iel );
5050 // either create new elements or reverse mirrored ones
5051 //if ( !theCopy && !needReverse && !theTargetMesh )
5052 if ( !theCopy && !theTargetMesh )
5055 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5056 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5057 theElems.insert( *invElemIt );
5059 // replicate or reverse elements
5062 REV_TETRA = 0, // = nbNodes - 4
5063 REV_PYRAMID = 1, // = nbNodes - 4
5064 REV_PENTA = 2, // = nbNodes - 4
5066 REV_HEXA = 4, // = nbNodes - 4
5070 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5071 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5072 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5073 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5074 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5075 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5078 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5080 const SMDS_MeshElement* elem = *itElem;
5081 if ( !elem || elem->GetType() == SMDSAbs_Node )
5084 int nbNodes = elem->NbNodes();
5085 int elemType = elem->GetType();
5087 if (elem->IsPoly()) {
5088 // Polygon or Polyhedral Volume
5089 switch ( elemType ) {
5092 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5094 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5095 while (itN->more()) {
5096 const SMDS_MeshNode* node =
5097 static_cast<const SMDS_MeshNode*>(itN->next());
5098 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5099 if (nodeMapIt == nodeMap.end())
5100 break; // not all nodes transformed
5101 //if (needReverse) {
5102 // // reverse mirrored faces and volumes
5103 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5105 poly_nodes[iNode] = (*nodeMapIt).second;
5109 if ( iNode != nbNodes )
5110 continue; // not all nodes transformed
5112 if ( theTargetMesh ) {
5113 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5114 srcElems.Append( elem );
5116 else if ( theCopy ) {
5117 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5118 srcElems.Append( elem );
5121 aMesh->ChangePolygonNodes(elem, poly_nodes);
5125 case SMDSAbs_Volume:
5127 // ATTENTION: Reversing is not yet done!!!
5128 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5129 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5131 MESSAGE("Warning: bad volumic element");
5135 vector<const SMDS_MeshNode*> poly_nodes;
5136 vector<int> quantities;
5138 bool allTransformed = true;
5139 int nbFaces = aPolyedre->NbFaces();
5140 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5141 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5142 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5143 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5144 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5145 if (nodeMapIt == nodeMap.end()) {
5146 allTransformed = false; // not all nodes transformed
5148 poly_nodes.push_back((*nodeMapIt).second);
5151 quantities.push_back(nbFaceNodes);
5153 if ( !allTransformed )
5154 continue; // not all nodes transformed
5156 if ( theTargetMesh ) {
5157 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5158 srcElems.Append( elem );
5160 else if ( theCopy ) {
5161 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5162 srcElems.Append( elem );
5165 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5175 int* i = index[ FORWARD ];
5176 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5177 // if ( elemType == SMDSAbs_Face )
5178 // i = index[ REV_FACE ];
5180 // i = index[ nbNodes - 4 ];
5182 if(elem->IsQuadratic()) {
5183 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5186 // if(nbNodes==3) { // quadratic edge
5187 // static int anIds[] = {1,0,2};
5190 // else if(nbNodes==6) { // quadratic triangle
5191 // static int anIds[] = {0,2,1,5,4,3};
5194 // else if(nbNodes==8) { // quadratic quadrangle
5195 // static int anIds[] = {0,3,2,1,7,6,5,4};
5198 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5199 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5202 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5203 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5206 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5207 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5210 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5211 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5217 // find transformed nodes
5218 vector<const SMDS_MeshNode*> nodes(nbNodes);
5220 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5221 while ( itN->more() ) {
5222 const SMDS_MeshNode* node =
5223 static_cast<const SMDS_MeshNode*>( itN->next() );
5224 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5225 if ( nodeMapIt == nodeMap.end() )
5226 break; // not all nodes transformed
5227 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5229 if ( iNode != nbNodes )
5230 continue; // not all nodes transformed
5232 if ( theTargetMesh ) {
5233 if ( SMDS_MeshElement* copy =
5234 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5235 myLastCreatedElems.Append( copy );
5236 srcElems.Append( elem );
5239 else if ( theCopy ) {
5240 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5241 myLastCreatedElems.Append( copy );
5242 srcElems.Append( elem );
5246 // reverse element as it was reversed by transformation
5248 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5252 PGroupIDs newGroupIDs;
5254 if ( theMakeGroups && theCopy ||
5255 theMakeGroups && theTargetMesh ) {
5256 string groupPostfix = "scaled";
5257 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5264 //=======================================================================
5266 * \brief Create groups of elements made during transformation
5267 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5268 * \param elemGens - elements making corresponding myLastCreatedElems
5269 * \param postfix - to append to names of new groups
5271 //=======================================================================
5273 SMESH_MeshEditor::PGroupIDs
5274 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5275 const SMESH_SequenceOfElemPtr& elemGens,
5276 const std::string& postfix,
5277 SMESH_Mesh* targetMesh)
5279 PGroupIDs newGroupIDs( new list<int> );
5280 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5282 // Sort existing groups by types and collect their names
5284 // to store an old group and a generated new one
5285 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5286 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5288 set< string > groupNames;
5290 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5291 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5292 while ( groupIt->more() ) {
5293 SMESH_Group * group = groupIt->next();
5294 if ( !group ) continue;
5295 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5296 if ( !groupDS || groupDS->IsEmpty() ) continue;
5297 groupNames.insert( group->GetName() );
5298 groupDS->SetStoreName( group->GetName() );
5299 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5304 // loop on nodes and elements
5305 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5307 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5308 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5309 if ( gens.Length() != elems.Length() )
5310 throw SALOME_Exception(LOCALIZED("invalid args"));
5312 // loop on created elements
5313 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5315 const SMDS_MeshElement* sourceElem = gens( iElem );
5316 if ( !sourceElem ) {
5317 MESSAGE("generateGroups(): NULL source element");
5320 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5321 if ( groupsOldNew.empty() ) {
5322 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5323 ++iElem; // skip all elements made by sourceElem
5326 // collect all elements made by sourceElem
5327 list< const SMDS_MeshElement* > resultElems;
5328 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5329 if ( resElem != sourceElem )
5330 resultElems.push_back( resElem );
5331 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5332 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5333 if ( resElem != sourceElem )
5334 resultElems.push_back( resElem );
5335 // do not generate element groups from node ones
5336 if ( sourceElem->GetType() == SMDSAbs_Node &&
5337 elems( iElem )->GetType() != SMDSAbs_Node )
5340 // add resultElems to groups made by ones the sourceElem belongs to
5341 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5342 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5344 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5345 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5347 SMDS_MeshGroup* & newGroup = gOldNew->second;
5348 if ( !newGroup )// create a new group
5351 string name = oldGroup->GetStoreName();
5352 if ( !targetMesh ) {
5356 while ( !groupNames.insert( name ).second ) // name exists
5362 TCollection_AsciiString nbStr(nb+1);
5363 name.resize( name.rfind('_')+1 );
5364 name += nbStr.ToCString();
5371 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5373 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5374 newGroup = & groupDS->SMDSGroup();
5375 newGroupIDs->push_back( id );
5378 // fill in a new group
5379 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5380 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5381 newGroup->Add( *resElemIt );
5384 } // loop on created elements
5385 }// loop on nodes and elements
5390 //================================================================================
5392 * \brief Return list of group of nodes close to each other within theTolerance
5393 * Search among theNodes or in the whole mesh if theNodes is empty using
5394 * an Octree algorithm
5396 //================================================================================
5398 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5399 const double theTolerance,
5400 TListOfListOfNodes & theGroupsOfNodes)
5402 myLastCreatedElems.Clear();
5403 myLastCreatedNodes.Clear();
5405 set<const SMDS_MeshNode*> nodes;
5406 if ( theNodes.empty() )
5407 { // get all nodes in the mesh
5408 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5409 while ( nIt->more() )
5410 nodes.insert( nodes.end(),nIt->next());
5415 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5419 //=======================================================================
5421 * \brief Implementation of search for the node closest to point
5423 //=======================================================================
5425 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5427 //---------------------------------------------------------------------
5429 * \brief Constructor
5431 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5433 myMesh = ( SMESHDS_Mesh* ) theMesh;
5435 set<const SMDS_MeshNode*> nodes;
5437 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5438 while ( nIt->more() )
5439 nodes.insert( nodes.end(), nIt->next() );
5441 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5443 // get max size of a leaf box
5444 SMESH_OctreeNode* tree = myOctreeNode;
5445 while ( !tree->isLeaf() )
5447 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5451 myHalfLeafSize = tree->maxSize() / 2.;
5454 //---------------------------------------------------------------------
5456 * \brief Move node and update myOctreeNode accordingly
5458 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5460 myOctreeNode->UpdateByMoveNode( node, toPnt );
5461 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5464 //---------------------------------------------------------------------
5466 * \brief Do it's job
5468 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5470 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5471 map<double, const SMDS_MeshNode*> dist2Nodes;
5472 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5473 if ( !dist2Nodes.empty() )
5474 return dist2Nodes.begin()->second;
5475 list<const SMDS_MeshNode*> nodes;
5476 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5478 double minSqDist = DBL_MAX;
5479 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5481 // sort leafs by their distance from thePnt
5482 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5483 TDistTreeMap treeMap;
5484 list< SMESH_OctreeNode* > treeList;
5485 list< SMESH_OctreeNode* >::iterator trIt;
5486 treeList.push_back( myOctreeNode );
5488 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5489 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5491 SMESH_OctreeNode* tree = *trIt;
5492 if ( !tree->isLeaf() ) // put children to the queue
5494 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5495 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5496 while ( cIt->more() )
5497 treeList.push_back( cIt->next() );
5499 else if ( tree->NbNodes() ) // put a tree to the treeMap
5501 const Bnd_B3d& box = tree->getBox();
5502 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5503 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5504 if ( !it_in.second ) // not unique distance to box center
5505 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5508 // find distance after which there is no sense to check tree's
5509 double sqLimit = DBL_MAX;
5510 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5511 if ( treeMap.size() > 5 ) {
5512 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5513 const Bnd_B3d& box = closestTree->getBox();
5514 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5515 sqLimit = limit * limit;
5517 // get all nodes from trees
5518 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5519 if ( sqDist_tree->first > sqLimit )
5521 SMESH_OctreeNode* tree = sqDist_tree->second;
5522 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5525 // find closest among nodes
5526 minSqDist = DBL_MAX;
5527 const SMDS_MeshNode* closestNode = 0;
5528 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5529 for ( ; nIt != nodes.end(); ++nIt ) {
5530 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5531 if ( minSqDist > sqDist ) {
5539 //---------------------------------------------------------------------
5543 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5545 //---------------------------------------------------------------------
5547 * \brief Return the node tree
5549 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5552 SMESH_OctreeNode* myOctreeNode;
5553 SMESHDS_Mesh* myMesh;
5554 double myHalfLeafSize; // max size of a leaf box
5557 //=======================================================================
5559 * \brief Return SMESH_NodeSearcher
5561 //=======================================================================
5563 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5565 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5568 // ========================================================================
5569 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5571 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5572 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5573 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5575 //=======================================================================
5577 * \brief Octal tree of bounding boxes of elements
5579 //=======================================================================
5581 class ElementBndBoxTree : public SMESH_Octree
5585 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5586 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5587 ~ElementBndBoxTree();
5590 ElementBndBoxTree() {}
5591 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5592 void buildChildrenData();
5593 Bnd_B3d* buildRootBox();
5595 //!< Bounding box of element
5596 struct ElementBox : public Bnd_B3d
5598 const SMDS_MeshElement* _element;
5599 int _refCount; // an ElementBox can be included in several tree branches
5600 ElementBox(const SMDS_MeshElement* elem);
5602 vector< ElementBox* > _elements;
5605 //================================================================================
5607 * \brief ElementBndBoxTree creation
5609 //================================================================================
5611 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5612 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5614 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5615 _elements.reserve( nbElems );
5617 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5618 while ( elemIt->more() )
5619 _elements.push_back( new ElementBox( elemIt->next() ));
5621 if ( _elements.size() > MaxNbElemsInLeaf )
5627 //================================================================================
5631 //================================================================================
5633 ElementBndBoxTree::~ElementBndBoxTree()
5635 for ( int i = 0; i < _elements.size(); ++i )
5636 if ( --_elements[i]->_refCount <= 0 )
5637 delete _elements[i];
5640 //================================================================================
5642 * \brief Return the maximal box
5644 //================================================================================
5646 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5648 Bnd_B3d* box = new Bnd_B3d;
5649 for ( int i = 0; i < _elements.size(); ++i )
5650 box->Add( *_elements[i] );
5654 //================================================================================
5656 * \brief Redistrubute element boxes among children
5658 //================================================================================
5660 void ElementBndBoxTree::buildChildrenData()
5662 for ( int i = 0; i < _elements.size(); ++i )
5664 for (int j = 0; j < 8; j++)
5666 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5668 _elements[i]->_refCount++;
5669 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5672 _elements[i]->_refCount--;
5676 for (int j = 0; j < 8; j++)
5678 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5679 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5680 child->myIsLeaf = true;
5682 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5683 child->_elements.resize( child->_elements.size() ); // compact
5687 //================================================================================
5689 * \brief Return elements which can include the point
5691 //================================================================================
5693 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5694 TIDSortedElemSet& foundElems)
5696 if ( level() && getBox().IsOut( point.XYZ() ))
5701 for ( int i = 0; i < _elements.size(); ++i )
5702 if ( !_elements[i]->IsOut( point.XYZ() ))
5703 foundElems.insert( _elements[i]->_element );
5707 for (int i = 0; i < 8; i++)
5708 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5712 //================================================================================
5714 * \brief Construct the element box
5716 //================================================================================
5718 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5722 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5723 while ( nIt->more() )
5724 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5725 Enlarge( NodeRadius );
5730 //=======================================================================
5732 * \brief Implementation of search for the elements by point
5734 //=======================================================================
5736 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5738 SMESHDS_Mesh* _mesh;
5739 ElementBndBoxTree* _ebbTree;
5740 SMESH_NodeSearcherImpl* _nodeSearcher;
5741 SMDSAbs_ElementType _elementType;
5743 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh ): _mesh(&mesh),_ebbTree(0),_nodeSearcher(0) {}
5744 ~SMESH_ElementSearcherImpl()
5746 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5747 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5751 * \brief Find elements of given type where the given point is IN or ON.
5752 * Returns nb of found elements and elements them-selves.
5754 * 'ALL' type means elements of any type excluding nodes and 0D elements
5756 int FindElementsByPoint(const gp_Pnt& point,
5757 SMDSAbs_ElementType type,
5758 vector< const SMDS_MeshElement* >& foundElements)
5760 foundElements.clear();
5762 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5764 // -----------------
5766 // -----------------
5767 double tolerance = 0;
5768 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5770 double boxSize = _nodeSearcher->getTree()->maxSize();
5771 tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5773 else if ( _ebbTree && meshInfo.NbElements() > 0 )
5775 double boxSize = _ebbTree->maxSize();
5776 tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5778 if ( tolerance == 0 )
5780 // define tolerance by size of a most complex element
5781 int complexType = SMDSAbs_Volume;
5782 while ( complexType > SMDSAbs_All &&
5783 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5785 if ( complexType == SMDSAbs_All ) return foundElements.size(); // empty mesh
5788 if ( complexType == int( SMDSAbs_Node ))
5790 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
5792 if ( meshInfo.NbNodes() > 2 )
5793 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
5797 const SMDS_MeshElement* elem =
5798 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
5799 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
5800 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
5801 while ( nodeIt->more() )
5803 double dist = n1.Distance( cast2Node( nodeIt->next() ));
5804 elemSize = max( dist, elemSize );
5807 tolerance = 1e-6 * elemSize;
5810 // =================================================================================
5811 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
5813 if ( !_nodeSearcher )
5814 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
5816 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
5817 if ( !closeNode ) return foundElements.size();
5819 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
5820 return foundElements.size(); // to far from any node
5822 if ( type == SMDSAbs_Node )
5824 foundElements.push_back( closeNode );
5828 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
5829 while ( elemIt->more() )
5830 foundElements.push_back( elemIt->next() );
5833 // =================================================================================
5834 else // elements more complex than 0D
5836 if ( !_ebbTree || _elementType != type )
5838 if ( _ebbTree ) delete _ebbTree;
5839 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
5841 TIDSortedElemSet suspectElems;
5842 _ebbTree->getElementsNearPoint( point, suspectElems );
5843 TIDSortedElemSet::iterator elem = suspectElems.begin();
5844 for ( ; elem != suspectElems.end(); ++elem )
5845 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
5846 foundElements.push_back( *elem );
5848 return foundElements.size();
5850 }; // struct SMESH_ElementSearcherImpl
5852 //=======================================================================
5854 * \brief Return SMESH_ElementSearcher
5856 //=======================================================================
5858 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
5860 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
5863 //=======================================================================
5865 * \brief Return true if the point is IN or ON of the element
5867 //=======================================================================
5869 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
5871 if ( element->GetType() == SMDSAbs_Volume)
5873 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
5876 // get ordered nodes
5878 vector< gp_XYZ > xyz;
5880 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
5881 if ( element->IsQuadratic() )
5882 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
5883 nodeIt = f->interlacedNodesElemIterator();
5884 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
5885 nodeIt = e->interlacedNodesElemIterator();
5887 while ( nodeIt->more() )
5888 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
5890 int i, nbNodes = element->NbNodes();
5892 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
5894 // compute face normal
5895 gp_Vec faceNorm(0,0,0);
5896 xyz.push_back( xyz.front() );
5897 for ( i = 0; i < nbNodes; ++i )
5899 gp_Vec edge1( xyz[i+1], xyz[i]);
5900 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
5901 faceNorm += edge1 ^ edge2;
5903 double normSize = faceNorm.Magnitude();
5904 if ( normSize <= tol )
5906 // degenerated face: point is out if it is out of all face edges
5907 for ( i = 0; i < nbNodes; ++i )
5909 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
5910 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
5911 SMDS_MeshEdge edge( &n1, &n2 );
5912 if ( !isOut( &edge, point, tol ))
5917 faceNorm /= normSize;
5919 // check if the point lays on face plane
5920 gp_Vec n2p( xyz[0], point );
5921 if ( fabs( n2p * faceNorm ) > tol )
5922 return true; // not on face plane
5924 // check if point is out of face boundary:
5925 // define it by closest transition of a ray point->infinity through face boundary
5926 // on the face plane.
5927 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
5928 // to find intersections of the ray with the boundary.
5930 gp_Vec plnNorm = ray ^ faceNorm;
5931 normSize = plnNorm.Magnitude();
5932 if ( normSize <= tol ) return false; // point coincides with the first node
5933 plnNorm /= normSize;
5934 // for each node of the face, compute its signed distance to the plane
5935 vector<double> dist( nbNodes + 1);
5936 for ( i = 0; i < nbNodes; ++i )
5938 gp_Vec n2p( xyz[i], point );
5939 dist[i] = n2p * plnNorm;
5941 dist.back() = dist.front();
5942 // find the closest intersection
5944 double rClosest, distClosest = 1e100;;
5946 for ( i = 0; i < nbNodes; ++i )
5949 if ( fabs( dist[i]) < tol )
5951 else if ( fabs( dist[i+1]) < tol )
5953 else if ( dist[i] * dist[i+1] < 0 )
5954 r = dist[i] / ( dist[i] - dist[i+1] );
5956 continue; // no intersection
5957 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
5958 gp_Vec p2int ( point, pInt);
5959 if ( p2int * ray > -tol ) // right half-space
5961 double intDist = p2int.SquareMagnitude();
5962 if ( intDist < distClosest )
5967 distClosest = intDist;
5972 return true; // no intesections - out
5974 // analyse transition
5975 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
5976 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
5977 gp_Vec p2int ( point, pClosest );
5978 bool out = (edgeNorm * p2int) < -tol;
5979 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
5982 // ray pass through a face node; analyze transition through an adjacent edge
5983 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
5984 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
5985 gp_Vec edgeAdjacent( p1, p2 );
5986 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
5987 bool out2 = (edgeNorm2 * p2int) < -tol;
5989 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
5990 return covexCorner ? (out || out2) : (out && out2);
5992 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
5994 // point is out of edge if it is NOT ON any straight part of edge
5995 // (we consider quadratic edge as being composed of two straight parts)
5996 for ( i = 1; i < nbNodes; ++i )
5998 gp_Vec edge( xyz[i-1], xyz[i]);
5999 gp_Vec n1p ( xyz[i-1], point);
6000 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6003 gp_Vec n2p( xyz[i], point );
6004 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6006 return false; // point is ON this part
6010 // Node or 0D element -------------------------------------------------------------------------
6012 gp_Vec n2p ( xyz[0], point );
6013 return n2p.Magnitude() <= tol;
6018 //=======================================================================
6019 //function : SimplifyFace
6021 //=======================================================================
6022 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6023 vector<const SMDS_MeshNode *>& poly_nodes,
6024 vector<int>& quantities) const
6026 int nbNodes = faceNodes.size();
6031 set<const SMDS_MeshNode*> nodeSet;
6033 // get simple seq of nodes
6034 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6035 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6036 int iSimple = 0, nbUnique = 0;
6038 simpleNodes[iSimple++] = faceNodes[0];
6040 for (int iCur = 1; iCur < nbNodes; iCur++) {
6041 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6042 simpleNodes[iSimple++] = faceNodes[iCur];
6043 if (nodeSet.insert( faceNodes[iCur] ).second)
6047 int nbSimple = iSimple;
6048 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6058 bool foundLoop = (nbSimple > nbUnique);
6061 set<const SMDS_MeshNode*> loopSet;
6062 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6063 const SMDS_MeshNode* n = simpleNodes[iSimple];
6064 if (!loopSet.insert( n ).second) {
6068 int iC = 0, curLast = iSimple;
6069 for (; iC < curLast; iC++) {
6070 if (simpleNodes[iC] == n) break;
6072 int loopLen = curLast - iC;
6074 // create sub-element
6076 quantities.push_back(loopLen);
6077 for (; iC < curLast; iC++) {
6078 poly_nodes.push_back(simpleNodes[iC]);
6081 // shift the rest nodes (place from the first loop position)
6082 for (iC = curLast + 1; iC < nbSimple; iC++) {
6083 simpleNodes[iC - loopLen] = simpleNodes[iC];
6085 nbSimple -= loopLen;
6088 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6089 } // while (foundLoop)
6093 quantities.push_back(iSimple);
6094 for (int i = 0; i < iSimple; i++)
6095 poly_nodes.push_back(simpleNodes[i]);
6101 //=======================================================================
6102 //function : MergeNodes
6103 //purpose : In each group, the cdr of nodes are substituted by the first one
6105 //=======================================================================
6107 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6109 myLastCreatedElems.Clear();
6110 myLastCreatedNodes.Clear();
6112 SMESHDS_Mesh* aMesh = GetMeshDS();
6114 TNodeNodeMap nodeNodeMap; // node to replace - new node
6115 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6116 list< int > rmElemIds, rmNodeIds;
6118 // Fill nodeNodeMap and elems
6120 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6121 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6122 list<const SMDS_MeshNode*>& nodes = *grIt;
6123 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6124 const SMDS_MeshNode* nToKeep = *nIt;
6125 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6126 const SMDS_MeshNode* nToRemove = *nIt;
6127 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6128 if ( nToRemove != nToKeep ) {
6129 rmNodeIds.push_back( nToRemove->GetID() );
6130 AddToSameGroups( nToKeep, nToRemove, aMesh );
6133 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6134 while ( invElemIt->more() ) {
6135 const SMDS_MeshElement* elem = invElemIt->next();
6140 // Change element nodes or remove an element
6142 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6143 for ( ; eIt != elems.end(); eIt++ ) {
6144 const SMDS_MeshElement* elem = *eIt;
6145 int nbNodes = elem->NbNodes();
6146 int aShapeId = FindShape( elem );
6148 set<const SMDS_MeshNode*> nodeSet;
6149 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6150 int iUnique = 0, iCur = 0, nbRepl = 0;
6151 vector<int> iRepl( nbNodes );
6153 // get new seq of nodes
6154 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6155 while ( itN->more() ) {
6156 const SMDS_MeshNode* n =
6157 static_cast<const SMDS_MeshNode*>( itN->next() );
6159 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6160 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6162 // BUG 0020185: begin
6164 bool stopRecur = false;
6165 set<const SMDS_MeshNode*> nodesRecur;
6166 nodesRecur.insert(n);
6167 while (!stopRecur) {
6168 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6169 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6170 n = (*nnIt_i).second;
6171 if (!nodesRecur.insert(n).second) {
6172 // error: recursive dependancy
6181 iRepl[ nbRepl++ ] = iCur;
6183 curNodes[ iCur ] = n;
6184 bool isUnique = nodeSet.insert( n ).second;
6186 uniqueNodes[ iUnique++ ] = n;
6190 // Analyse element topology after replacement
6193 int nbUniqueNodes = nodeSet.size();
6194 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6195 // Polygons and Polyhedral volumes
6196 if (elem->IsPoly()) {
6198 if (elem->GetType() == SMDSAbs_Face) {
6200 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6202 for (; inode < nbNodes; inode++) {
6203 face_nodes[inode] = curNodes[inode];
6206 vector<const SMDS_MeshNode *> polygons_nodes;
6207 vector<int> quantities;
6208 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6212 for (int iface = 0; iface < nbNew - 1; iface++) {
6213 int nbNodes = quantities[iface];
6214 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6215 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6216 poly_nodes[ii] = polygons_nodes[inode];
6218 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6219 myLastCreatedElems.Append(newElem);
6221 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6223 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6226 rmElemIds.push_back(elem->GetID());
6230 else if (elem->GetType() == SMDSAbs_Volume) {
6231 // Polyhedral volume
6232 if (nbUniqueNodes < 4) {
6233 rmElemIds.push_back(elem->GetID());
6236 // each face has to be analized in order to check volume validity
6237 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6238 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6240 int nbFaces = aPolyedre->NbFaces();
6242 vector<const SMDS_MeshNode *> poly_nodes;
6243 vector<int> quantities;
6245 for (int iface = 1; iface <= nbFaces; iface++) {
6246 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6247 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6249 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6250 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6251 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6252 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6253 faceNode = (*nnIt).second;
6255 faceNodes[inode - 1] = faceNode;
6258 SimplifyFace(faceNodes, poly_nodes, quantities);
6261 if (quantities.size() > 3) {
6262 // to be done: remove coincident faces
6265 if (quantities.size() > 3)
6266 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6268 rmElemIds.push_back(elem->GetID());
6272 rmElemIds.push_back(elem->GetID());
6283 switch ( nbNodes ) {
6284 case 2: ///////////////////////////////////// EDGE
6285 isOk = false; break;
6286 case 3: ///////////////////////////////////// TRIANGLE
6287 isOk = false; break;
6289 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6291 else { //////////////////////////////////// QUADRANGLE
6292 if ( nbUniqueNodes < 3 )
6294 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6295 isOk = false; // opposite nodes stick
6298 case 6: ///////////////////////////////////// PENTAHEDRON
6299 if ( nbUniqueNodes == 4 ) {
6300 // ---------------------------------> tetrahedron
6302 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6303 // all top nodes stick: reverse a bottom
6304 uniqueNodes[ 0 ] = curNodes [ 1 ];
6305 uniqueNodes[ 1 ] = curNodes [ 0 ];
6307 else if (nbRepl == 3 &&
6308 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6309 // all bottom nodes stick: set a top before
6310 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6311 uniqueNodes[ 0 ] = curNodes [ 3 ];
6312 uniqueNodes[ 1 ] = curNodes [ 4 ];
6313 uniqueNodes[ 2 ] = curNodes [ 5 ];
6315 else if (nbRepl == 4 &&
6316 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6317 // a lateral face turns into a line: reverse a bottom
6318 uniqueNodes[ 0 ] = curNodes [ 1 ];
6319 uniqueNodes[ 1 ] = curNodes [ 0 ];
6324 else if ( nbUniqueNodes == 5 ) {
6325 // PENTAHEDRON --------------------> 2 tetrahedrons
6326 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6327 // a bottom node sticks with a linked top one
6329 SMDS_MeshElement* newElem =
6330 aMesh->AddVolume(curNodes[ 3 ],
6333 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6334 myLastCreatedElems.Append(newElem);
6336 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6337 // 2. : reverse a bottom
6338 uniqueNodes[ 0 ] = curNodes [ 1 ];
6339 uniqueNodes[ 1 ] = curNodes [ 0 ];
6349 if(elem->IsQuadratic()) { // Quadratic quadrangle
6362 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6363 uniqueNodes[0] = curNodes[0];
6364 uniqueNodes[1] = curNodes[2];
6365 uniqueNodes[2] = curNodes[3];
6366 uniqueNodes[3] = curNodes[5];
6367 uniqueNodes[4] = curNodes[6];
6368 uniqueNodes[5] = curNodes[7];
6371 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6372 uniqueNodes[0] = curNodes[0];
6373 uniqueNodes[1] = curNodes[1];
6374 uniqueNodes[2] = curNodes[2];
6375 uniqueNodes[3] = curNodes[4];
6376 uniqueNodes[4] = curNodes[5];
6377 uniqueNodes[5] = curNodes[6];
6380 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6381 uniqueNodes[0] = curNodes[1];
6382 uniqueNodes[1] = curNodes[2];
6383 uniqueNodes[2] = curNodes[3];
6384 uniqueNodes[3] = curNodes[5];
6385 uniqueNodes[4] = curNodes[6];
6386 uniqueNodes[5] = curNodes[0];
6389 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6390 uniqueNodes[0] = curNodes[0];
6391 uniqueNodes[1] = curNodes[1];
6392 uniqueNodes[2] = curNodes[3];
6393 uniqueNodes[3] = curNodes[4];
6394 uniqueNodes[4] = curNodes[6];
6395 uniqueNodes[5] = curNodes[7];
6398 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6399 uniqueNodes[0] = curNodes[0];
6400 uniqueNodes[1] = curNodes[2];
6401 uniqueNodes[2] = curNodes[3];
6402 uniqueNodes[3] = curNodes[1];
6403 uniqueNodes[4] = curNodes[6];
6404 uniqueNodes[5] = curNodes[7];
6407 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6408 uniqueNodes[0] = curNodes[0];
6409 uniqueNodes[1] = curNodes[1];
6410 uniqueNodes[2] = curNodes[2];
6411 uniqueNodes[3] = curNodes[4];
6412 uniqueNodes[4] = curNodes[5];
6413 uniqueNodes[5] = curNodes[7];
6416 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6417 uniqueNodes[0] = curNodes[0];
6418 uniqueNodes[1] = curNodes[1];
6419 uniqueNodes[2] = curNodes[3];
6420 uniqueNodes[3] = curNodes[4];
6421 uniqueNodes[4] = curNodes[2];
6422 uniqueNodes[5] = curNodes[7];
6425 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6426 uniqueNodes[0] = curNodes[0];
6427 uniqueNodes[1] = curNodes[1];
6428 uniqueNodes[2] = curNodes[2];
6429 uniqueNodes[3] = curNodes[4];
6430 uniqueNodes[4] = curNodes[5];
6431 uniqueNodes[5] = curNodes[3];
6437 //////////////////////////////////// HEXAHEDRON
6439 SMDS_VolumeTool hexa (elem);
6440 hexa.SetExternalNormal();
6441 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6442 //////////////////////// ---> tetrahedron
6443 for ( int iFace = 0; iFace < 6; iFace++ ) {
6444 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6445 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6446 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6447 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6448 // one face turns into a point ...
6449 int iOppFace = hexa.GetOppFaceIndex( iFace );
6450 ind = hexa.GetFaceNodesIndices( iOppFace );
6452 iUnique = 2; // reverse a tetrahedron bottom
6453 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6454 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6456 else if ( iUnique >= 0 )
6457 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6459 if ( nbStick == 1 ) {
6460 // ... and the opposite one - into a triangle.
6462 ind = hexa.GetFaceNodesIndices( iFace );
6463 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6470 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6471 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6472 for ( int iFace = 0; iFace < 6; iFace++ ) {
6473 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6474 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6475 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6476 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6477 // one face turns into a point ...
6478 int iOppFace = hexa.GetOppFaceIndex( iFace );
6479 ind = hexa.GetFaceNodesIndices( iOppFace );
6481 iUnique = 2; // reverse a tetrahedron 1 bottom
6482 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6483 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6485 else if ( iUnique >= 0 )
6486 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6488 if ( nbStick == 0 ) {
6489 // ... and the opposite one is a quadrangle
6491 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6492 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6495 SMDS_MeshElement* newElem =
6496 aMesh->AddVolume(curNodes[ind[ 0 ]],
6499 curNodes[indTop[ 0 ]]);
6500 myLastCreatedElems.Append(newElem);
6502 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6509 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6510 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6511 // find indices of quad and tri faces
6512 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6513 for ( iFace = 0; iFace < 6; iFace++ ) {
6514 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6516 for ( iCur = 0; iCur < 4; iCur++ )
6517 nodeSet.insert( curNodes[ind[ iCur ]] );
6518 nbUniqueNodes = nodeSet.size();
6519 if ( nbUniqueNodes == 3 )
6520 iTriFace[ nbTri++ ] = iFace;
6521 else if ( nbUniqueNodes == 4 )
6522 iQuadFace[ nbQuad++ ] = iFace;
6524 if (nbQuad == 2 && nbTri == 4 &&
6525 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
6526 // 2 opposite quadrangles stuck with a diagonal;
6527 // sample groups of merged indices: (0-4)(2-6)
6528 // --------------------------------------------> 2 tetrahedrons
6529 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
6530 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
6531 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
6532 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
6533 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
6534 // stuck with 0-2 diagonal
6542 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
6543 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
6544 // stuck with 1-3 diagonal
6556 uniqueNodes[ 0 ] = curNodes [ i0 ];
6557 uniqueNodes[ 1 ] = curNodes [ i1d ];
6558 uniqueNodes[ 2 ] = curNodes [ i3d ];
6559 uniqueNodes[ 3 ] = curNodes [ i0t ];
6562 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
6566 myLastCreatedElems.Append(newElem);
6568 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6571 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
6572 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
6573 // --------------------------------------------> prism
6574 // find 2 opposite triangles
6576 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
6577 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
6578 // find indices of kept and replaced nodes
6579 // and fill unique nodes of 2 opposite triangles
6580 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
6581 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
6582 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
6583 // fill unique nodes
6586 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
6587 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
6588 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
6590 // iCur of a linked node of the opposite face (make normals co-directed):
6591 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
6592 // check that correspondent corners of triangles are linked
6593 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
6596 uniqueNodes[ iUnique ] = n;
6597 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
6606 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
6612 } // switch ( nbNodes )
6614 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
6617 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
6618 // Change nodes of polyedre
6619 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6620 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6622 int nbFaces = aPolyedre->NbFaces();
6624 vector<const SMDS_MeshNode *> poly_nodes;
6625 vector<int> quantities (nbFaces);
6627 for (int iface = 1; iface <= nbFaces; iface++) {
6628 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6629 quantities[iface - 1] = nbFaceNodes;
6631 for (inode = 1; inode <= nbFaceNodes; inode++) {
6632 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
6634 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
6635 if (nnIt != nodeNodeMap.end()) { // curNode sticks
6636 curNode = (*nnIt).second;
6638 poly_nodes.push_back(curNode);
6641 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
6645 // Change regular element or polygon
6646 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
6650 // Remove invalid regular element or invalid polygon
6651 rmElemIds.push_back( elem->GetID() );
6654 } // loop on elements
6656 // Remove equal nodes and bad elements
6658 Remove( rmNodeIds, true );
6659 Remove( rmElemIds, false );
6664 // ========================================================
6665 // class : SortableElement
6666 // purpose : allow sorting elements basing on their nodes
6667 // ========================================================
6668 class SortableElement : public set <const SMDS_MeshElement*>
6672 SortableElement( const SMDS_MeshElement* theElem )
6675 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
6676 while ( nodeIt->more() )
6677 this->insert( nodeIt->next() );
6680 const SMDS_MeshElement* Get() const
6683 void Set(const SMDS_MeshElement* e) const
6688 mutable const SMDS_MeshElement* myElem;
6691 //=======================================================================
6692 //function : FindEqualElements
6693 //purpose : Return list of group of elements built on the same nodes.
6694 // Search among theElements or in the whole mesh if theElements is empty
6695 //=======================================================================
6696 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
6697 TListOfListOfElementsID & theGroupsOfElementsID)
6699 myLastCreatedElems.Clear();
6700 myLastCreatedNodes.Clear();
6702 typedef set<const SMDS_MeshElement*> TElemsSet;
6703 typedef map< SortableElement, int > TMapOfNodeSet;
6704 typedef list<int> TGroupOfElems;
6707 if ( theElements.empty() )
6708 { // get all elements in the mesh
6709 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
6710 while ( eIt->more() )
6711 elems.insert( elems.end(), eIt->next());
6714 elems = theElements;
6716 vector< TGroupOfElems > arrayOfGroups;
6717 TGroupOfElems groupOfElems;
6718 TMapOfNodeSet mapOfNodeSet;
6720 TElemsSet::iterator elemIt = elems.begin();
6721 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
6722 const SMDS_MeshElement* curElem = *elemIt;
6723 SortableElement SE(curElem);
6726 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
6727 if( !(pp.second) ) {
6728 TMapOfNodeSet::iterator& itSE = pp.first;
6729 ind = (*itSE).second;
6730 arrayOfGroups[ind].push_back(curElem->GetID());
6733 groupOfElems.clear();
6734 groupOfElems.push_back(curElem->GetID());
6735 arrayOfGroups.push_back(groupOfElems);
6740 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
6741 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
6742 groupOfElems = *groupIt;
6743 if ( groupOfElems.size() > 1 ) {
6744 groupOfElems.sort();
6745 theGroupsOfElementsID.push_back(groupOfElems);
6750 //=======================================================================
6751 //function : MergeElements
6752 //purpose : In each given group, substitute all elements by the first one.
6753 //=======================================================================
6755 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
6757 myLastCreatedElems.Clear();
6758 myLastCreatedNodes.Clear();
6760 typedef list<int> TListOfIDs;
6761 TListOfIDs rmElemIds; // IDs of elems to remove
6763 SMESHDS_Mesh* aMesh = GetMeshDS();
6765 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
6766 while ( groupsIt != theGroupsOfElementsID.end() ) {
6767 TListOfIDs& aGroupOfElemID = *groupsIt;
6768 aGroupOfElemID.sort();
6769 int elemIDToKeep = aGroupOfElemID.front();
6770 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
6771 aGroupOfElemID.pop_front();
6772 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
6773 while ( idIt != aGroupOfElemID.end() ) {
6774 int elemIDToRemove = *idIt;
6775 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
6776 // add the kept element in groups of removed one (PAL15188)
6777 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
6778 rmElemIds.push_back( elemIDToRemove );
6784 Remove( rmElemIds, false );
6787 //=======================================================================
6788 //function : MergeEqualElements
6789 //purpose : Remove all but one of elements built on the same nodes.
6790 //=======================================================================
6792 void SMESH_MeshEditor::MergeEqualElements()
6794 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
6795 to merge equal elements in the whole mesh */
6796 TListOfListOfElementsID aGroupsOfElementsID;
6797 FindEqualElements(aMeshElements, aGroupsOfElementsID);
6798 MergeElements(aGroupsOfElementsID);
6801 //=======================================================================
6802 //function : FindFaceInSet
6803 //purpose : Return a face having linked nodes n1 and n2 and which is
6804 // - not in avoidSet,
6805 // - in elemSet provided that !elemSet.empty()
6806 // i1 and i2 optionally returns indices of n1 and n2
6807 //=======================================================================
6809 const SMDS_MeshElement*
6810 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
6811 const SMDS_MeshNode* n2,
6812 const TIDSortedElemSet& elemSet,
6813 const TIDSortedElemSet& avoidSet,
6819 const SMDS_MeshElement* face = 0;
6821 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
6822 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
6824 const SMDS_MeshElement* elem = invElemIt->next();
6825 if (avoidSet.count( elem ))
6827 if ( !elemSet.empty() && !elemSet.count( elem ))
6830 i1 = elem->GetNodeIndex( n1 );
6831 // find a n2 linked to n1
6832 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
6833 for ( int di = -1; di < 2 && !face; di += 2 )
6835 i2 = (i1+di+nbN) % nbN;
6836 if ( elem->GetNode( i2 ) == n2 )
6839 if ( !face && elem->IsQuadratic())
6841 // analysis for quadratic elements using all nodes
6842 const SMDS_QuadraticFaceOfNodes* F =
6843 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
6844 // use special nodes iterator
6845 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6846 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
6847 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
6849 const SMDS_MeshNode* n = cast2Node( anIter->next() );
6850 if ( n1 == prevN && n2 == n )
6854 else if ( n2 == prevN && n1 == n )
6856 face = elem; swap( i1, i2 );
6862 if ( n1ind ) *n1ind = i1;
6863 if ( n2ind ) *n2ind = i2;
6867 //=======================================================================
6868 //function : findAdjacentFace
6870 //=======================================================================
6872 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
6873 const SMDS_MeshNode* n2,
6874 const SMDS_MeshElement* elem)
6876 TIDSortedElemSet elemSet, avoidSet;
6878 avoidSet.insert ( elem );
6879 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
6882 //=======================================================================
6883 //function : FindFreeBorder
6885 //=======================================================================
6887 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
6889 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
6890 const SMDS_MeshNode* theSecondNode,
6891 const SMDS_MeshNode* theLastNode,
6892 list< const SMDS_MeshNode* > & theNodes,
6893 list< const SMDS_MeshElement* >& theFaces)
6895 if ( !theFirstNode || !theSecondNode )
6897 // find border face between theFirstNode and theSecondNode
6898 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
6902 theFaces.push_back( curElem );
6903 theNodes.push_back( theFirstNode );
6904 theNodes.push_back( theSecondNode );
6906 //vector<const SMDS_MeshNode*> nodes;
6907 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
6908 TIDSortedElemSet foundElems;
6909 bool needTheLast = ( theLastNode != 0 );
6911 while ( nStart != theLastNode ) {
6912 if ( nStart == theFirstNode )
6913 return !needTheLast;
6915 // find all free border faces sharing form nStart
6917 list< const SMDS_MeshElement* > curElemList;
6918 list< const SMDS_MeshNode* > nStartList;
6919 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
6920 while ( invElemIt->more() ) {
6921 const SMDS_MeshElement* e = invElemIt->next();
6922 if ( e == curElem || foundElems.insert( e ).second ) {
6924 int iNode = 0, nbNodes = e->NbNodes();
6925 //const SMDS_MeshNode* nodes[nbNodes+1];
6926 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
6928 if(e->IsQuadratic()) {
6929 const SMDS_QuadraticFaceOfNodes* F =
6930 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
6931 // use special nodes iterator
6932 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
6933 while( anIter->more() ) {
6934 nodes[ iNode++ ] = anIter->next();
6938 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
6939 while ( nIt->more() )
6940 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
6942 nodes[ iNode ] = nodes[ 0 ];
6944 for ( iNode = 0; iNode < nbNodes; iNode++ )
6945 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
6946 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
6947 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
6949 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
6950 curElemList.push_back( e );
6954 // analyse the found
6956 int nbNewBorders = curElemList.size();
6957 if ( nbNewBorders == 0 ) {
6958 // no free border furthermore
6959 return !needTheLast;
6961 else if ( nbNewBorders == 1 ) {
6962 // one more element found
6964 nStart = nStartList.front();
6965 curElem = curElemList.front();
6966 theFaces.push_back( curElem );
6967 theNodes.push_back( nStart );
6970 // several continuations found
6971 list< const SMDS_MeshElement* >::iterator curElemIt;
6972 list< const SMDS_MeshNode* >::iterator nStartIt;
6973 // check if one of them reached the last node
6974 if ( needTheLast ) {
6975 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6976 curElemIt!= curElemList.end();
6977 curElemIt++, nStartIt++ )
6978 if ( *nStartIt == theLastNode ) {
6979 theFaces.push_back( *curElemIt );
6980 theNodes.push_back( *nStartIt );
6984 // find the best free border by the continuations
6985 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
6986 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
6987 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
6988 curElemIt!= curElemList.end();
6989 curElemIt++, nStartIt++ )
6991 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
6992 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
6993 // find one more free border
6994 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
6998 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
6999 // choice: clear a worse one
7000 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7001 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7002 contNodes[ iWorse ].clear();
7003 contFaces[ iWorse ].clear();
7006 if ( contNodes[0].empty() && contNodes[1].empty() )
7009 // append the best free border
7010 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7011 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7012 theNodes.pop_back(); // remove nIgnore
7013 theNodes.pop_back(); // remove nStart
7014 theFaces.pop_back(); // remove curElem
7015 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7016 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7017 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7018 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7021 } // several continuations found
7022 } // while ( nStart != theLastNode )
7027 //=======================================================================
7028 //function : CheckFreeBorderNodes
7029 //purpose : Return true if the tree nodes are on a free border
7030 //=======================================================================
7032 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7033 const SMDS_MeshNode* theNode2,
7034 const SMDS_MeshNode* theNode3)
7036 list< const SMDS_MeshNode* > nodes;
7037 list< const SMDS_MeshElement* > faces;
7038 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7041 //=======================================================================
7042 //function : SewFreeBorder
7044 //=======================================================================
7046 SMESH_MeshEditor::Sew_Error
7047 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7048 const SMDS_MeshNode* theBordSecondNode,
7049 const SMDS_MeshNode* theBordLastNode,
7050 const SMDS_MeshNode* theSideFirstNode,
7051 const SMDS_MeshNode* theSideSecondNode,
7052 const SMDS_MeshNode* theSideThirdNode,
7053 const bool theSideIsFreeBorder,
7054 const bool toCreatePolygons,
7055 const bool toCreatePolyedrs)
7057 myLastCreatedElems.Clear();
7058 myLastCreatedNodes.Clear();
7060 MESSAGE("::SewFreeBorder()");
7061 Sew_Error aResult = SEW_OK;
7063 // ====================================
7064 // find side nodes and elements
7065 // ====================================
7067 list< const SMDS_MeshNode* > nSide[ 2 ];
7068 list< const SMDS_MeshElement* > eSide[ 2 ];
7069 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7070 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7074 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7075 nSide[0], eSide[0])) {
7076 MESSAGE(" Free Border 1 not found " );
7077 aResult = SEW_BORDER1_NOT_FOUND;
7079 if (theSideIsFreeBorder) {
7082 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7083 nSide[1], eSide[1])) {
7084 MESSAGE(" Free Border 2 not found " );
7085 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7088 if ( aResult != SEW_OK )
7091 if (!theSideIsFreeBorder) {
7095 // -------------------------------------------------------------------------
7097 // 1. If nodes to merge are not coincident, move nodes of the free border
7098 // from the coord sys defined by the direction from the first to last
7099 // nodes of the border to the correspondent sys of the side 2
7100 // 2. On the side 2, find the links most co-directed with the correspondent
7101 // links of the free border
7102 // -------------------------------------------------------------------------
7104 // 1. Since sewing may brake if there are volumes to split on the side 2,
7105 // we wont move nodes but just compute new coordinates for them
7106 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7107 TNodeXYZMap nBordXYZ;
7108 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7109 list< const SMDS_MeshNode* >::iterator nBordIt;
7111 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7112 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7113 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7114 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7115 double tol2 = 1.e-8;
7116 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7117 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7118 // Need node movement.
7120 // find X and Z axes to create trsf
7121 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7123 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7125 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7128 gp_Ax3 toBordAx( Pb1, Zb, X );
7129 gp_Ax3 fromSideAx( Ps1, Zs, X );
7130 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7132 gp_Trsf toBordSys, fromSide2Sys;
7133 toBordSys.SetTransformation( toBordAx );
7134 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7135 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7138 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7139 const SMDS_MeshNode* n = *nBordIt;
7140 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7141 toBordSys.Transforms( xyz );
7142 fromSide2Sys.Transforms( xyz );
7143 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7147 // just insert nodes XYZ in the nBordXYZ map
7148 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7149 const SMDS_MeshNode* n = *nBordIt;
7150 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7154 // 2. On the side 2, find the links most co-directed with the correspondent
7155 // links of the free border
7157 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7158 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7159 sideNodes.push_back( theSideFirstNode );
7161 bool hasVolumes = false;
7162 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7163 set<long> foundSideLinkIDs, checkedLinkIDs;
7164 SMDS_VolumeTool volume;
7165 //const SMDS_MeshNode* faceNodes[ 4 ];
7167 const SMDS_MeshNode* sideNode;
7168 const SMDS_MeshElement* sideElem;
7169 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7170 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7171 nBordIt = bordNodes.begin();
7173 // border node position and border link direction to compare with
7174 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7175 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7176 // choose next side node by link direction or by closeness to
7177 // the current border node:
7178 bool searchByDir = ( *nBordIt != theBordLastNode );
7180 // find the next node on the Side 2
7182 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7184 checkedLinkIDs.clear();
7185 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7187 // loop on inverse elements of current node (prevSideNode) on the Side 2
7188 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7189 while ( invElemIt->more() )
7191 const SMDS_MeshElement* elem = invElemIt->next();
7192 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7193 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7194 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7195 bool isVolume = volume.Set( elem );
7196 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7197 if ( isVolume ) // --volume
7199 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7200 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7201 if(elem->IsQuadratic()) {
7202 const SMDS_QuadraticFaceOfNodes* F =
7203 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7204 // use special nodes iterator
7205 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7206 while( anIter->more() ) {
7207 nodes[ iNode ] = anIter->next();
7208 if ( nodes[ iNode++ ] == prevSideNode )
7209 iPrevNode = iNode - 1;
7213 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7214 while ( nIt->more() ) {
7215 nodes[ iNode ] = cast2Node( nIt->next() );
7216 if ( nodes[ iNode++ ] == prevSideNode )
7217 iPrevNode = iNode - 1;
7220 // there are 2 links to check
7225 // loop on links, to be precise, on the second node of links
7226 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7227 const SMDS_MeshNode* n = nodes[ iNode ];
7229 if ( !volume.IsLinked( n, prevSideNode ))
7233 if ( iNode ) // a node before prevSideNode
7234 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7235 else // a node after prevSideNode
7236 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7238 // check if this link was already used
7239 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7240 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7241 if (!isJustChecked &&
7242 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7244 // test a link geometrically
7245 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7246 bool linkIsBetter = false;
7247 double dot = 0.0, dist = 0.0;
7248 if ( searchByDir ) { // choose most co-directed link
7249 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7250 linkIsBetter = ( dot > maxDot );
7252 else { // choose link with the node closest to bordPos
7253 dist = ( nextXYZ - bordPos ).SquareModulus();
7254 linkIsBetter = ( dist < minDist );
7256 if ( linkIsBetter ) {
7265 } // loop on inverse elements of prevSideNode
7268 MESSAGE(" Cant find path by links of the Side 2 ");
7269 return SEW_BAD_SIDE_NODES;
7271 sideNodes.push_back( sideNode );
7272 sideElems.push_back( sideElem );
7273 foundSideLinkIDs.insert ( linkID );
7274 prevSideNode = sideNode;
7276 if ( *nBordIt == theBordLastNode )
7277 searchByDir = false;
7279 // find the next border link to compare with
7280 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7281 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7282 // move to next border node if sideNode is before forward border node (bordPos)
7283 while ( *nBordIt != theBordLastNode && !searchByDir ) {
7284 prevBordNode = *nBordIt;
7286 bordPos = nBordXYZ[ *nBordIt ];
7287 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7288 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7292 while ( sideNode != theSideSecondNode );
7294 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7295 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7296 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7298 } // end nodes search on the side 2
7300 // ============================
7301 // sew the border to the side 2
7302 // ============================
7304 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7305 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7307 TListOfListOfNodes nodeGroupsToMerge;
7308 if ( nbNodes[0] == nbNodes[1] ||
7309 ( theSideIsFreeBorder && !theSideThirdNode)) {
7311 // all nodes are to be merged
7313 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7314 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7315 nIt[0]++, nIt[1]++ )
7317 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7318 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7319 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7324 // insert new nodes into the border and the side to get equal nb of segments
7326 // get normalized parameters of nodes on the borders
7327 //double param[ 2 ][ maxNbNodes ];
7329 param[0] = new double [ maxNbNodes ];
7330 param[1] = new double [ maxNbNodes ];
7332 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7333 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7334 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7335 const SMDS_MeshNode* nPrev = *nIt;
7336 double bordLength = 0;
7337 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7338 const SMDS_MeshNode* nCur = *nIt;
7339 gp_XYZ segment (nCur->X() - nPrev->X(),
7340 nCur->Y() - nPrev->Y(),
7341 nCur->Z() - nPrev->Z());
7342 double segmentLen = segment.Modulus();
7343 bordLength += segmentLen;
7344 param[ iBord ][ iNode ] = bordLength;
7347 // normalize within [0,1]
7348 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7349 param[ iBord ][ iNode ] /= bordLength;
7353 // loop on border segments
7354 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7355 int i[ 2 ] = { 0, 0 };
7356 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7357 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7359 TElemOfNodeListMap insertMap;
7360 TElemOfNodeListMap::iterator insertMapIt;
7362 // key: elem to insert nodes into
7363 // value: 2 nodes to insert between + nodes to be inserted
7365 bool next[ 2 ] = { false, false };
7367 // find min adjacent segment length after sewing
7368 double nextParam = 10., prevParam = 0;
7369 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7370 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7371 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7372 if ( i[ iBord ] > 0 )
7373 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7375 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7376 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7377 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7379 // choose to insert or to merge nodes
7380 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7381 if ( Abs( du ) <= minSegLen * 0.2 ) {
7384 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7385 const SMDS_MeshNode* n0 = *nIt[0];
7386 const SMDS_MeshNode* n1 = *nIt[1];
7387 nodeGroupsToMerge.back().push_back( n1 );
7388 nodeGroupsToMerge.back().push_back( n0 );
7389 // position of node of the border changes due to merge
7390 param[ 0 ][ i[0] ] += du;
7391 // move n1 for the sake of elem shape evaluation during insertion.
7392 // n1 will be removed by MergeNodes() anyway
7393 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7394 next[0] = next[1] = true;
7399 int intoBord = ( du < 0 ) ? 0 : 1;
7400 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7401 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7402 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7403 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7404 if ( intoBord == 1 ) {
7405 // move node of the border to be on a link of elem of the side
7406 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7407 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7408 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7409 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7410 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7412 insertMapIt = insertMap.find( elem );
7413 bool notFound = ( insertMapIt == insertMap.end() );
7414 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7416 // insert into another link of the same element:
7417 // 1. perform insertion into the other link of the elem
7418 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7419 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7420 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7421 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7422 // 2. perform insertion into the link of adjacent faces
7424 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7426 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7430 if (toCreatePolyedrs) {
7431 // perform insertion into the links of adjacent volumes
7432 UpdateVolumes(n12, n22, nodeList);
7434 // 3. find an element appeared on n1 and n2 after the insertion
7435 insertMap.erase( elem );
7436 elem = findAdjacentFace( n1, n2, 0 );
7438 if ( notFound || otherLink ) {
7439 // add element and nodes of the side into the insertMap
7440 insertMapIt = insertMap.insert
7441 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7442 (*insertMapIt).second.push_back( n1 );
7443 (*insertMapIt).second.push_back( n2 );
7445 // add node to be inserted into elem
7446 (*insertMapIt).second.push_back( nIns );
7447 next[ 1 - intoBord ] = true;
7450 // go to the next segment
7451 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7452 if ( next[ iBord ] ) {
7453 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7455 nPrev[ iBord ] = *nIt[ iBord ];
7456 nIt[ iBord ]++; i[ iBord ]++;
7460 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7462 // perform insertion of nodes into elements
7464 for (insertMapIt = insertMap.begin();
7465 insertMapIt != insertMap.end();
7468 const SMDS_MeshElement* elem = (*insertMapIt).first;
7469 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7470 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7471 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7473 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7475 if ( !theSideIsFreeBorder ) {
7476 // look for and insert nodes into the faces adjacent to elem
7478 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7480 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7485 if (toCreatePolyedrs) {
7486 // perform insertion into the links of adjacent volumes
7487 UpdateVolumes(n1, n2, nodeList);
7493 } // end: insert new nodes
7495 MergeNodes ( nodeGroupsToMerge );
7500 //=======================================================================
7501 //function : InsertNodesIntoLink
7502 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7503 // and theBetweenNode2 and split theElement
7504 //=======================================================================
7506 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7507 const SMDS_MeshNode* theBetweenNode1,
7508 const SMDS_MeshNode* theBetweenNode2,
7509 list<const SMDS_MeshNode*>& theNodesToInsert,
7510 const bool toCreatePoly)
7512 if ( theFace->GetType() != SMDSAbs_Face ) return;
7514 // find indices of 2 link nodes and of the rest nodes
7515 int iNode = 0, il1, il2, i3, i4;
7516 il1 = il2 = i3 = i4 = -1;
7517 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
7518 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
7520 if(theFace->IsQuadratic()) {
7521 const SMDS_QuadraticFaceOfNodes* F =
7522 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7523 // use special nodes iterator
7524 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7525 while( anIter->more() ) {
7526 const SMDS_MeshNode* n = anIter->next();
7527 if ( n == theBetweenNode1 )
7529 else if ( n == theBetweenNode2 )
7535 nodes[ iNode++ ] = n;
7539 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7540 while ( nodeIt->more() ) {
7541 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7542 if ( n == theBetweenNode1 )
7544 else if ( n == theBetweenNode2 )
7550 nodes[ iNode++ ] = n;
7553 if ( il1 < 0 || il2 < 0 || i3 < 0 )
7556 // arrange link nodes to go one after another regarding the face orientation
7557 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
7558 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
7563 aNodesToInsert.reverse();
7565 // check that not link nodes of a quadrangles are in good order
7566 int nbFaceNodes = theFace->NbNodes();
7567 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
7573 if (toCreatePoly || theFace->IsPoly()) {
7576 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
7578 // add nodes of face up to first node of link
7581 if(theFace->IsQuadratic()) {
7582 const SMDS_QuadraticFaceOfNodes* F =
7583 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
7584 // use special nodes iterator
7585 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7586 while( anIter->more() && !isFLN ) {
7587 const SMDS_MeshNode* n = anIter->next();
7588 poly_nodes[iNode++] = n;
7589 if (n == nodes[il1]) {
7593 // add nodes to insert
7594 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7595 for (; nIt != aNodesToInsert.end(); nIt++) {
7596 poly_nodes[iNode++] = *nIt;
7598 // add nodes of face starting from last node of link
7599 while ( anIter->more() ) {
7600 poly_nodes[iNode++] = anIter->next();
7604 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
7605 while ( nodeIt->more() && !isFLN ) {
7606 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7607 poly_nodes[iNode++] = n;
7608 if (n == nodes[il1]) {
7612 // add nodes to insert
7613 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7614 for (; nIt != aNodesToInsert.end(); nIt++) {
7615 poly_nodes[iNode++] = *nIt;
7617 // add nodes of face starting from last node of link
7618 while ( nodeIt->more() ) {
7619 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
7620 poly_nodes[iNode++] = n;
7624 // edit or replace the face
7625 SMESHDS_Mesh *aMesh = GetMeshDS();
7627 if (theFace->IsPoly()) {
7628 aMesh->ChangePolygonNodes(theFace, poly_nodes);
7631 int aShapeId = FindShape( theFace );
7633 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7634 myLastCreatedElems.Append(newElem);
7635 if ( aShapeId && newElem )
7636 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7638 aMesh->RemoveElement(theFace);
7643 if( !theFace->IsQuadratic() ) {
7645 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
7646 int nbLinkNodes = 2 + aNodesToInsert.size();
7647 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
7648 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
7649 linkNodes[ 0 ] = nodes[ il1 ];
7650 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
7651 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7652 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7653 linkNodes[ iNode++ ] = *nIt;
7655 // decide how to split a quadrangle: compare possible variants
7656 // and choose which of splits to be a quadrangle
7657 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
7658 if ( nbFaceNodes == 3 ) {
7659 iBestQuad = nbSplits;
7662 else if ( nbFaceNodes == 4 ) {
7663 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
7664 double aBestRate = DBL_MAX;
7665 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
7667 double aBadRate = 0;
7668 // evaluate elements quality
7669 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
7670 if ( iSplit == iQuad ) {
7671 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
7675 aBadRate += getBadRate( &quad, aCrit );
7678 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
7680 nodes[ iSplit < iQuad ? i4 : i3 ]);
7681 aBadRate += getBadRate( &tria, aCrit );
7685 if ( aBadRate < aBestRate ) {
7687 aBestRate = aBadRate;
7692 // create new elements
7693 SMESHDS_Mesh *aMesh = GetMeshDS();
7694 int aShapeId = FindShape( theFace );
7697 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
7698 SMDS_MeshElement* newElem = 0;
7699 if ( iSplit == iBestQuad )
7700 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7705 newElem = aMesh->AddFace (linkNodes[ i1++ ],
7707 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
7708 myLastCreatedElems.Append(newElem);
7709 if ( aShapeId && newElem )
7710 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7713 // change nodes of theFace
7714 const SMDS_MeshNode* newNodes[ 4 ];
7715 newNodes[ 0 ] = linkNodes[ i1 ];
7716 newNodes[ 1 ] = linkNodes[ i2 ];
7717 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
7718 newNodes[ 3 ] = nodes[ i4 ];
7719 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
7720 } // end if(!theFace->IsQuadratic())
7721 else { // theFace is quadratic
7722 // we have to split theFace on simple triangles and one simple quadrangle
7724 int nbshift = tmp*2;
7725 // shift nodes in nodes[] by nbshift
7727 for(i=0; i<nbshift; i++) {
7728 const SMDS_MeshNode* n = nodes[0];
7729 for(j=0; j<nbFaceNodes-1; j++) {
7730 nodes[j] = nodes[j+1];
7732 nodes[nbFaceNodes-1] = n;
7734 il1 = il1 - nbshift;
7735 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
7736 // n0 n1 n2 n0 n1 n2
7737 // +-----+-----+ +-----+-----+
7746 // create new elements
7747 SMESHDS_Mesh *aMesh = GetMeshDS();
7748 int aShapeId = FindShape( theFace );
7751 if(nbFaceNodes==6) { // quadratic triangle
7752 SMDS_MeshElement* newElem =
7753 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7754 myLastCreatedElems.Append(newElem);
7755 if ( aShapeId && newElem )
7756 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7757 if(theFace->IsMediumNode(nodes[il1])) {
7758 // create quadrangle
7759 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
7760 myLastCreatedElems.Append(newElem);
7761 if ( aShapeId && newElem )
7762 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7768 // create quadrangle
7769 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
7770 myLastCreatedElems.Append(newElem);
7771 if ( aShapeId && newElem )
7772 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7778 else { // nbFaceNodes==8 - quadratic quadrangle
7779 SMDS_MeshElement* newElem =
7780 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
7781 myLastCreatedElems.Append(newElem);
7782 if ( aShapeId && newElem )
7783 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7784 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
7785 myLastCreatedElems.Append(newElem);
7786 if ( aShapeId && newElem )
7787 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7788 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
7789 myLastCreatedElems.Append(newElem);
7790 if ( aShapeId && newElem )
7791 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7792 if(theFace->IsMediumNode(nodes[il1])) {
7793 // create quadrangle
7794 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
7795 myLastCreatedElems.Append(newElem);
7796 if ( aShapeId && newElem )
7797 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7803 // create quadrangle
7804 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
7805 myLastCreatedElems.Append(newElem);
7806 if ( aShapeId && newElem )
7807 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7813 // create needed triangles using n1,n2,n3 and inserted nodes
7814 int nbn = 2 + aNodesToInsert.size();
7815 //const SMDS_MeshNode* aNodes[nbn];
7816 vector<const SMDS_MeshNode*> aNodes(nbn);
7817 aNodes[0] = nodes[n1];
7818 aNodes[nbn-1] = nodes[n2];
7819 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
7820 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
7821 aNodes[iNode++] = *nIt;
7823 for(i=1; i<nbn; i++) {
7824 SMDS_MeshElement* newElem =
7825 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
7826 myLastCreatedElems.Append(newElem);
7827 if ( aShapeId && newElem )
7828 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7830 // remove old quadratic face
7831 aMesh->RemoveElement(theFace);
7835 //=======================================================================
7836 //function : UpdateVolumes
7838 //=======================================================================
7839 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
7840 const SMDS_MeshNode* theBetweenNode2,
7841 list<const SMDS_MeshNode*>& theNodesToInsert)
7843 myLastCreatedElems.Clear();
7844 myLastCreatedNodes.Clear();
7846 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
7847 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
7848 const SMDS_MeshElement* elem = invElemIt->next();
7850 // check, if current volume has link theBetweenNode1 - theBetweenNode2
7851 SMDS_VolumeTool aVolume (elem);
7852 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
7855 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
7856 int iface, nbFaces = aVolume.NbFaces();
7857 vector<const SMDS_MeshNode *> poly_nodes;
7858 vector<int> quantities (nbFaces);
7860 for (iface = 0; iface < nbFaces; iface++) {
7861 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
7862 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
7863 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
7865 for (int inode = 0; inode < nbFaceNodes; inode++) {
7866 poly_nodes.push_back(faceNodes[inode]);
7868 if (nbInserted == 0) {
7869 if (faceNodes[inode] == theBetweenNode1) {
7870 if (faceNodes[inode + 1] == theBetweenNode2) {
7871 nbInserted = theNodesToInsert.size();
7873 // add nodes to insert
7874 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
7875 for (; nIt != theNodesToInsert.end(); nIt++) {
7876 poly_nodes.push_back(*nIt);
7880 else if (faceNodes[inode] == theBetweenNode2) {
7881 if (faceNodes[inode + 1] == theBetweenNode1) {
7882 nbInserted = theNodesToInsert.size();
7884 // add nodes to insert in reversed order
7885 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
7887 for (; nIt != theNodesToInsert.begin(); nIt--) {
7888 poly_nodes.push_back(*nIt);
7890 poly_nodes.push_back(*nIt);
7897 quantities[iface] = nbFaceNodes + nbInserted;
7900 // Replace or update the volume
7901 SMESHDS_Mesh *aMesh = GetMeshDS();
7903 if (elem->IsPoly()) {
7904 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7908 int aShapeId = FindShape( elem );
7910 SMDS_MeshElement* newElem =
7911 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7912 myLastCreatedElems.Append(newElem);
7913 if (aShapeId && newElem)
7914 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7916 aMesh->RemoveElement(elem);
7921 //=======================================================================
7923 * \brief Convert elements contained in a submesh to quadratic
7924 * \retval int - nb of checked elements
7926 //=======================================================================
7928 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
7929 SMESH_MesherHelper& theHelper,
7930 const bool theForce3d)
7933 if( !theSm ) return nbElem;
7935 const bool notFromGroups = false;
7936 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
7937 while(ElemItr->more())
7940 const SMDS_MeshElement* elem = ElemItr->next();
7941 if( !elem || elem->IsQuadratic() ) continue;
7943 int id = elem->GetID();
7944 int nbNodes = elem->NbNodes();
7945 vector<const SMDS_MeshNode *> aNds (nbNodes);
7947 for(int i = 0; i < nbNodes; i++)
7949 aNds[i] = elem->GetNode(i);
7951 SMDSAbs_ElementType aType = elem->GetType();
7953 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
7955 const SMDS_MeshElement* NewElem = 0;
7961 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
7969 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
7972 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7979 case SMDSAbs_Volume :
7984 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
7987 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
7990 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
7993 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
7994 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8004 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8006 theSm->AddElement( NewElem );
8011 //=======================================================================
8012 //function : ConvertToQuadratic
8014 //=======================================================================
8015 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8017 SMESHDS_Mesh* meshDS = GetMeshDS();
8019 SMESH_MesherHelper aHelper(*myMesh);
8020 aHelper.SetIsQuadratic( true );
8021 const bool notFromGroups = false;
8023 int nbCheckedElems = 0;
8024 if ( myMesh->HasShapeToMesh() )
8026 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8028 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8029 while ( smIt->more() ) {
8030 SMESH_subMesh* sm = smIt->next();
8031 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8032 aHelper.SetSubShape( sm->GetSubShape() );
8033 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8038 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8039 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8041 SMESHDS_SubMesh *smDS = 0;
8042 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8043 while(aEdgeItr->more())
8045 const SMDS_MeshEdge* edge = aEdgeItr->next();
8046 if(edge && !edge->IsQuadratic())
8048 int id = edge->GetID();
8049 const SMDS_MeshNode* n1 = edge->GetNode(0);
8050 const SMDS_MeshNode* n2 = edge->GetNode(1);
8052 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8054 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8055 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8058 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8059 while(aFaceItr->more())
8061 const SMDS_MeshFace* face = aFaceItr->next();
8062 if(!face || face->IsQuadratic() ) continue;
8064 int id = face->GetID();
8065 int nbNodes = face->NbNodes();
8066 vector<const SMDS_MeshNode *> aNds (nbNodes);
8068 for(int i = 0; i < nbNodes; i++)
8070 aNds[i] = face->GetNode(i);
8073 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8075 SMDS_MeshFace * NewFace = 0;
8079 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8082 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8087 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8089 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8090 while(aVolumeItr->more())
8092 const SMDS_MeshVolume* volume = aVolumeItr->next();
8093 if(!volume || volume->IsQuadratic() ) continue;
8095 int id = volume->GetID();
8096 int nbNodes = volume->NbNodes();
8097 vector<const SMDS_MeshNode *> aNds (nbNodes);
8099 for(int i = 0; i < nbNodes; i++)
8101 aNds[i] = volume->GetNode(i);
8104 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8106 SMDS_MeshVolume * NewVolume = 0;
8110 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8111 aNds[3], id, theForce3d );
8114 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8115 aNds[3], aNds[4], id, theForce3d);
8118 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8119 aNds[3], aNds[4], aNds[5], id, theForce3d);
8122 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8123 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8128 ReplaceElemInGroups(volume, NewVolume, meshDS);
8131 if ( !theForce3d ) {
8132 aHelper.SetSubShape(0); // apply to the whole mesh
8133 aHelper.FixQuadraticElements();
8137 //=======================================================================
8139 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8140 * \retval int - nb of checked elements
8142 //=======================================================================
8144 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8145 SMDS_ElemIteratorPtr theItr,
8146 const int theShapeID)
8149 SMESHDS_Mesh* meshDS = GetMeshDS();
8150 const bool notFromGroups = false;
8152 while( theItr->more() )
8154 const SMDS_MeshElement* elem = theItr->next();
8156 if( elem && elem->IsQuadratic())
8158 int id = elem->GetID();
8159 int nbNodes = elem->NbNodes();
8160 vector<const SMDS_MeshNode *> aNds, mediumNodes;
8161 aNds.reserve( nbNodes );
8162 mediumNodes.reserve( nbNodes );
8164 for(int i = 0; i < nbNodes; i++)
8166 const SMDS_MeshNode* n = elem->GetNode(i);
8168 if( elem->IsMediumNode( n ) )
8169 mediumNodes.push_back( n );
8171 aNds.push_back( n );
8173 if( aNds.empty() ) continue;
8174 SMDSAbs_ElementType aType = elem->GetType();
8176 //remove old quadratic element
8177 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8179 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8180 ReplaceElemInGroups(elem, NewElem, meshDS);
8181 if( theSm && NewElem )
8182 theSm->AddElement( NewElem );
8184 // remove medium nodes
8185 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8186 for ( ; nIt != mediumNodes.end(); ++nIt ) {
8187 const SMDS_MeshNode* n = *nIt;
8188 if ( n->NbInverseElements() == 0 ) {
8189 if ( n->GetPosition()->GetShapeId() != theShapeID )
8190 meshDS->RemoveFreeNode( n, meshDS->MeshElements
8191 ( n->GetPosition()->GetShapeId() ));
8193 meshDS->RemoveFreeNode( n, theSm );
8201 //=======================================================================
8202 //function : ConvertFromQuadratic
8204 //=======================================================================
8205 bool SMESH_MeshEditor::ConvertFromQuadratic()
8207 int nbCheckedElems = 0;
8208 if ( myMesh->HasShapeToMesh() )
8210 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8212 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8213 while ( smIt->more() ) {
8214 SMESH_subMesh* sm = smIt->next();
8215 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8216 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8222 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8223 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8225 SMESHDS_SubMesh *aSM = 0;
8226 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8232 //=======================================================================
8233 //function : SewSideElements
8235 //=======================================================================
8237 SMESH_MeshEditor::Sew_Error
8238 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8239 TIDSortedElemSet& theSide2,
8240 const SMDS_MeshNode* theFirstNode1,
8241 const SMDS_MeshNode* theFirstNode2,
8242 const SMDS_MeshNode* theSecondNode1,
8243 const SMDS_MeshNode* theSecondNode2)
8245 myLastCreatedElems.Clear();
8246 myLastCreatedNodes.Clear();
8248 MESSAGE ("::::SewSideElements()");
8249 if ( theSide1.size() != theSide2.size() )
8250 return SEW_DIFF_NB_OF_ELEMENTS;
8252 Sew_Error aResult = SEW_OK;
8254 // 1. Build set of faces representing each side
8255 // 2. Find which nodes of the side 1 to merge with ones on the side 2
8256 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8258 // =======================================================================
8259 // 1. Build set of faces representing each side:
8260 // =======================================================================
8261 // a. build set of nodes belonging to faces
8262 // b. complete set of faces: find missing fices whose nodes are in set of nodes
8263 // c. create temporary faces representing side of volumes if correspondent
8264 // face does not exist
8266 SMESHDS_Mesh* aMesh = GetMeshDS();
8267 SMDS_Mesh aTmpFacesMesh;
8268 set<const SMDS_MeshElement*> faceSet1, faceSet2;
8269 set<const SMDS_MeshElement*> volSet1, volSet2;
8270 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
8271 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8272 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
8273 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8274 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8275 int iSide, iFace, iNode;
8277 for ( iSide = 0; iSide < 2; iSide++ ) {
8278 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
8279 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8280 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8281 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
8282 set<const SMDS_MeshElement*>::iterator vIt;
8283 TIDSortedElemSet::iterator eIt;
8284 set<const SMDS_MeshNode*>::iterator nIt;
8286 // check that given nodes belong to given elements
8287 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8288 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8289 int firstIndex = -1, secondIndex = -1;
8290 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8291 const SMDS_MeshElement* elem = *eIt;
8292 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8293 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8294 if ( firstIndex > -1 && secondIndex > -1 ) break;
8296 if ( firstIndex < 0 || secondIndex < 0 ) {
8297 // we can simply return until temporary faces created
8298 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8301 // -----------------------------------------------------------
8302 // 1a. Collect nodes of existing faces
8303 // and build set of face nodes in order to detect missing
8304 // faces corresponing to sides of volumes
8305 // -----------------------------------------------------------
8307 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8309 // loop on the given element of a side
8310 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8311 //const SMDS_MeshElement* elem = *eIt;
8312 const SMDS_MeshElement* elem = *eIt;
8313 if ( elem->GetType() == SMDSAbs_Face ) {
8314 faceSet->insert( elem );
8315 set <const SMDS_MeshNode*> faceNodeSet;
8316 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8317 while ( nodeIt->more() ) {
8318 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8319 nodeSet->insert( n );
8320 faceNodeSet.insert( n );
8322 setOfFaceNodeSet.insert( faceNodeSet );
8324 else if ( elem->GetType() == SMDSAbs_Volume )
8325 volSet->insert( elem );
8327 // ------------------------------------------------------------------------------
8328 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8329 // ------------------------------------------------------------------------------
8331 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8332 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8333 while ( fIt->more() ) { // loop on faces sharing a node
8334 const SMDS_MeshElement* f = fIt->next();
8335 if ( faceSet->find( f ) == faceSet->end() ) {
8336 // check if all nodes are in nodeSet and
8337 // complete setOfFaceNodeSet if they are
8338 set <const SMDS_MeshNode*> faceNodeSet;
8339 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8340 bool allInSet = true;
8341 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8342 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8343 if ( nodeSet->find( n ) == nodeSet->end() )
8346 faceNodeSet.insert( n );
8349 faceSet->insert( f );
8350 setOfFaceNodeSet.insert( faceNodeSet );
8356 // -------------------------------------------------------------------------
8357 // 1c. Create temporary faces representing sides of volumes if correspondent
8358 // face does not exist
8359 // -------------------------------------------------------------------------
8361 if ( !volSet->empty() ) {
8362 //int nodeSetSize = nodeSet->size();
8364 // loop on given volumes
8365 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8366 SMDS_VolumeTool vol (*vIt);
8367 // loop on volume faces: find free faces
8368 // --------------------------------------
8369 list<const SMDS_MeshElement* > freeFaceList;
8370 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8371 if ( !vol.IsFreeFace( iFace ))
8373 // check if there is already a face with same nodes in a face set
8374 const SMDS_MeshElement* aFreeFace = 0;
8375 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8376 int nbNodes = vol.NbFaceNodes( iFace );
8377 set <const SMDS_MeshNode*> faceNodeSet;
8378 vol.GetFaceNodes( iFace, faceNodeSet );
8379 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8381 // no such a face is given but it still can exist, check it
8382 if ( nbNodes == 3 ) {
8383 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8385 else if ( nbNodes == 4 ) {
8386 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8389 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8390 aFreeFace = aMesh->FindFace(poly_nodes);
8394 // create a temporary face
8395 if ( nbNodes == 3 ) {
8396 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8398 else if ( nbNodes == 4 ) {
8399 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8402 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8403 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8407 freeFaceList.push_back( aFreeFace );
8409 } // loop on faces of a volume
8411 // choose one of several free faces
8412 // --------------------------------------
8413 if ( freeFaceList.size() > 1 ) {
8414 // choose a face having max nb of nodes shared by other elems of a side
8415 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8416 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8417 while ( fIt != freeFaceList.end() ) { // loop on free faces
8418 int nbSharedNodes = 0;
8419 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8420 while ( nodeIt->more() ) { // loop on free face nodes
8421 const SMDS_MeshNode* n =
8422 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8423 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8424 while ( invElemIt->more() ) {
8425 const SMDS_MeshElement* e = invElemIt->next();
8426 if ( faceSet->find( e ) != faceSet->end() )
8428 if ( elemSet->find( e ) != elemSet->end() )
8432 if ( nbSharedNodes >= maxNbNodes ) {
8433 maxNbNodes = nbSharedNodes;
8437 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8439 if ( freeFaceList.size() > 1 )
8441 // could not choose one face, use another way
8442 // choose a face most close to the bary center of the opposite side
8443 gp_XYZ aBC( 0., 0., 0. );
8444 set <const SMDS_MeshNode*> addedNodes;
8445 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8446 eIt = elemSet2->begin();
8447 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8448 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8449 while ( nodeIt->more() ) { // loop on free face nodes
8450 const SMDS_MeshNode* n =
8451 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8452 if ( addedNodes.insert( n ).second )
8453 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8456 aBC /= addedNodes.size();
8457 double minDist = DBL_MAX;
8458 fIt = freeFaceList.begin();
8459 while ( fIt != freeFaceList.end() ) { // loop on free faces
8461 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8462 while ( nodeIt->more() ) { // loop on free face nodes
8463 const SMDS_MeshNode* n =
8464 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8465 gp_XYZ p( n->X(),n->Y(),n->Z() );
8466 dist += ( aBC - p ).SquareModulus();
8468 if ( dist < minDist ) {
8470 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8473 fIt = freeFaceList.erase( fIt++ );
8476 } // choose one of several free faces of a volume
8478 if ( freeFaceList.size() == 1 ) {
8479 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8480 faceSet->insert( aFreeFace );
8481 // complete a node set with nodes of a found free face
8482 // for ( iNode = 0; iNode < ; iNode++ )
8483 // nodeSet->insert( fNodes[ iNode ] );
8486 } // loop on volumes of a side
8488 // // complete a set of faces if new nodes in a nodeSet appeared
8489 // // ----------------------------------------------------------
8490 // if ( nodeSetSize != nodeSet->size() ) {
8491 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8492 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8493 // while ( fIt->more() ) { // loop on faces sharing a node
8494 // const SMDS_MeshElement* f = fIt->next();
8495 // if ( faceSet->find( f ) == faceSet->end() ) {
8496 // // check if all nodes are in nodeSet and
8497 // // complete setOfFaceNodeSet if they are
8498 // set <const SMDS_MeshNode*> faceNodeSet;
8499 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8500 // bool allInSet = true;
8501 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8502 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8503 // if ( nodeSet->find( n ) == nodeSet->end() )
8504 // allInSet = false;
8506 // faceNodeSet.insert( n );
8508 // if ( allInSet ) {
8509 // faceSet->insert( f );
8510 // setOfFaceNodeSet.insert( faceNodeSet );
8516 } // Create temporary faces, if there are volumes given
8519 if ( faceSet1.size() != faceSet2.size() ) {
8520 // delete temporary faces: they are in reverseElements of actual nodes
8521 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8522 while ( tmpFaceIt->more() )
8523 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8524 MESSAGE("Diff nb of faces");
8525 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8528 // ============================================================
8529 // 2. Find nodes to merge:
8530 // bind a node to remove to a node to put instead
8531 // ============================================================
8533 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
8534 if ( theFirstNode1 != theFirstNode2 )
8535 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
8536 if ( theSecondNode1 != theSecondNode2 )
8537 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
8539 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8540 set< long > linkIdSet; // links to process
8541 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
8543 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
8544 list< NLink > linkList[2];
8545 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8546 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8547 // loop on links in linkList; find faces by links and append links
8548 // of the found faces to linkList
8549 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8550 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8551 NLink link[] = { *linkIt[0], *linkIt[1] };
8552 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
8553 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
8556 // by links, find faces in the face sets,
8557 // and find indices of link nodes in the found faces;
8558 // in a face set, there is only one or no face sharing a link
8559 // ---------------------------------------------------------------
8561 const SMDS_MeshElement* face[] = { 0, 0 };
8562 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
8563 vector<const SMDS_MeshNode*> fnodes1(9);
8564 vector<const SMDS_MeshNode*> fnodes2(9);
8565 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
8566 vector<const SMDS_MeshNode*> notLinkNodes1(6);
8567 vector<const SMDS_MeshNode*> notLinkNodes2(6);
8568 int iLinkNode[2][2];
8569 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8570 const SMDS_MeshNode* n1 = link[iSide].first;
8571 const SMDS_MeshNode* n2 = link[iSide].second;
8572 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8573 set< const SMDS_MeshElement* > fMap;
8574 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
8575 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
8576 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8577 while ( fIt->more() ) { // loop on faces sharing a node
8578 const SMDS_MeshElement* f = fIt->next();
8579 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8580 ! fMap.insert( f ).second ) // f encounters twice
8582 if ( face[ iSide ] ) {
8583 MESSAGE( "2 faces per link " );
8584 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
8588 faceSet->erase( f );
8589 // get face nodes and find ones of a link
8594 fnodes1.resize(f->NbNodes()+1);
8595 notLinkNodes1.resize(f->NbNodes()-2);
8598 fnodes2.resize(f->NbNodes()+1);
8599 notLinkNodes2.resize(f->NbNodes()-2);
8602 if(!f->IsQuadratic()) {
8603 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
8604 while ( nIt->more() ) {
8605 const SMDS_MeshNode* n =
8606 static_cast<const SMDS_MeshNode*>( nIt->next() );
8608 iLinkNode[ iSide ][ 0 ] = iNode;
8610 else if ( n == n2 ) {
8611 iLinkNode[ iSide ][ 1 ] = iNode;
8613 //else if ( notLinkNodes[ iSide ][ 0 ] )
8614 // notLinkNodes[ iSide ][ 1 ] = n;
8616 // notLinkNodes[ iSide ][ 0 ] = n;
8620 notLinkNodes1[nbl] = n;
8621 //notLinkNodes1.push_back(n);
8623 notLinkNodes2[nbl] = n;
8624 //notLinkNodes2.push_back(n);
8626 //faceNodes[ iSide ][ iNode++ ] = n;
8628 fnodes1[iNode++] = n;
8631 fnodes2[iNode++] = n;
8635 else { // f->IsQuadratic()
8636 const SMDS_QuadraticFaceOfNodes* F =
8637 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
8638 // use special nodes iterator
8639 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8640 while ( anIter->more() ) {
8641 const SMDS_MeshNode* n =
8642 static_cast<const SMDS_MeshNode*>( anIter->next() );
8644 iLinkNode[ iSide ][ 0 ] = iNode;
8646 else if ( n == n2 ) {
8647 iLinkNode[ iSide ][ 1 ] = iNode;
8652 notLinkNodes1[nbl] = n;
8655 notLinkNodes2[nbl] = n;
8659 fnodes1[iNode++] = n;
8662 fnodes2[iNode++] = n;
8666 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
8668 fnodes1[iNode] = fnodes1[0];
8671 fnodes2[iNode] = fnodes1[0];
8678 // check similarity of elements of the sides
8679 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8680 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8681 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8682 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8685 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8687 break; // do not return because it s necessary to remove tmp faces
8690 // set nodes to merge
8691 // -------------------
8693 if ( face[0] && face[1] ) {
8694 int nbNodes = face[0]->NbNodes();
8695 if ( nbNodes != face[1]->NbNodes() ) {
8696 MESSAGE("Diff nb of face nodes");
8697 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8698 break; // do not return because it s necessary to remove tmp faces
8700 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
8701 if ( nbNodes == 3 ) {
8702 //nReplaceMap.insert( TNodeNodeMap::value_type
8703 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8704 nReplaceMap.insert( TNodeNodeMap::value_type
8705 ( notLinkNodes1[0], notLinkNodes2[0] ));
8708 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
8709 // analyse link orientation in faces
8710 int i1 = iLinkNode[ iSide ][ 0 ];
8711 int i2 = iLinkNode[ iSide ][ 1 ];
8712 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
8713 // if notLinkNodes are the first and the last ones, then
8714 // their order does not correspond to the link orientation
8715 if (( i1 == 1 && i2 == 2 ) ||
8716 ( i1 == 2 && i2 == 1 ))
8717 reverse[ iSide ] = !reverse[ iSide ];
8719 if ( reverse[0] == reverse[1] ) {
8720 //nReplaceMap.insert( TNodeNodeMap::value_type
8721 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
8722 //nReplaceMap.insert( TNodeNodeMap::value_type
8723 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
8724 for(int nn=0; nn<nbNodes-2; nn++) {
8725 nReplaceMap.insert( TNodeNodeMap::value_type
8726 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
8730 //nReplaceMap.insert( TNodeNodeMap::value_type
8731 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
8732 //nReplaceMap.insert( TNodeNodeMap::value_type
8733 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
8734 for(int nn=0; nn<nbNodes-2; nn++) {
8735 nReplaceMap.insert( TNodeNodeMap::value_type
8736 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
8741 // add other links of the faces to linkList
8742 // -----------------------------------------
8744 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
8745 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8746 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
8747 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
8748 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
8749 if ( !iter_isnew.second ) { // already in a set: no need to process
8750 linkIdSet.erase( iter_isnew.first );
8752 else // new in set == encountered for the first time: add
8754 //const SMDS_MeshNode* n1 = nodes[ iNode ];
8755 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
8756 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
8757 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
8758 linkList[0].push_back ( NLink( n1, n2 ));
8759 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8763 } // loop on link lists
8765 if ( aResult == SEW_OK &&
8766 ( linkIt[0] != linkList[0].end() ||
8767 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
8768 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
8769 " " << (faceSetPtr[1]->empty()));
8770 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8773 // ====================================================================
8774 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8775 // ====================================================================
8777 // delete temporary faces: they are in reverseElements of actual nodes
8778 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
8779 while ( tmpFaceIt->more() )
8780 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
8782 if ( aResult != SEW_OK)
8785 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
8786 // loop on nodes replacement map
8787 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
8788 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
8789 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
8790 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
8791 nodeIDsToRemove.push_back( nToRemove->GetID() );
8792 // loop on elements sharing nToRemove
8793 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
8794 while ( invElemIt->more() ) {
8795 const SMDS_MeshElement* e = invElemIt->next();
8796 // get a new suite of nodes: make replacement
8797 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
8798 vector< const SMDS_MeshNode*> nodes( nbNodes );
8799 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8800 while ( nIt->more() ) {
8801 const SMDS_MeshNode* n =
8802 static_cast<const SMDS_MeshNode*>( nIt->next() );
8803 nnIt = nReplaceMap.find( n );
8804 if ( nnIt != nReplaceMap.end() ) {
8810 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
8811 // elemIDsToRemove.push_back( e->GetID() );
8814 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
8818 Remove( nodeIDsToRemove, true );
8823 //================================================================================
8825 * \brief Find corresponding nodes in two sets of faces
8826 * \param theSide1 - first face set
8827 * \param theSide2 - second first face
8828 * \param theFirstNode1 - a boundary node of set 1
8829 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
8830 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
8831 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
8832 * \param nReplaceMap - output map of corresponding nodes
8833 * \retval bool - is a success or not
8835 //================================================================================
8838 //#define DEBUG_MATCHING_NODES
8841 SMESH_MeshEditor::Sew_Error
8842 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
8843 set<const SMDS_MeshElement*>& theSide2,
8844 const SMDS_MeshNode* theFirstNode1,
8845 const SMDS_MeshNode* theFirstNode2,
8846 const SMDS_MeshNode* theSecondNode1,
8847 const SMDS_MeshNode* theSecondNode2,
8848 TNodeNodeMap & nReplaceMap)
8850 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
8852 nReplaceMap.clear();
8853 if ( theFirstNode1 != theFirstNode2 )
8854 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
8855 if ( theSecondNode1 != theSecondNode2 )
8856 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
8858 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
8859 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
8861 list< NLink > linkList[2];
8862 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
8863 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
8865 // loop on links in linkList; find faces by links and append links
8866 // of the found faces to linkList
8867 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
8868 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
8869 NLink link[] = { *linkIt[0], *linkIt[1] };
8870 if ( linkSet.find( link[0] ) == linkSet.end() )
8873 // by links, find faces in the face sets,
8874 // and find indices of link nodes in the found faces;
8875 // in a face set, there is only one or no face sharing a link
8876 // ---------------------------------------------------------------
8878 const SMDS_MeshElement* face[] = { 0, 0 };
8879 list<const SMDS_MeshNode*> notLinkNodes[2];
8880 //bool reverse[] = { false, false }; // order of notLinkNodes
8882 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
8884 const SMDS_MeshNode* n1 = link[iSide].first;
8885 const SMDS_MeshNode* n2 = link[iSide].second;
8886 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8887 set< const SMDS_MeshElement* > facesOfNode1;
8888 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
8890 // during a loop of the first node, we find all faces around n1,
8891 // during a loop of the second node, we find one face sharing both n1 and n2
8892 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
8893 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
8894 while ( fIt->more() ) { // loop on faces sharing a node
8895 const SMDS_MeshElement* f = fIt->next();
8896 if (faceSet->find( f ) != faceSet->end() && // f is in face set
8897 ! facesOfNode1.insert( f ).second ) // f encounters twice
8899 if ( face[ iSide ] ) {
8900 MESSAGE( "2 faces per link " );
8901 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8904 faceSet->erase( f );
8906 // get not link nodes
8907 int nbN = f->NbNodes();
8908 if ( f->IsQuadratic() )
8910 nbNodes[ iSide ] = nbN;
8911 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
8912 int i1 = f->GetNodeIndex( n1 );
8913 int i2 = f->GetNodeIndex( n2 );
8914 int iEnd = nbN, iBeg = -1, iDelta = 1;
8915 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
8917 std::swap( iEnd, iBeg ); iDelta = -1;
8922 if ( i == iEnd ) i = iBeg + iDelta;
8923 if ( i == i1 ) break;
8924 nodes.push_back ( f->GetNode( i ) );
8930 // check similarity of elements of the sides
8931 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
8932 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
8933 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
8934 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
8937 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8941 // set nodes to merge
8942 // -------------------
8944 if ( face[0] && face[1] ) {
8945 if ( nbNodes[0] != nbNodes[1] ) {
8946 MESSAGE("Diff nb of face nodes");
8947 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
8949 #ifdef DEBUG_MATCHING_NODES
8950 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
8951 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
8952 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
8954 int nbN = nbNodes[0];
8956 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
8957 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
8958 for ( int i = 0 ; i < nbN - 2; ++i ) {
8959 #ifdef DEBUG_MATCHING_NODES
8960 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
8962 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
8966 // add other links of the face 1 to linkList
8967 // -----------------------------------------
8969 const SMDS_MeshElement* f0 = face[0];
8970 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
8971 for ( int i = 0; i < nbN; i++ )
8973 const SMDS_MeshNode* n2 = f0->GetNode( i );
8974 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
8975 linkSet.insert( SMESH_TLink( n1, n2 ));
8976 if ( !iter_isnew.second ) { // already in a set: no need to process
8977 linkSet.erase( iter_isnew.first );
8979 else // new in set == encountered for the first time: add
8981 #ifdef DEBUG_MATCHING_NODES
8982 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
8983 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
8985 linkList[0].push_back ( NLink( n1, n2 ));
8986 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
8991 } // loop on link lists
8996 //================================================================================
8998 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
8999 \param theElems - the list of elements (edges or faces) to be replicated
9000 The nodes for duplication could be found from these elements
9001 \param theNodesNot - list of nodes to NOT replicate
9002 \param theAffectedElems - the list of elements (cells and edges) to which the
9003 replicated nodes should be associated to.
9004 \return TRUE if operation has been completed successfully, FALSE otherwise
9006 //================================================================================
9008 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9009 const TIDSortedElemSet& theNodesNot,
9010 const TIDSortedElemSet& theAffectedElems )
9012 myLastCreatedElems.Clear();
9013 myLastCreatedNodes.Clear();
9015 if ( theElems.size() == 0 )
9018 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9023 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9024 // duplicate elements and nodes
9025 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9026 // replce nodes by duplications
9027 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9031 //================================================================================
9033 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9034 \param theMeshDS - mesh instance
9035 \param theElems - the elements replicated or modified (nodes should be changed)
9036 \param theNodesNot - nodes to NOT replicate
9037 \param theNodeNodeMap - relation of old node to new created node
9038 \param theIsDoubleElem - flag os to replicate element or modify
9039 \return TRUE if operation has been completed successfully, FALSE otherwise
9041 //================================================================================
9043 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9044 const TIDSortedElemSet& theElems,
9045 const TIDSortedElemSet& theNodesNot,
9046 std::map< const SMDS_MeshNode*,
9047 const SMDS_MeshNode* >& theNodeNodeMap,
9048 const bool theIsDoubleElem )
9050 // iterate on through element and duplicate them (by nodes duplication)
9052 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9053 for ( ; elemItr != theElems.end(); ++elemItr )
9055 const SMDS_MeshElement* anElem = *elemItr;
9059 bool isDuplicate = false;
9060 // duplicate nodes to duplicate element
9061 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9062 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9064 while ( anIter->more() )
9067 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9068 SMDS_MeshNode* aNewNode = aCurrNode;
9069 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9070 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9071 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9074 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9075 theNodeNodeMap[ aCurrNode ] = aNewNode;
9076 myLastCreatedNodes.Append( aNewNode );
9078 isDuplicate |= (aCurrNode != aNewNode);
9079 newNodes[ ind++ ] = aNewNode;
9084 if ( theIsDoubleElem )
9085 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9087 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9094 //================================================================================
9096 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9097 \param theNodes - identifiers of nodes to be doubled
9098 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9099 nodes. If list of element identifiers is empty then nodes are doubled but
9100 they not assigned to elements
9101 \return TRUE if operation has been completed successfully, FALSE otherwise
9103 //================================================================================
9105 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9106 const std::list< int >& theListOfModifiedElems )
9108 myLastCreatedElems.Clear();
9109 myLastCreatedNodes.Clear();
9111 if ( theListOfNodes.size() == 0 )
9114 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9118 // iterate through nodes and duplicate them
9120 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9122 std::list< int >::const_iterator aNodeIter;
9123 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9125 int aCurr = *aNodeIter;
9126 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9132 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9135 anOldNodeToNewNode[ aNode ] = aNewNode;
9136 myLastCreatedNodes.Append( aNewNode );
9140 // Create map of new nodes for modified elements
9142 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9144 std::list< int >::const_iterator anElemIter;
9145 for ( anElemIter = theListOfModifiedElems.begin();
9146 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9148 int aCurr = *anElemIter;
9149 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9153 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9155 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9157 while ( anIter->more() )
9159 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9160 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9162 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9163 aNodeArr[ ind++ ] = aNewNode;
9166 aNodeArr[ ind++ ] = aCurrNode;
9168 anElemToNodes[ anElem ] = aNodeArr;
9171 // Change nodes of elements
9173 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9174 anElemToNodesIter = anElemToNodes.begin();
9175 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9177 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9178 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9180 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9188 //================================================================================
9190 \brief Check if element located inside shape
9191 \return TRUE if IN or ON shape, FALSE otherwise
9193 //================================================================================
9195 template<class Classifier>
9196 bool isInside(const SMDS_MeshElement* theElem,
9197 Classifier& theClassifier,
9198 const double theTol)
9200 gp_XYZ centerXYZ (0, 0, 0);
9201 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9202 while (aNodeItr->more())
9203 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9205 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9206 theClassifier.Perform(aPnt, theTol);
9207 TopAbs_State aState = theClassifier.State();
9208 return (aState == TopAbs_IN || aState == TopAbs_ON );
9211 //================================================================================
9213 * \brief Classifier of the 3D point on the TopoDS_Face
9214 * with interaface suitable for isInside()
9216 //================================================================================
9218 struct _FaceClassifier
9220 Extrema_ExtPS _extremum;
9221 BRepAdaptor_Surface _surface;
9222 TopAbs_State _state;
9224 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9226 _extremum.Initialize( _surface,
9227 _surface.FirstUParameter(), _surface.LastUParameter(),
9228 _surface.FirstVParameter(), _surface.LastVParameter(),
9229 _surface.Tolerance(), _surface.Tolerance() );
9231 void Perform(const gp_Pnt& aPnt, double theTol)
9233 _state = TopAbs_OUT;
9234 _extremum.Perform(aPnt);
9235 if ( _extremum.IsDone() )
9236 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9237 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9239 TopAbs_State State() const
9246 //================================================================================
9248 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9249 \param theElems - group of of elements (edges or faces) to be replicated
9250 \param theNodesNot - group of nodes not to replicate
9251 \param theShape - shape to detect affected elements (element which geometric center
9252 located on or inside shape).
9253 The replicated nodes should be associated to affected elements.
9254 \return TRUE if operation has been completed successfully, FALSE otherwise
9256 //================================================================================
9258 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9259 const TIDSortedElemSet& theNodesNot,
9260 const TopoDS_Shape& theShape )
9262 if ( theShape.IsNull() )
9265 const double aTol = Precision::Confusion();
9266 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9267 auto_ptr<_FaceClassifier> aFaceClassifier;
9268 if ( theShape.ShapeType() == TopAbs_SOLID )
9270 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9271 bsc3d->PerformInfinitePoint(aTol);
9273 else if (theShape.ShapeType() == TopAbs_FACE )
9275 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9278 // iterates on indicated elements and get elements by back references from their nodes
9279 TIDSortedElemSet anAffected;
9280 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9281 for ( ; elemItr != theElems.end(); ++elemItr )
9283 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9287 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9288 while ( nodeItr->more() )
9290 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9291 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9293 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9294 while ( backElemItr->more() )
9296 const SMDS_MeshElement* curElem = backElemItr->next();
9297 if ( curElem && theElems.find(curElem) == theElems.end() &&
9299 isInside( curElem, *bsc3d, aTol ) :
9300 isInside( curElem, *aFaceClassifier, aTol )))
9301 anAffected.insert( curElem );
9305 return DoubleNodes( theElems, theNodesNot, anAffected );
9308 //================================================================================
9310 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9311 * The created 2D mesh elements based on nodes of free faces of boundary volumes
9312 * \return TRUE if operation has been completed successfully, FALSE otherwise
9314 //================================================================================
9316 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9318 // iterates on volume elements and detect all free faces on them
9319 SMESHDS_Mesh* aMesh = GetMeshDS();
9323 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9326 const SMDS_MeshVolume* volume = vIt->next();
9327 SMDS_VolumeTool vTool( volume );
9328 vTool.SetExternalNormal();
9329 const bool isPoly = volume->IsPoly();
9330 const bool isQuad = volume->IsQuadratic();
9331 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9333 if (!vTool.IsFreeFace(iface))
9335 vector<const SMDS_MeshNode *> nodes;
9336 int nbFaceNodes = vTool.NbFaceNodes(iface);
9337 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9339 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9340 nodes.push_back(faceNodes[inode]);
9342 for ( inode = 1; inode < nbFaceNodes; inode += 2)
9343 nodes.push_back(faceNodes[inode]);
9345 // add new face based on volume nodes
9346 if (aMesh->FindFace( nodes ) )
9347 continue; // face already exsist
9348 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );