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_Algo.hxx"
42 #include "SMESH_ControlsDef.hxx"
43 #include "SMESH_Group.hxx"
44 #include "SMESH_MesherHelper.hxx"
45 #include "SMESH_OctreeNode.hxx"
46 #include "SMESH_subMesh.hxx"
48 #include "utilities.h"
50 #include <BRepAdaptor_Surface.hxx>
51 #include <BRepClass3d_SolidClassifier.hxx>
52 #include <BRep_Tool.hxx>
54 #include <Extrema_GenExtPS.hxx>
55 #include <Extrema_POnCurv.hxx>
56 #include <Extrema_POnSurf.hxx>
57 #include <GC_MakeSegment.hxx>
58 #include <Geom2d_Curve.hxx>
59 #include <GeomAPI_ExtremaCurveCurve.hxx>
60 #include <GeomAdaptor_Surface.hxx>
61 #include <Geom_Curve.hxx>
62 #include <Geom_Line.hxx>
63 #include <Geom_Surface.hxx>
64 #include <IntAna_IntConicQuad.hxx>
65 #include <IntAna_Quadric.hxx>
66 #include <Precision.hxx>
67 #include <TColStd_ListOfInteger.hxx>
68 #include <TopAbs_State.hxx>
70 #include <TopExp_Explorer.hxx>
71 #include <TopTools_ListIteratorOfListOfShape.hxx>
72 #include <TopTools_ListOfShape.hxx>
73 #include <TopTools_SequenceOfShape.hxx>
75 #include <TopoDS_Face.hxx>
81 #include <gp_Trsf.hxx>
93 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
96 using namespace SMESH::Controls;
98 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
99 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
101 //=======================================================================
102 //function : SMESH_MeshEditor
104 //=======================================================================
106 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
107 :myMesh( theMesh ) // theMesh may be NULL
111 //=======================================================================
115 //=======================================================================
118 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
119 const SMDSAbs_ElementType type,
123 SMDS_MeshElement* e = 0;
124 int nbnode = node.size();
125 SMESHDS_Mesh* mesh = GetMeshDS();
129 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
130 else e = mesh->AddEdge (node[0], node[1] );
131 else if ( nbnode == 3 )
132 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
133 else e = mesh->AddEdge (node[0], node[1], node[2] );
138 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
139 else e = mesh->AddFace (node[0], node[1], node[2] );
140 else if (nbnode == 4)
141 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
142 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
143 else if (nbnode == 6)
144 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
145 node[4], node[5], ID);
146 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
148 else if (nbnode == 8)
149 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150 node[4], node[5], node[6], node[7], ID);
151 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
152 node[4], node[5], node[6], node[7] );
154 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
155 else e = mesh->AddPolygonalFace (node );
161 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
162 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
163 else if (nbnode == 5)
164 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
166 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
168 else if (nbnode == 6)
169 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
170 node[4], node[5], ID);
171 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
173 else if (nbnode == 8)
174 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175 node[4], node[5], node[6], node[7], ID);
176 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
177 node[4], node[5], node[6], node[7] );
178 else if (nbnode == 10)
179 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180 node[4], node[5], node[6], node[7],
181 node[8], node[9], ID);
182 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 node[4], node[5], node[6], node[7],
185 else if (nbnode == 13)
186 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7],
188 node[8], node[9], node[10],node[11],
190 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
191 node[4], node[5], node[6], node[7],
192 node[8], node[9], node[10],node[11],
194 else if (nbnode == 15)
195 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7],
197 node[8], node[9], node[10],node[11],
198 node[12],node[13],node[14],ID);
199 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
200 node[4], node[5], node[6], node[7],
201 node[8], node[9], node[10],node[11],
202 node[12],node[13],node[14] );
203 else if (nbnode == 20)
204 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
205 node[4], node[5], node[6], node[7],
206 node[8], node[9], node[10],node[11],
207 node[12],node[13],node[14],node[15],
208 node[16],node[17],node[18],node[19],ID);
209 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
210 node[4], node[5], node[6], node[7],
211 node[8], node[9], node[10],node[11],
212 node[12],node[13],node[14],node[15],
213 node[16],node[17],node[18],node[19] );
219 //=======================================================================
223 //=======================================================================
225 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
226 const SMDSAbs_ElementType type,
230 vector<const SMDS_MeshNode*> nodes;
231 nodes.reserve( nodeIDs.size() );
232 vector<int>::const_iterator id = nodeIDs.begin();
233 while ( id != nodeIDs.end() ) {
234 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
235 nodes.push_back( node );
239 return AddElement( nodes, type, isPoly, ID );
242 //=======================================================================
244 //purpose : Remove a node or an element.
245 // Modify a compute state of sub-meshes which become empty
246 //=======================================================================
248 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
251 myLastCreatedElems.Clear();
252 myLastCreatedNodes.Clear();
254 SMESHDS_Mesh* aMesh = GetMeshDS();
255 set< SMESH_subMesh *> smmap;
257 list<int>::const_iterator it = theIDs.begin();
258 for ( ; it != theIDs.end(); it++ ) {
259 const SMDS_MeshElement * elem;
261 elem = aMesh->FindNode( *it );
263 elem = aMesh->FindElement( *it );
267 // Notify VERTEX sub-meshes about modification
269 const SMDS_MeshNode* node = cast2Node( elem );
270 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
271 if ( int aShapeID = node->GetPosition()->GetShapeId() )
272 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
275 // Find sub-meshes to notify about modification
276 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
277 // while ( nodeIt->more() ) {
278 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
279 // const SMDS_PositionPtr& aPosition = node->GetPosition();
280 // if ( aPosition.get() ) {
281 // if ( int aShapeID = aPosition->GetShapeId() ) {
282 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
283 // smmap.insert( sm );
290 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
292 aMesh->RemoveElement( elem );
295 // Notify sub-meshes about modification
296 if ( !smmap.empty() ) {
297 set< SMESH_subMesh *>::iterator smIt;
298 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
299 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
302 // // Check if the whole mesh becomes empty
303 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
304 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
309 //=======================================================================
310 //function : FindShape
311 //purpose : Return an index of the shape theElem is on
312 // or zero if a shape not found
313 //=======================================================================
315 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
317 myLastCreatedElems.Clear();
318 myLastCreatedNodes.Clear();
320 SMESHDS_Mesh * aMesh = GetMeshDS();
321 if ( aMesh->ShapeToMesh().IsNull() )
324 if ( theElem->GetType() == SMDSAbs_Node ) {
325 const SMDS_PositionPtr& aPosition =
326 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
327 if ( aPosition.get() )
328 return aPosition->GetShapeId();
333 TopoDS_Shape aShape; // the shape a node is on
334 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
335 while ( nodeIt->more() ) {
336 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
337 const SMDS_PositionPtr& aPosition = node->GetPosition();
338 if ( aPosition.get() ) {
339 int aShapeID = aPosition->GetShapeId();
340 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
342 if ( sm->Contains( theElem ))
344 if ( aShape.IsNull() )
345 aShape = aMesh->IndexToShape( aShapeID );
348 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
353 // None of nodes is on a proper shape,
354 // find the shape among ancestors of aShape on which a node is
355 if ( aShape.IsNull() ) {
356 //MESSAGE ("::FindShape() - NONE node is on shape")
359 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
360 for ( ; ancIt.More(); ancIt.Next() ) {
361 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
362 if ( sm && sm->Contains( theElem ))
363 return aMesh->ShapeToIndex( ancIt.Value() );
366 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
370 //=======================================================================
371 //function : IsMedium
373 //=======================================================================
375 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
376 const SMDSAbs_ElementType typeToCheck)
378 bool isMedium = false;
379 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
380 while (it->more() && !isMedium ) {
381 const SMDS_MeshElement* elem = it->next();
382 isMedium = elem->IsMediumNode(node);
387 //=======================================================================
388 //function : ShiftNodesQuadTria
390 // Shift nodes in the array corresponded to quadratic triangle
391 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
392 //=======================================================================
393 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
395 const SMDS_MeshNode* nd1 = aNodes[0];
396 aNodes[0] = aNodes[1];
397 aNodes[1] = aNodes[2];
399 const SMDS_MeshNode* nd2 = aNodes[3];
400 aNodes[3] = aNodes[4];
401 aNodes[4] = aNodes[5];
405 //=======================================================================
406 //function : GetNodesFromTwoTria
408 // Shift nodes in the array corresponded to quadratic triangle
409 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
410 //=======================================================================
411 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
412 const SMDS_MeshElement * theTria2,
413 const SMDS_MeshNode* N1[],
414 const SMDS_MeshNode* N2[])
416 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
419 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
422 if(it->more()) return false;
423 it = theTria2->nodesIterator();
426 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
429 if(it->more()) return false;
431 int sames[3] = {-1,-1,-1};
443 if(nbsames!=2) return false;
445 ShiftNodesQuadTria(N1);
447 ShiftNodesQuadTria(N1);
450 i = sames[0] + sames[1] + sames[2];
452 ShiftNodesQuadTria(N2);
454 // now we receive following N1 and N2 (using numeration as above image)
455 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
456 // i.e. first nodes from both arrays determ new diagonal
460 //=======================================================================
461 //function : InverseDiag
462 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
463 // but having other common link.
464 // Return False if args are improper
465 //=======================================================================
467 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
468 const SMDS_MeshElement * theTria2 )
470 myLastCreatedElems.Clear();
471 myLastCreatedNodes.Clear();
473 if (!theTria1 || !theTria2)
476 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
477 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
480 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
481 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
485 // put nodes in array and find out indices of the same ones
486 const SMDS_MeshNode* aNodes [6];
487 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
489 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
490 while ( it->more() ) {
491 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
493 if ( i > 2 ) // theTria2
494 // find same node of theTria1
495 for ( int j = 0; j < 3; j++ )
496 if ( aNodes[ i ] == aNodes[ j ]) {
505 return false; // theTria1 is not a triangle
506 it = theTria2->nodesIterator();
508 if ( i == 6 && it->more() )
509 return false; // theTria2 is not a triangle
512 // find indices of 1,2 and of A,B in theTria1
513 int iA = 0, iB = 0, i1 = 0, i2 = 0;
514 for ( i = 0; i < 6; i++ ) {
515 if ( sameInd [ i ] == 0 )
522 // nodes 1 and 2 should not be the same
523 if ( aNodes[ i1 ] == aNodes[ i2 ] )
527 aNodes[ iA ] = aNodes[ i2 ];
529 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
531 //MESSAGE( theTria1 << theTria2 );
533 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
534 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
536 //MESSAGE( theTria1 << theTria2 );
540 } // end if(F1 && F2)
542 // check case of quadratic faces
543 const SMDS_QuadraticFaceOfNodes* QF1 =
544 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
545 if(!QF1) return false;
546 const SMDS_QuadraticFaceOfNodes* QF2 =
547 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
548 if(!QF2) return false;
551 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
552 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
560 const SMDS_MeshNode* N1 [6];
561 const SMDS_MeshNode* N2 [6];
562 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
564 // now we receive following N1 and N2 (using numeration as above image)
565 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
566 // i.e. first nodes from both arrays determ new diagonal
568 const SMDS_MeshNode* N1new [6];
569 const SMDS_MeshNode* N2new [6];
582 // replaces nodes in faces
583 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
584 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
589 //=======================================================================
590 //function : findTriangles
591 //purpose : find triangles sharing theNode1-theNode2 link
592 //=======================================================================
594 static bool findTriangles(const SMDS_MeshNode * theNode1,
595 const SMDS_MeshNode * theNode2,
596 const SMDS_MeshElement*& theTria1,
597 const SMDS_MeshElement*& theTria2)
599 if ( !theNode1 || !theNode2 ) return false;
601 theTria1 = theTria2 = 0;
603 set< const SMDS_MeshElement* > emap;
604 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
606 const SMDS_MeshElement* elem = it->next();
607 if ( elem->NbNodes() == 3 )
610 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
612 const SMDS_MeshElement* elem = it->next();
613 if ( emap.find( elem ) != emap.end() )
615 // theTria1 must be element with minimum ID
616 if( theTria1->GetID() < elem->GetID() ) {
629 return ( theTria1 && theTria2 );
632 //=======================================================================
633 //function : InverseDiag
634 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
635 // with ones built on the same 4 nodes but having other common link.
636 // Return false if proper faces not found
637 //=======================================================================
639 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
640 const SMDS_MeshNode * theNode2)
642 myLastCreatedElems.Clear();
643 myLastCreatedNodes.Clear();
645 MESSAGE( "::InverseDiag()" );
647 const SMDS_MeshElement *tr1, *tr2;
648 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
651 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
652 //if (!F1) return false;
653 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
654 //if (!F2) return false;
657 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
658 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
662 // put nodes in array
663 // and find indices of 1,2 and of A in tr1 and of B in tr2
664 int i, iA1 = 0, i1 = 0;
665 const SMDS_MeshNode* aNodes1 [3];
666 SMDS_ElemIteratorPtr it;
667 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
668 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
669 if ( aNodes1[ i ] == theNode1 )
670 iA1 = i; // node A in tr1
671 else if ( aNodes1[ i ] != theNode2 )
675 const SMDS_MeshNode* aNodes2 [3];
676 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
677 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
678 if ( aNodes2[ i ] == theNode2 )
679 iB2 = i; // node B in tr2
680 else if ( aNodes2[ i ] != theNode1 )
684 // nodes 1 and 2 should not be the same
685 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
689 aNodes1[ iA1 ] = aNodes2[ i2 ];
691 aNodes2[ iB2 ] = aNodes1[ i1 ];
693 //MESSAGE( tr1 << tr2 );
695 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
696 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
698 //MESSAGE( tr1 << tr2 );
703 // check case of quadratic faces
704 const SMDS_QuadraticFaceOfNodes* QF1 =
705 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
706 if(!QF1) return false;
707 const SMDS_QuadraticFaceOfNodes* QF2 =
708 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
709 if(!QF2) return false;
710 return InverseDiag(tr1,tr2);
713 //=======================================================================
714 //function : getQuadrangleNodes
715 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
716 // fusion of triangles tr1 and tr2 having shared link on
717 // theNode1 and theNode2
718 //=======================================================================
720 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
721 const SMDS_MeshNode * theNode1,
722 const SMDS_MeshNode * theNode2,
723 const SMDS_MeshElement * tr1,
724 const SMDS_MeshElement * tr2 )
726 if( tr1->NbNodes() != tr2->NbNodes() )
728 // find the 4-th node to insert into tr1
729 const SMDS_MeshNode* n4 = 0;
730 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
732 while ( !n4 && i<3 ) {
733 const SMDS_MeshNode * n = cast2Node( it->next() );
735 bool isDiag = ( n == theNode1 || n == theNode2 );
739 // Make an array of nodes to be in a quadrangle
740 int iNode = 0, iFirstDiag = -1;
741 it = tr1->nodesIterator();
744 const SMDS_MeshNode * n = cast2Node( it->next() );
746 bool isDiag = ( n == theNode1 || n == theNode2 );
748 if ( iFirstDiag < 0 )
750 else if ( iNode - iFirstDiag == 1 )
751 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
753 else if ( n == n4 ) {
754 return false; // tr1 and tr2 should not have all the same nodes
756 theQuadNodes[ iNode++ ] = n;
758 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
759 theQuadNodes[ iNode ] = n4;
764 //=======================================================================
765 //function : DeleteDiag
766 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
767 // with a quadrangle built on the same 4 nodes.
768 // Return false if proper faces not found
769 //=======================================================================
771 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
772 const SMDS_MeshNode * theNode2)
774 myLastCreatedElems.Clear();
775 myLastCreatedNodes.Clear();
777 MESSAGE( "::DeleteDiag()" );
779 const SMDS_MeshElement *tr1, *tr2;
780 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
783 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
784 //if (!F1) return false;
785 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
786 //if (!F2) return false;
789 const SMDS_MeshNode* aNodes [ 4 ];
790 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
793 //MESSAGE( endl << tr1 << tr2 );
795 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
796 myLastCreatedElems.Append(tr1);
797 GetMeshDS()->RemoveElement( tr2 );
799 //MESSAGE( endl << tr1 );
804 // check case of quadratic faces
805 const SMDS_QuadraticFaceOfNodes* QF1 =
806 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
807 if(!QF1) return false;
808 const SMDS_QuadraticFaceOfNodes* QF2 =
809 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
810 if(!QF2) return false;
813 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
814 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
822 const SMDS_MeshNode* N1 [6];
823 const SMDS_MeshNode* N2 [6];
824 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
826 // now we receive following N1 and N2 (using numeration as above image)
827 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
828 // i.e. first nodes from both arrays determ new diagonal
830 const SMDS_MeshNode* aNodes[8];
840 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
841 myLastCreatedElems.Append(tr1);
842 GetMeshDS()->RemoveElement( tr2 );
844 // remove middle node (9)
845 GetMeshDS()->RemoveNode( N1[4] );
850 //=======================================================================
851 //function : Reorient
852 //purpose : Reverse theElement orientation
853 //=======================================================================
855 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
857 myLastCreatedElems.Clear();
858 myLastCreatedNodes.Clear();
862 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
863 if ( !it || !it->more() )
866 switch ( theElem->GetType() ) {
870 if(!theElem->IsQuadratic()) {
871 int i = theElem->NbNodes();
872 vector<const SMDS_MeshNode*> aNodes( i );
874 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
875 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
878 // quadratic elements
879 if(theElem->GetType()==SMDSAbs_Edge) {
880 vector<const SMDS_MeshNode*> aNodes(3);
881 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
882 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
883 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
884 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
887 int nbn = theElem->NbNodes();
888 vector<const SMDS_MeshNode*> aNodes(nbn);
889 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
891 for(; i<nbn/2; i++) {
892 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
894 for(i=0; i<nbn/2; i++) {
895 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
897 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
901 case SMDSAbs_Volume: {
902 if (theElem->IsPoly()) {
903 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
904 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
906 MESSAGE("Warning: bad volumic element");
910 int nbFaces = aPolyedre->NbFaces();
911 vector<const SMDS_MeshNode *> poly_nodes;
912 vector<int> quantities (nbFaces);
914 // reverse each face of the polyedre
915 for (int iface = 1; iface <= nbFaces; iface++) {
916 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
917 quantities[iface - 1] = nbFaceNodes;
919 for (inode = nbFaceNodes; inode >= 1; inode--) {
920 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
921 poly_nodes.push_back(curNode);
925 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
929 SMDS_VolumeTool vTool;
930 if ( !vTool.Set( theElem ))
933 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
942 //=======================================================================
943 //function : getBadRate
945 //=======================================================================
947 static double getBadRate (const SMDS_MeshElement* theElem,
948 SMESH::Controls::NumericalFunctorPtr& theCrit)
950 SMESH::Controls::TSequenceOfXYZ P;
951 if ( !theElem || !theCrit->GetPoints( theElem, P ))
953 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
954 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
957 //=======================================================================
958 //function : QuadToTri
959 //purpose : Cut quadrangles into triangles.
960 // theCrit is used to select a diagonal to cut
961 //=======================================================================
963 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
964 SMESH::Controls::NumericalFunctorPtr theCrit)
966 myLastCreatedElems.Clear();
967 myLastCreatedNodes.Clear();
969 MESSAGE( "::QuadToTri()" );
971 if ( !theCrit.get() )
974 SMESHDS_Mesh * aMesh = GetMeshDS();
976 Handle(Geom_Surface) surface;
977 SMESH_MesherHelper helper( *GetMesh() );
979 TIDSortedElemSet::iterator itElem;
980 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
981 const SMDS_MeshElement* elem = *itElem;
982 if ( !elem || elem->GetType() != SMDSAbs_Face )
984 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
987 // retrieve element nodes
988 const SMDS_MeshNode* aNodes [8];
989 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
991 while ( itN->more() )
992 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
994 // compare two sets of possible triangles
995 double aBadRate1, aBadRate2; // to what extent a set is bad
996 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
997 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
998 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1000 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1001 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1002 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1004 int aShapeId = FindShape( elem );
1005 const SMDS_MeshElement* newElem = 0;
1007 if( !elem->IsQuadratic() ) {
1009 // split liner quadrangle
1011 if ( aBadRate1 <= aBadRate2 ) {
1012 // tr1 + tr2 is better
1013 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1014 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1017 // tr3 + tr4 is better
1018 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1019 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1024 // split quadratic quadrangle
1026 // get surface elem is on
1027 if ( aShapeId != helper.GetSubShapeID() ) {
1031 shape = aMesh->IndexToShape( aShapeId );
1032 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1033 TopoDS_Face face = TopoDS::Face( shape );
1034 surface = BRep_Tool::Surface( face );
1035 if ( !surface.IsNull() )
1036 helper.SetSubShape( shape );
1040 const SMDS_MeshNode* aNodes [8];
1041 const SMDS_MeshNode* inFaceNode = 0;
1042 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1044 while ( itN->more() ) {
1045 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1046 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1047 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1049 inFaceNode = aNodes[ i-1 ];
1052 // find middle point for (0,1,2,3)
1053 // and create a node in this point;
1055 if ( surface.IsNull() ) {
1057 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1061 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1064 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1066 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1068 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1069 myLastCreatedNodes.Append(newN);
1071 // create a new element
1072 const SMDS_MeshNode* N[6];
1073 if ( aBadRate1 <= aBadRate2 ) {
1080 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1081 aNodes[6], aNodes[7], newN );
1090 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1091 aNodes[7], aNodes[4], newN );
1093 aMesh->ChangeElementNodes( elem, N, 6 );
1097 // care of a new element
1099 myLastCreatedElems.Append(newElem);
1100 AddToSameGroups( newElem, elem, aMesh );
1102 // put a new triangle on the same shape
1104 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1109 //=======================================================================
1110 //function : BestSplit
1111 //purpose : Find better diagonal for cutting.
1112 //=======================================================================
1114 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1115 SMESH::Controls::NumericalFunctorPtr theCrit)
1117 myLastCreatedElems.Clear();
1118 myLastCreatedNodes.Clear();
1123 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1126 if( theQuad->NbNodes()==4 ||
1127 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1129 // retrieve element nodes
1130 const SMDS_MeshNode* aNodes [4];
1131 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1133 //while (itN->more())
1135 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1137 // compare two sets of possible triangles
1138 double aBadRate1, aBadRate2; // to what extent a set is bad
1139 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1140 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1141 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1143 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1144 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1145 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1147 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1148 return 1; // diagonal 1-3
1150 return 2; // diagonal 2-4
1157 // Methods of splitting volumes into tetra
1159 const int theHexTo5[5*4] =
1167 const int theHexTo6[6*4] =
1175 const int thePyraTo2[2*4] =
1181 const int thePentaTo8[8*4] =
1196 const int* _connectivity;
1197 bool _addNode; // additional node is to be created
1198 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1199 : _nbTetra(nbTet), _connectivity(conn), _addNode(addNode) {}
1203 * \brief return TSplitMethod for the given element
1205 TSplitMethod getSplitMethod( const SMDS_MeshElement* vol, const int theMethodFlags)
1207 TSplitMethod method;
1208 if ( vol->GetType() == SMDSAbs_Volume && !vol->IsPoly())
1209 switch ( vol->NbNodes() )
1213 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1214 method = TSplitMethod( 5, theHexTo5 );
1216 method = TSplitMethod( 6, theHexTo6 );
1220 method = TSplitMethod( 2, thePyraTo2 );
1224 method = TSplitMethod( 8, thePentaTo8, /*addNode=*/true );
1232 //=======================================================================
1233 //function : SplitVolumesIntoTetra
1234 //purpose : Split volumic elements into tetrahedra.
1235 //=======================================================================
1237 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1238 const int theMethodFlags)
1240 // sdt-like iterator on coordinates of nodes of mesh element
1241 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1242 NXyzIterator xyzEnd;
1244 SMESH_MesherHelper helper( *GetMesh());
1246 TIDSortedElemSet::const_iterator elem = theElems.begin();
1247 for ( ; elem != theElems.end(); ++elem )
1249 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1250 if ( geomType <= SMDSEntity_Quad_Tetra )
1251 continue; // tetra or face or edge
1253 if ( (*elem)->IsQuadratic() )
1255 // add quadratic links to the helper
1256 SMDS_VolumeTool vol( *elem );
1257 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1259 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1260 for ( int iN = 0; iN < vol.NbFaceNodes( iF ); iN += 2)
1261 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1263 helper.SetIsQuadratic( true );
1267 helper.SetIsQuadratic( false );
1270 vector<const SMDS_MeshElement* > tetras; // splits of a volume
1272 if ( geomType == SMDSEntity_Polyhedra )
1274 // Each face of a polyhedron is split into triangles and
1275 // each of triangles and a cell barycenter form a tetrahedron.
1277 SMDS_VolumeTool vol( *elem );
1279 // make a node at barycenter
1280 gp_XYZ gc = std::accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd,gp_XYZ(0,0,0));
1281 gc /= vol.NbNodes();
1282 SMDS_MeshNode* gcNode = GetMeshDS()->AddNode( gc.X(), gc.Y(), gc.Z() );
1284 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1286 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1287 int nbFNodes = vol.NbFaceNodes( iF );
1288 int nbTria = nbFNodes - 2;
1289 bool extFace = vol.IsFaceExternal( iF );
1290 SMDS_MeshElement* tet;
1291 for ( int i = 0; i < nbTria; ++i )
1294 tet = helper.AddVolume( fNodes[0], fNodes[i+1], fNodes[i+2], gcNode );
1296 tet = helper.AddVolume( fNodes[0], fNodes[i+2], fNodes[i+1], gcNode );
1297 tetras.push_back( tet );
1305 TSplitMethod splitMethod = getSplitMethod( *elem, theMethodFlags );
1306 if ( splitMethod._nbTetra < 1 ) continue;
1308 vector<const SMDS_MeshNode*> volNodes( (*elem)->begin_nodes(), (*elem)->end_nodes());
1313 //=======================================================================
1314 //function : AddToSameGroups
1315 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1316 //=======================================================================
1318 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1319 const SMDS_MeshElement* elemInGroups,
1320 SMESHDS_Mesh * aMesh)
1322 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1323 if (!groups.empty()) {
1324 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1325 for ( ; grIt != groups.end(); grIt++ ) {
1326 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1327 if ( group && group->Contains( elemInGroups ))
1328 group->SMDSGroup().Add( elemToAdd );
1334 //=======================================================================
1335 //function : RemoveElemFromGroups
1336 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1337 //=======================================================================
1338 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1339 SMESHDS_Mesh * aMesh)
1341 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1342 if (!groups.empty())
1344 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1345 for (; GrIt != groups.end(); GrIt++)
1347 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1348 if (!grp || grp->IsEmpty()) continue;
1349 grp->SMDSGroup().Remove(removeelem);
1354 //=======================================================================
1355 //function : ReplaceElemInGroups
1356 //purpose : replace elemToRm by elemToAdd in the all groups
1357 //=======================================================================
1359 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1360 const SMDS_MeshElement* elemToAdd,
1361 SMESHDS_Mesh * aMesh)
1363 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1364 if (!groups.empty()) {
1365 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1366 for ( ; grIt != groups.end(); grIt++ ) {
1367 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1368 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1369 group->SMDSGroup().Add( elemToAdd );
1374 //=======================================================================
1375 //function : QuadToTri
1376 //purpose : Cut quadrangles into triangles.
1377 // theCrit is used to select a diagonal to cut
1378 //=======================================================================
1380 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1381 const bool the13Diag)
1383 myLastCreatedElems.Clear();
1384 myLastCreatedNodes.Clear();
1386 MESSAGE( "::QuadToTri()" );
1388 SMESHDS_Mesh * aMesh = GetMeshDS();
1390 Handle(Geom_Surface) surface;
1391 SMESH_MesherHelper helper( *GetMesh() );
1393 TIDSortedElemSet::iterator itElem;
1394 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1395 const SMDS_MeshElement* elem = *itElem;
1396 if ( !elem || elem->GetType() != SMDSAbs_Face )
1398 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1399 if(!isquad) continue;
1401 if(elem->NbNodes()==4) {
1402 // retrieve element nodes
1403 const SMDS_MeshNode* aNodes [4];
1404 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1406 while ( itN->more() )
1407 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1409 int aShapeId = FindShape( elem );
1410 const SMDS_MeshElement* newElem = 0;
1412 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1413 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1416 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1417 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1419 myLastCreatedElems.Append(newElem);
1420 // put a new triangle on the same shape and add to the same groups
1422 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1423 AddToSameGroups( newElem, elem, aMesh );
1426 // Quadratic quadrangle
1428 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1430 // get surface elem is on
1431 int aShapeId = FindShape( elem );
1432 if ( aShapeId != helper.GetSubShapeID() ) {
1436 shape = aMesh->IndexToShape( aShapeId );
1437 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1438 TopoDS_Face face = TopoDS::Face( shape );
1439 surface = BRep_Tool::Surface( face );
1440 if ( !surface.IsNull() )
1441 helper.SetSubShape( shape );
1445 const SMDS_MeshNode* aNodes [8];
1446 const SMDS_MeshNode* inFaceNode = 0;
1447 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1449 while ( itN->more() ) {
1450 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1451 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1452 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1454 inFaceNode = aNodes[ i-1 ];
1458 // find middle point for (0,1,2,3)
1459 // and create a node in this point;
1461 if ( surface.IsNull() ) {
1463 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1467 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1470 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1472 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1474 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1475 myLastCreatedNodes.Append(newN);
1477 // create a new element
1478 const SMDS_MeshElement* newElem = 0;
1479 const SMDS_MeshNode* N[6];
1487 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1488 aNodes[6], aNodes[7], newN );
1497 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1498 aNodes[7], aNodes[4], newN );
1500 myLastCreatedElems.Append(newElem);
1501 aMesh->ChangeElementNodes( elem, N, 6 );
1502 // put a new triangle on the same shape and add to the same groups
1504 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1505 AddToSameGroups( newElem, elem, aMesh );
1512 //=======================================================================
1513 //function : getAngle
1515 //=======================================================================
1517 double getAngle(const SMDS_MeshElement * tr1,
1518 const SMDS_MeshElement * tr2,
1519 const SMDS_MeshNode * n1,
1520 const SMDS_MeshNode * n2)
1522 double angle = 2*PI; // bad angle
1525 SMESH::Controls::TSequenceOfXYZ P1, P2;
1526 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1527 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1530 if(!tr1->IsQuadratic())
1531 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1533 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1534 if ( N1.SquareMagnitude() <= gp::Resolution() )
1536 if(!tr2->IsQuadratic())
1537 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1539 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1540 if ( N2.SquareMagnitude() <= gp::Resolution() )
1543 // find the first diagonal node n1 in the triangles:
1544 // take in account a diagonal link orientation
1545 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1546 for ( int t = 0; t < 2; t++ ) {
1547 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1548 int i = 0, iDiag = -1;
1549 while ( it->more()) {
1550 const SMDS_MeshElement *n = it->next();
1551 if ( n == n1 || n == n2 )
1555 if ( i - iDiag == 1 )
1556 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1564 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1567 angle = N1.Angle( N2 );
1572 // =================================================
1573 // class generating a unique ID for a pair of nodes
1574 // and able to return nodes by that ID
1575 // =================================================
1579 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1580 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1583 long GetLinkID (const SMDS_MeshNode * n1,
1584 const SMDS_MeshNode * n2) const
1586 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1589 bool GetNodes (const long theLinkID,
1590 const SMDS_MeshNode* & theNode1,
1591 const SMDS_MeshNode* & theNode2) const
1593 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1594 if ( !theNode1 ) return false;
1595 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1596 if ( !theNode2 ) return false;
1602 const SMESHDS_Mesh* myMesh;
1607 //=======================================================================
1608 //function : TriToQuad
1609 //purpose : Fuse neighbour triangles into quadrangles.
1610 // theCrit is used to select a neighbour to fuse with.
1611 // theMaxAngle is a max angle between element normals at which
1612 // fusion is still performed.
1613 //=======================================================================
1615 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1616 SMESH::Controls::NumericalFunctorPtr theCrit,
1617 const double theMaxAngle)
1619 myLastCreatedElems.Clear();
1620 myLastCreatedNodes.Clear();
1622 MESSAGE( "::TriToQuad()" );
1624 if ( !theCrit.get() )
1627 SMESHDS_Mesh * aMesh = GetMeshDS();
1629 // Prepare data for algo: build
1630 // 1. map of elements with their linkIDs
1631 // 2. map of linkIDs with their elements
1633 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1634 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1635 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1636 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1638 TIDSortedElemSet::iterator itElem;
1639 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1640 const SMDS_MeshElement* elem = *itElem;
1641 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1642 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1643 if(!IsTria) continue;
1645 // retrieve element nodes
1646 const SMDS_MeshNode* aNodes [4];
1647 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1650 aNodes[ i++ ] = cast2Node( itN->next() );
1651 aNodes[ 3 ] = aNodes[ 0 ];
1654 for ( i = 0; i < 3; i++ ) {
1655 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1656 // check if elements sharing a link can be fused
1657 itLE = mapLi_listEl.find( link );
1658 if ( itLE != mapLi_listEl.end() ) {
1659 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1661 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1662 //if ( FindShape( elem ) != FindShape( elem2 ))
1663 // continue; // do not fuse triangles laying on different shapes
1664 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1665 continue; // avoid making badly shaped quads
1666 (*itLE).second.push_back( elem );
1669 mapLi_listEl[ link ].push_back( elem );
1671 mapEl_setLi [ elem ].insert( link );
1674 // Clean the maps from the links shared by a sole element, ie
1675 // links to which only one element is bound in mapLi_listEl
1677 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1678 int nbElems = (*itLE).second.size();
1679 if ( nbElems < 2 ) {
1680 const SMDS_MeshElement* elem = (*itLE).second.front();
1681 SMESH_TLink link = (*itLE).first;
1682 mapEl_setLi[ elem ].erase( link );
1683 if ( mapEl_setLi[ elem ].empty() )
1684 mapEl_setLi.erase( elem );
1688 // Algo: fuse triangles into quadrangles
1690 while ( ! mapEl_setLi.empty() ) {
1691 // Look for the start element:
1692 // the element having the least nb of shared links
1693 const SMDS_MeshElement* startElem = 0;
1695 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1696 int nbLinks = (*itEL).second.size();
1697 if ( nbLinks < minNbLinks ) {
1698 startElem = (*itEL).first;
1699 minNbLinks = nbLinks;
1700 if ( minNbLinks == 1 )
1705 // search elements to fuse starting from startElem or links of elements
1706 // fused earlyer - startLinks
1707 list< SMESH_TLink > startLinks;
1708 while ( startElem || !startLinks.empty() ) {
1709 while ( !startElem && !startLinks.empty() ) {
1710 // Get an element to start, by a link
1711 SMESH_TLink linkId = startLinks.front();
1712 startLinks.pop_front();
1713 itLE = mapLi_listEl.find( linkId );
1714 if ( itLE != mapLi_listEl.end() ) {
1715 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1716 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1717 for ( ; itE != listElem.end() ; itE++ )
1718 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1720 mapLi_listEl.erase( itLE );
1725 // Get candidates to be fused
1726 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1727 const SMESH_TLink *link12, *link13;
1729 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1730 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1731 ASSERT( !setLi.empty() );
1732 set< SMESH_TLink >::iterator itLi;
1733 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1735 const SMESH_TLink & link = (*itLi);
1736 itLE = mapLi_listEl.find( link );
1737 if ( itLE == mapLi_listEl.end() )
1740 const SMDS_MeshElement* elem = (*itLE).second.front();
1742 elem = (*itLE).second.back();
1743 mapLi_listEl.erase( itLE );
1744 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1755 // add other links of elem to list of links to re-start from
1756 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1757 set< SMESH_TLink >::iterator it;
1758 for ( it = links.begin(); it != links.end(); it++ ) {
1759 const SMESH_TLink& link2 = (*it);
1760 if ( link2 != link )
1761 startLinks.push_back( link2 );
1765 // Get nodes of possible quadrangles
1766 const SMDS_MeshNode *n12 [4], *n13 [4];
1767 bool Ok12 = false, Ok13 = false;
1768 const SMDS_MeshNode *linkNode1, *linkNode2;
1770 linkNode1 = link12->first;
1771 linkNode2 = link12->second;
1772 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1776 linkNode1 = link13->first;
1777 linkNode2 = link13->second;
1778 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1782 // Choose a pair to fuse
1783 if ( Ok12 && Ok13 ) {
1784 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1785 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1786 double aBadRate12 = getBadRate( &quad12, theCrit );
1787 double aBadRate13 = getBadRate( &quad13, theCrit );
1788 if ( aBadRate13 < aBadRate12 )
1795 // and remove fused elems and removed links from the maps
1796 mapEl_setLi.erase( tr1 );
1798 mapEl_setLi.erase( tr2 );
1799 mapLi_listEl.erase( *link12 );
1800 if(tr1->NbNodes()==3) {
1801 if( tr1->GetID() < tr2->GetID() ) {
1802 aMesh->ChangeElementNodes( tr1, n12, 4 );
1803 myLastCreatedElems.Append(tr1);
1804 aMesh->RemoveElement( tr2 );
1807 aMesh->ChangeElementNodes( tr2, n12, 4 );
1808 myLastCreatedElems.Append(tr2);
1809 aMesh->RemoveElement( tr1);
1813 const SMDS_MeshNode* N1 [6];
1814 const SMDS_MeshNode* N2 [6];
1815 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1816 // now we receive following N1 and N2 (using numeration as above image)
1817 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1818 // i.e. first nodes from both arrays determ new diagonal
1819 const SMDS_MeshNode* aNodes[8];
1828 if( tr1->GetID() < tr2->GetID() ) {
1829 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1830 myLastCreatedElems.Append(tr1);
1831 GetMeshDS()->RemoveElement( tr2 );
1834 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1835 myLastCreatedElems.Append(tr2);
1836 GetMeshDS()->RemoveElement( tr1 );
1838 // remove middle node (9)
1839 GetMeshDS()->RemoveNode( N1[4] );
1843 mapEl_setLi.erase( tr3 );
1844 mapLi_listEl.erase( *link13 );
1845 if(tr1->NbNodes()==3) {
1846 if( tr1->GetID() < tr2->GetID() ) {
1847 aMesh->ChangeElementNodes( tr1, n13, 4 );
1848 myLastCreatedElems.Append(tr1);
1849 aMesh->RemoveElement( tr3 );
1852 aMesh->ChangeElementNodes( tr3, n13, 4 );
1853 myLastCreatedElems.Append(tr3);
1854 aMesh->RemoveElement( tr1 );
1858 const SMDS_MeshNode* N1 [6];
1859 const SMDS_MeshNode* N2 [6];
1860 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1861 // now we receive following N1 and N2 (using numeration as above image)
1862 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1863 // i.e. first nodes from both arrays determ new diagonal
1864 const SMDS_MeshNode* aNodes[8];
1873 if( tr1->GetID() < tr2->GetID() ) {
1874 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1875 myLastCreatedElems.Append(tr1);
1876 GetMeshDS()->RemoveElement( tr3 );
1879 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1880 myLastCreatedElems.Append(tr3);
1881 GetMeshDS()->RemoveElement( tr1 );
1883 // remove middle node (9)
1884 GetMeshDS()->RemoveNode( N1[4] );
1888 // Next element to fuse: the rejected one
1890 startElem = Ok12 ? tr3 : tr2;
1892 } // if ( startElem )
1893 } // while ( startElem || !startLinks.empty() )
1894 } // while ( ! mapEl_setLi.empty() )
1900 /*#define DUMPSO(txt) \
1901 // cout << txt << endl;
1902 //=============================================================================
1906 //=============================================================================
1907 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1911 int tmp = idNodes[ i1 ];
1912 idNodes[ i1 ] = idNodes[ i2 ];
1913 idNodes[ i2 ] = tmp;
1914 gp_Pnt Ptmp = P[ i1 ];
1917 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1920 //=======================================================================
1921 //function : SortQuadNodes
1922 //purpose : Set 4 nodes of a quadrangle face in a good order.
1923 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1925 //=======================================================================
1927 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1932 for ( i = 0; i < 4; i++ ) {
1933 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1935 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1938 gp_Vec V1(P[0], P[1]);
1939 gp_Vec V2(P[0], P[2]);
1940 gp_Vec V3(P[0], P[3]);
1942 gp_Vec Cross1 = V1 ^ V2;
1943 gp_Vec Cross2 = V2 ^ V3;
1946 if (Cross1.Dot(Cross2) < 0)
1951 if (Cross1.Dot(Cross2) < 0)
1955 swap ( i, i + 1, idNodes, P );
1957 // for ( int ii = 0; ii < 4; ii++ ) {
1958 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1959 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1965 //=======================================================================
1966 //function : SortHexaNodes
1967 //purpose : Set 8 nodes of a hexahedron in a good order.
1968 // Return success status
1969 //=======================================================================
1971 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1976 DUMPSO( "INPUT: ========================================");
1977 for ( i = 0; i < 8; i++ ) {
1978 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1979 if ( !n ) return false;
1980 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1981 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1983 DUMPSO( "========================================");
1986 set<int> faceNodes; // ids of bottom face nodes, to be found
1987 set<int> checkedId1; // ids of tried 2-nd nodes
1988 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1989 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1990 int iMin, iLoop1 = 0;
1992 // Loop to try the 2-nd nodes
1994 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
1996 // Find not checked 2-nd node
1997 for ( i = 1; i < 8; i++ )
1998 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
1999 int id1 = idNodes[i];
2000 swap ( 1, i, idNodes, P );
2001 checkedId1.insert ( id1 );
2005 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2006 // ie that all but meybe one (id3 which is on the same face) nodes
2007 // lay on the same side from the triangle plane.
2009 bool manyInPlane = false; // more than 4 nodes lay in plane
2011 while ( ++iLoop2 < 6 ) {
2013 // get 1-2-3 plane coeffs
2014 Standard_Real A, B, C, D;
2015 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2016 if ( N.SquareMagnitude() > gp::Resolution() )
2018 gp_Pln pln ( P[0], N );
2019 pln.Coefficients( A, B, C, D );
2021 // find the node (iMin) closest to pln
2022 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2024 for ( i = 3; i < 8; i++ ) {
2025 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2026 if ( fabs( dist[i] ) < minDist ) {
2027 minDist = fabs( dist[i] );
2030 if ( fabs( dist[i] ) <= tol )
2031 idInPln.insert( idNodes[i] );
2034 // there should not be more than 4 nodes in bottom plane
2035 if ( idInPln.size() > 1 )
2037 DUMPSO( "### idInPln.size() = " << idInPln.size());
2038 // idInPlane does not contain the first 3 nodes
2039 if ( manyInPlane || idInPln.size() == 5)
2040 return false; // all nodes in one plane
2043 // set the 1-st node to be not in plane
2044 for ( i = 3; i < 8; i++ ) {
2045 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2046 DUMPSO( "### Reset 0-th node");
2047 swap( 0, i, idNodes, P );
2052 // reset to re-check second nodes
2053 leastDist = DBL_MAX;
2057 break; // from iLoop2;
2060 // check that the other 4 nodes are on the same side
2061 bool sameSide = true;
2062 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2063 for ( i = 3; sameSide && i < 8; i++ ) {
2065 sameSide = ( isNeg == dist[i] <= 0.);
2068 // keep best solution
2069 if ( sameSide && minDist < leastDist ) {
2070 leastDist = minDist;
2072 faceNodes.insert( idNodes[ 1 ] );
2073 faceNodes.insert( idNodes[ 2 ] );
2074 faceNodes.insert( idNodes[ iMin ] );
2075 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2076 << " leastDist = " << leastDist);
2077 if ( leastDist <= DBL_MIN )
2082 // set next 3-d node to check
2083 int iNext = 2 + iLoop2;
2085 DUMPSO( "Try 2-nd");
2086 swap ( 2, iNext, idNodes, P );
2088 } // while ( iLoop2 < 6 )
2091 if ( faceNodes.empty() ) return false;
2093 // Put the faceNodes in proper places
2094 for ( i = 4; i < 8; i++ ) {
2095 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2096 // find a place to put
2098 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2100 DUMPSO( "Set faceNodes");
2101 swap ( iTo, i, idNodes, P );
2106 // Set nodes of the found bottom face in good order
2107 DUMPSO( " Found bottom face: ");
2108 i = SortQuadNodes( theMesh, idNodes );
2110 gp_Pnt Ptmp = P[ i ];
2115 // for ( int ii = 0; ii < 4; ii++ ) {
2116 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2117 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2120 // Gravity center of the top and bottom faces
2121 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2122 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2124 // Get direction from the bottom to the top face
2125 gp_Vec upDir ( aGCb, aGCt );
2126 Standard_Real upDirSize = upDir.Magnitude();
2127 if ( upDirSize <= gp::Resolution() ) return false;
2130 // Assure that the bottom face normal points up
2131 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2132 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2133 if ( Nb.Dot( upDir ) < 0 ) {
2134 DUMPSO( "Reverse bottom face");
2135 swap( 1, 3, idNodes, P );
2138 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2139 Standard_Real minDist = DBL_MAX;
2140 for ( i = 4; i < 8; i++ ) {
2141 // projection of P[i] to the plane defined by P[0] and upDir
2142 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2143 Standard_Real sqDist = P[0].SquareDistance( Pp );
2144 if ( sqDist < minDist ) {
2149 DUMPSO( "Set 4-th");
2150 swap ( 4, iMin, idNodes, P );
2152 // Set nodes of the top face in good order
2153 DUMPSO( "Sort top face");
2154 i = SortQuadNodes( theMesh, &idNodes[4] );
2157 gp_Pnt Ptmp = P[ i ];
2162 // Assure that direction of the top face normal is from the bottom face
2163 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2164 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2165 if ( Nt.Dot( upDir ) < 0 ) {
2166 DUMPSO( "Reverse top face");
2167 swap( 5, 7, idNodes, P );
2170 // DUMPSO( "OUTPUT: ========================================");
2171 // for ( i = 0; i < 8; i++ ) {
2172 // float *p = ugrid->GetPoint(idNodes[i]);
2173 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2179 //================================================================================
2181 * \brief Return nodes linked to the given one
2182 * \param theNode - the node
2183 * \param linkedNodes - the found nodes
2184 * \param type - the type of elements to check
2186 * Medium nodes are ignored
2188 //================================================================================
2190 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2191 TIDSortedElemSet & linkedNodes,
2192 SMDSAbs_ElementType type )
2194 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2195 while ( elemIt->more() )
2197 const SMDS_MeshElement* elem = elemIt->next();
2198 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2199 if ( elem->GetType() == SMDSAbs_Volume )
2201 SMDS_VolumeTool vol( elem );
2202 while ( nodeIt->more() ) {
2203 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2204 if ( theNode != n && vol.IsLinked( theNode, n ))
2205 linkedNodes.insert( n );
2210 for ( int i = 0; nodeIt->more(); ++i ) {
2211 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2212 if ( n == theNode ) {
2213 int iBefore = i - 1;
2215 if ( elem->IsQuadratic() ) {
2216 int nb = elem->NbNodes() / 2;
2217 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2218 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2220 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2221 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2228 //=======================================================================
2229 //function : laplacianSmooth
2230 //purpose : pulls theNode toward the center of surrounding nodes directly
2231 // connected to that node along an element edge
2232 //=======================================================================
2234 void laplacianSmooth(const SMDS_MeshNode* theNode,
2235 const Handle(Geom_Surface)& theSurface,
2236 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2238 // find surrounding nodes
2240 TIDSortedElemSet nodeSet;
2241 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2243 // compute new coodrs
2245 double coord[] = { 0., 0., 0. };
2246 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2247 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2248 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2249 if ( theSurface.IsNull() ) { // smooth in 3D
2250 coord[0] += node->X();
2251 coord[1] += node->Y();
2252 coord[2] += node->Z();
2254 else { // smooth in 2D
2255 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2256 gp_XY* uv = theUVMap[ node ];
2257 coord[0] += uv->X();
2258 coord[1] += uv->Y();
2261 int nbNodes = nodeSet.size();
2264 coord[0] /= nbNodes;
2265 coord[1] /= nbNodes;
2267 if ( !theSurface.IsNull() ) {
2268 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2269 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2270 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2276 coord[2] /= nbNodes;
2280 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2283 //=======================================================================
2284 //function : centroidalSmooth
2285 //purpose : pulls theNode toward the element-area-weighted centroid of the
2286 // surrounding elements
2287 //=======================================================================
2289 void centroidalSmooth(const SMDS_MeshNode* theNode,
2290 const Handle(Geom_Surface)& theSurface,
2291 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2293 gp_XYZ aNewXYZ(0.,0.,0.);
2294 SMESH::Controls::Area anAreaFunc;
2295 double totalArea = 0.;
2300 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2301 while ( elemIt->more() )
2303 const SMDS_MeshElement* elem = elemIt->next();
2306 gp_XYZ elemCenter(0.,0.,0.);
2307 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2308 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2309 int nn = elem->NbNodes();
2310 if(elem->IsQuadratic()) nn = nn/2;
2312 //while ( itN->more() ) {
2314 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2316 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2317 aNodePoints.push_back( aP );
2318 if ( !theSurface.IsNull() ) { // smooth in 2D
2319 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2320 gp_XY* uv = theUVMap[ aNode ];
2321 aP.SetCoord( uv->X(), uv->Y(), 0. );
2325 double elemArea = anAreaFunc.GetValue( aNodePoints );
2326 totalArea += elemArea;
2328 aNewXYZ += elemCenter * elemArea;
2330 aNewXYZ /= totalArea;
2331 if ( !theSurface.IsNull() ) {
2332 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2333 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2338 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2341 //=======================================================================
2342 //function : getClosestUV
2343 //purpose : return UV of closest projection
2344 //=======================================================================
2346 static bool getClosestUV (Extrema_GenExtPS& projector,
2347 const gp_Pnt& point,
2350 projector.Perform( point );
2351 if ( projector.IsDone() ) {
2352 double u, v, minVal = DBL_MAX;
2353 for ( int i = projector.NbExt(); i > 0; i-- )
2354 if ( projector.Value( i ) < minVal ) {
2355 minVal = projector.Value( i );
2356 projector.Point( i ).Parameter( u, v );
2358 result.SetCoord( u, v );
2364 //=======================================================================
2366 //purpose : Smooth theElements during theNbIterations or until a worst
2367 // element has aspect ratio <= theTgtAspectRatio.
2368 // Aspect Ratio varies in range [1.0, inf].
2369 // If theElements is empty, the whole mesh is smoothed.
2370 // theFixedNodes contains additionally fixed nodes. Nodes built
2371 // on edges and boundary nodes are always fixed.
2372 //=======================================================================
2374 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2375 set<const SMDS_MeshNode*> & theFixedNodes,
2376 const SmoothMethod theSmoothMethod,
2377 const int theNbIterations,
2378 double theTgtAspectRatio,
2381 myLastCreatedElems.Clear();
2382 myLastCreatedNodes.Clear();
2384 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2386 if ( theTgtAspectRatio < 1.0 )
2387 theTgtAspectRatio = 1.0;
2389 const double disttol = 1.e-16;
2391 SMESH::Controls::AspectRatio aQualityFunc;
2393 SMESHDS_Mesh* aMesh = GetMeshDS();
2395 if ( theElems.empty() ) {
2396 // add all faces to theElems
2397 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2398 while ( fIt->more() ) {
2399 const SMDS_MeshElement* face = fIt->next();
2400 theElems.insert( face );
2403 // get all face ids theElems are on
2404 set< int > faceIdSet;
2405 TIDSortedElemSet::iterator itElem;
2407 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2408 int fId = FindShape( *itElem );
2409 // check that corresponding submesh exists and a shape is face
2411 faceIdSet.find( fId ) == faceIdSet.end() &&
2412 aMesh->MeshElements( fId )) {
2413 TopoDS_Shape F = aMesh->IndexToShape( fId );
2414 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2415 faceIdSet.insert( fId );
2418 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2420 // ===============================================
2421 // smooth elements on each TopoDS_Face separately
2422 // ===============================================
2424 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2425 for ( ; fId != faceIdSet.rend(); ++fId ) {
2426 // get face surface and submesh
2427 Handle(Geom_Surface) surface;
2428 SMESHDS_SubMesh* faceSubMesh = 0;
2430 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2431 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2432 bool isUPeriodic = false, isVPeriodic = false;
2434 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2435 surface = BRep_Tool::Surface( face );
2436 faceSubMesh = aMesh->MeshElements( *fId );
2437 fToler2 = BRep_Tool::Tolerance( face );
2438 fToler2 *= fToler2 * 10.;
2439 isUPeriodic = surface->IsUPeriodic();
2441 vPeriod = surface->UPeriod();
2442 isVPeriodic = surface->IsVPeriodic();
2444 uPeriod = surface->VPeriod();
2445 surface->Bounds( u1, u2, v1, v2 );
2447 // ---------------------------------------------------------
2448 // for elements on a face, find movable and fixed nodes and
2449 // compute UV for them
2450 // ---------------------------------------------------------
2451 bool checkBoundaryNodes = false;
2452 bool isQuadratic = false;
2453 set<const SMDS_MeshNode*> setMovableNodes;
2454 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2455 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2456 list< const SMDS_MeshElement* > elemsOnFace;
2458 Extrema_GenExtPS projector;
2459 GeomAdaptor_Surface surfAdaptor;
2460 if ( !surface.IsNull() ) {
2461 surfAdaptor.Load( surface );
2462 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2464 int nbElemOnFace = 0;
2465 itElem = theElems.begin();
2466 // loop on not yet smoothed elements: look for elems on a face
2467 while ( itElem != theElems.end() ) {
2468 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2469 break; // all elements found
2471 const SMDS_MeshElement* elem = *itElem;
2472 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2473 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2477 elemsOnFace.push_back( elem );
2478 theElems.erase( itElem++ );
2482 isQuadratic = elem->IsQuadratic();
2484 // get movable nodes of elem
2485 const SMDS_MeshNode* node;
2486 SMDS_TypeOfPosition posType;
2487 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2488 int nn = 0, nbn = elem->NbNodes();
2489 if(elem->IsQuadratic())
2491 while ( nn++ < nbn ) {
2492 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2493 const SMDS_PositionPtr& pos = node->GetPosition();
2494 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2495 if (posType != SMDS_TOP_EDGE &&
2496 posType != SMDS_TOP_VERTEX &&
2497 theFixedNodes.find( node ) == theFixedNodes.end())
2499 // check if all faces around the node are on faceSubMesh
2500 // because a node on edge may be bound to face
2501 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2503 if ( faceSubMesh ) {
2504 while ( eIt->more() && all ) {
2505 const SMDS_MeshElement* e = eIt->next();
2506 all = faceSubMesh->Contains( e );
2510 setMovableNodes.insert( node );
2512 checkBoundaryNodes = true;
2514 if ( posType == SMDS_TOP_3DSPACE )
2515 checkBoundaryNodes = true;
2518 if ( surface.IsNull() )
2521 // get nodes to check UV
2522 list< const SMDS_MeshNode* > uvCheckNodes;
2523 itN = elem->nodesIterator();
2524 nn = 0; nbn = elem->NbNodes();
2525 if(elem->IsQuadratic())
2527 while ( nn++ < nbn ) {
2528 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2529 if ( uvMap.find( node ) == uvMap.end() )
2530 uvCheckNodes.push_back( node );
2531 // add nodes of elems sharing node
2532 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2533 // while ( eIt->more() ) {
2534 // const SMDS_MeshElement* e = eIt->next();
2535 // if ( e != elem ) {
2536 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2537 // while ( nIt->more() ) {
2538 // const SMDS_MeshNode* n =
2539 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2540 // if ( uvMap.find( n ) == uvMap.end() )
2541 // uvCheckNodes.push_back( n );
2547 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2548 for ( ; n != uvCheckNodes.end(); ++n ) {
2551 const SMDS_PositionPtr& pos = node->GetPosition();
2552 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2554 switch ( posType ) {
2555 case SMDS_TOP_FACE: {
2556 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2557 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2560 case SMDS_TOP_EDGE: {
2561 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2562 Handle(Geom2d_Curve) pcurve;
2563 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2564 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2565 if ( !pcurve.IsNull() ) {
2566 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2567 uv = pcurve->Value( u ).XY();
2571 case SMDS_TOP_VERTEX: {
2572 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2573 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2574 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2579 // check existing UV
2580 bool project = true;
2581 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2582 double dist1 = DBL_MAX, dist2 = 0;
2583 if ( posType != SMDS_TOP_3DSPACE ) {
2584 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2585 project = dist1 > fToler2;
2587 if ( project ) { // compute new UV
2589 if ( !getClosestUV( projector, pNode, newUV )) {
2590 MESSAGE("Node Projection Failed " << node);
2594 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2596 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2598 if ( posType != SMDS_TOP_3DSPACE )
2599 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2600 if ( dist2 < dist1 )
2604 // store UV in the map
2605 listUV.push_back( uv );
2606 uvMap.insert( make_pair( node, &listUV.back() ));
2608 } // loop on not yet smoothed elements
2610 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2611 checkBoundaryNodes = true;
2613 // fix nodes on mesh boundary
2615 if ( checkBoundaryNodes ) {
2616 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2617 map< NLink, int >::iterator link_nb;
2618 // put all elements links to linkNbMap
2619 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2620 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2621 const SMDS_MeshElement* elem = (*elemIt);
2622 int nbn = elem->NbNodes();
2623 if(elem->IsQuadratic())
2625 // loop on elem links: insert them in linkNbMap
2626 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2627 for ( int iN = 0; iN < nbn; ++iN ) {
2628 curNode = elem->GetNode( iN );
2630 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2631 else link = make_pair( prevNode , curNode );
2633 link_nb = linkNbMap.find( link );
2634 if ( link_nb == linkNbMap.end() )
2635 linkNbMap.insert( make_pair ( link, 1 ));
2640 // remove nodes that are in links encountered only once from setMovableNodes
2641 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2642 if ( link_nb->second == 1 ) {
2643 setMovableNodes.erase( link_nb->first.first );
2644 setMovableNodes.erase( link_nb->first.second );
2649 // -----------------------------------------------------
2650 // for nodes on seam edge, compute one more UV ( uvMap2 );
2651 // find movable nodes linked to nodes on seam and which
2652 // are to be smoothed using the second UV ( uvMap2 )
2653 // -----------------------------------------------------
2655 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2656 if ( !surface.IsNull() ) {
2657 TopExp_Explorer eExp( face, TopAbs_EDGE );
2658 for ( ; eExp.More(); eExp.Next() ) {
2659 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2660 if ( !BRep_Tool::IsClosed( edge, face ))
2662 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2663 if ( !sm ) continue;
2664 // find out which parameter varies for a node on seam
2667 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2668 if ( pcurve.IsNull() ) continue;
2669 uv1 = pcurve->Value( f );
2671 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2672 if ( pcurve.IsNull() ) continue;
2673 uv2 = pcurve->Value( f );
2674 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2676 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2677 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2679 // get nodes on seam and its vertices
2680 list< const SMDS_MeshNode* > seamNodes;
2681 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2682 while ( nSeamIt->more() ) {
2683 const SMDS_MeshNode* node = nSeamIt->next();
2684 if ( !isQuadratic || !IsMedium( node ))
2685 seamNodes.push_back( node );
2687 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2688 for ( ; vExp.More(); vExp.Next() ) {
2689 sm = aMesh->MeshElements( vExp.Current() );
2691 nSeamIt = sm->GetNodes();
2692 while ( nSeamIt->more() )
2693 seamNodes.push_back( nSeamIt->next() );
2696 // loop on nodes on seam
2697 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2698 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2699 const SMDS_MeshNode* nSeam = *noSeIt;
2700 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2701 if ( n_uv == uvMap.end() )
2704 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2705 // set the second UV
2706 listUV.push_back( *n_uv->second );
2707 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2708 if ( uvMap2.empty() )
2709 uvMap2 = uvMap; // copy the uvMap contents
2710 uvMap2[ nSeam ] = &listUV.back();
2712 // collect movable nodes linked to ones on seam in nodesNearSeam
2713 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2714 while ( eIt->more() ) {
2715 const SMDS_MeshElement* e = eIt->next();
2716 int nbUseMap1 = 0, nbUseMap2 = 0;
2717 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2718 int nn = 0, nbn = e->NbNodes();
2719 if(e->IsQuadratic()) nbn = nbn/2;
2720 while ( nn++ < nbn )
2722 const SMDS_MeshNode* n =
2723 static_cast<const SMDS_MeshNode*>( nIt->next() );
2725 setMovableNodes.find( n ) == setMovableNodes.end() )
2727 // add only nodes being closer to uv2 than to uv1
2728 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2729 0.5 * ( n->Y() + nSeam->Y() ),
2730 0.5 * ( n->Z() + nSeam->Z() ));
2732 getClosestUV( projector, pMid, uv );
2733 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2734 nodesNearSeam.insert( n );
2740 // for centroidalSmooth all element nodes must
2741 // be on one side of a seam
2742 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2743 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2745 while ( nn++ < nbn ) {
2746 const SMDS_MeshNode* n =
2747 static_cast<const SMDS_MeshNode*>( nIt->next() );
2748 setMovableNodes.erase( n );
2752 } // loop on nodes on seam
2753 } // loop on edge of a face
2754 } // if ( !face.IsNull() )
2756 if ( setMovableNodes.empty() ) {
2757 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2758 continue; // goto next face
2766 double maxRatio = -1., maxDisplacement = -1.;
2767 set<const SMDS_MeshNode*>::iterator nodeToMove;
2768 for ( it = 0; it < theNbIterations; it++ ) {
2769 maxDisplacement = 0.;
2770 nodeToMove = setMovableNodes.begin();
2771 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2772 const SMDS_MeshNode* node = (*nodeToMove);
2773 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2776 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2777 if ( theSmoothMethod == LAPLACIAN )
2778 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2780 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2782 // node displacement
2783 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2784 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2785 if ( aDispl > maxDisplacement )
2786 maxDisplacement = aDispl;
2788 // no node movement => exit
2789 //if ( maxDisplacement < 1.e-16 ) {
2790 if ( maxDisplacement < disttol ) {
2791 MESSAGE("-- no node movement --");
2795 // check elements quality
2797 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2798 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2799 const SMDS_MeshElement* elem = (*elemIt);
2800 if ( !elem || elem->GetType() != SMDSAbs_Face )
2802 SMESH::Controls::TSequenceOfXYZ aPoints;
2803 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2804 double aValue = aQualityFunc.GetValue( aPoints );
2805 if ( aValue > maxRatio )
2809 if ( maxRatio <= theTgtAspectRatio ) {
2810 MESSAGE("-- quality achived --");
2813 if (it+1 == theNbIterations) {
2814 MESSAGE("-- Iteration limit exceeded --");
2816 } // smoothing iterations
2818 MESSAGE(" Face id: " << *fId <<
2819 " Nb iterstions: " << it <<
2820 " Displacement: " << maxDisplacement <<
2821 " Aspect Ratio " << maxRatio);
2823 // ---------------------------------------
2824 // new nodes positions are computed,
2825 // record movement in DS and set new UV
2826 // ---------------------------------------
2827 nodeToMove = setMovableNodes.begin();
2828 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2829 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2830 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2831 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2832 if ( node_uv != uvMap.end() ) {
2833 gp_XY* uv = node_uv->second;
2835 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2839 // move medium nodes of quadratic elements
2842 SMESH_MesherHelper helper( *GetMesh() );
2843 if ( !face.IsNull() )
2844 helper.SetSubShape( face );
2845 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2846 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2847 const SMDS_QuadraticFaceOfNodes* QF =
2848 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2850 vector<const SMDS_MeshNode*> Ns;
2851 Ns.reserve(QF->NbNodes()+1);
2852 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2853 while ( anIter->more() )
2854 Ns.push_back( anIter->next() );
2855 Ns.push_back( Ns[0] );
2857 for(int i=0; i<QF->NbNodes(); i=i+2) {
2858 if ( !surface.IsNull() ) {
2859 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2860 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2861 gp_XY uv = ( uv1 + uv2 ) / 2.;
2862 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2863 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2866 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2867 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2868 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2870 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2871 fabs( Ns[i+1]->Y() - y ) > disttol ||
2872 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2873 // we have to move i+1 node
2874 aMesh->MoveNode( Ns[i+1], x, y, z );
2881 } // loop on face ids
2885 //=======================================================================
2886 //function : isReverse
2887 //purpose : Return true if normal of prevNodes is not co-directied with
2888 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2889 // iNotSame is where prevNodes and nextNodes are different
2890 //=======================================================================
2892 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2893 vector<const SMDS_MeshNode*> nextNodes,
2897 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2898 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2900 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2901 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2902 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2903 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2905 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2906 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2907 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2908 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2910 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2912 return (vA ^ vB) * vN < 0.0;
2915 //=======================================================================
2917 * \brief Create elements by sweeping an element
2918 * \param elem - element to sweep
2919 * \param newNodesItVec - nodes generated from each node of the element
2920 * \param newElems - generated elements
2921 * \param nbSteps - number of sweeping steps
2922 * \param srcElements - to append elem for each generated element
2924 //=======================================================================
2926 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2927 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2928 list<const SMDS_MeshElement*>& newElems,
2930 SMESH_SequenceOfElemPtr& srcElements)
2932 SMESHDS_Mesh* aMesh = GetMeshDS();
2934 // Loop on elem nodes:
2935 // find new nodes and detect same nodes indices
2936 int nbNodes = elem->NbNodes();
2937 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2938 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2939 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2940 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2942 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2943 vector<int> sames(nbNodes);
2944 vector<bool> issimple(nbNodes);
2946 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2947 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2948 const SMDS_MeshNode* node = nnIt->first;
2949 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2950 if ( listNewNodes.empty() ) {
2954 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2956 itNN[ iNode ] = listNewNodes.begin();
2957 prevNod[ iNode ] = node;
2958 nextNod[ iNode ] = listNewNodes.front();
2959 if( !elem->IsQuadratic() || !issimple[iNode] ) {
2960 if ( prevNod[ iNode ] != nextNod [ iNode ])
2961 iNotSameNode = iNode;
2965 sames[nbSame++] = iNode;
2970 //cout<<" nbSame = "<<nbSame<<endl;
2971 if ( nbSame == nbNodes || nbSame > 2) {
2972 MESSAGE( " Too many same nodes of element " << elem->GetID() );
2973 //INFOS( " Too many same nodes of element " << elem->GetID() );
2977 // if( elem->IsQuadratic() && nbSame>0 ) {
2978 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2982 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2983 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2985 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2986 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2987 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2991 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2992 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2993 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2994 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
2996 // check element orientation
2998 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
2999 //MESSAGE("Reversed elem " << elem );
3003 std::swap( iBeforeSame, iAfterSame );
3006 // make new elements
3007 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3009 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3010 if(issimple[iNode]) {
3011 nextNod[ iNode ] = *itNN[ iNode ];
3015 if( elem->GetType()==SMDSAbs_Node ) {
3016 // we have to use two nodes
3017 midlNod[ iNode ] = *itNN[ iNode ];
3019 nextNod[ iNode ] = *itNN[ iNode ];
3022 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3023 // we have to use each second node
3025 nextNod[ iNode ] = *itNN[ iNode ];
3029 // we have to use two nodes
3030 midlNod[ iNode ] = *itNN[ iNode ];
3032 nextNod[ iNode ] = *itNN[ iNode ];
3037 SMDS_MeshElement* aNewElem = 0;
3038 if(!elem->IsPoly()) {
3039 switch ( nbNodes ) {
3043 if ( nbSame == 0 ) {
3045 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3047 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3053 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3054 nextNod[ 1 ], nextNod[ 0 ] );
3056 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3057 nextNod[ iNotSameNode ] );
3061 case 3: { // TRIANGLE or quadratic edge
3062 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3064 if ( nbSame == 0 ) // --- pentahedron
3065 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3066 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3068 else if ( nbSame == 1 ) // --- pyramid
3069 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3070 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3071 nextNod[ iSameNode ]);
3073 else // 2 same nodes: --- tetrahedron
3074 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3075 nextNod[ iNotSameNode ]);
3077 else { // quadratic edge
3078 if(nbSame==0) { // quadratic quadrangle
3079 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3080 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3082 else if(nbSame==1) { // quadratic triangle
3084 return; // medium node on axis
3086 else if(sames[0]==0) {
3087 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3088 nextNod[2], midlNod[1], prevNod[2]);
3090 else { // sames[0]==1
3091 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3092 midlNod[0], nextNod[2], prevNod[2]);
3101 case 4: { // QUADRANGLE
3103 if ( nbSame == 0 ) // --- hexahedron
3104 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3105 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3107 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3108 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3109 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3110 nextNod[ iSameNode ]);
3111 newElems.push_back( aNewElem );
3112 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3113 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3114 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3116 else if ( nbSame == 2 ) { // pentahedron
3117 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3118 // iBeforeSame is same too
3119 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3120 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3121 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3123 // iAfterSame is same too
3124 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3125 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3126 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3130 case 6: { // quadratic triangle
3131 // create pentahedron with 15 nodes
3133 if(i0>0) { // reversed case
3134 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3135 nextNod[0], nextNod[2], nextNod[1],
3136 prevNod[5], prevNod[4], prevNod[3],
3137 nextNod[5], nextNod[4], nextNod[3],
3138 midlNod[0], midlNod[2], midlNod[1]);
3140 else { // not reversed case
3141 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3142 nextNod[0], nextNod[1], nextNod[2],
3143 prevNod[3], prevNod[4], prevNod[5],
3144 nextNod[3], nextNod[4], nextNod[5],
3145 midlNod[0], midlNod[1], midlNod[2]);
3148 else if(nbSame==1) {
3149 // 2d order pyramid of 13 nodes
3150 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3151 // int n12,int n23,int n34,int n41,
3152 // int n15,int n25,int n35,int n45, int ID);
3154 int n1,n4,n41,n15,n45;
3155 if(i0>0) { // reversed case
3156 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3157 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3163 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3164 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3169 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3170 nextNod[n4], prevNod[n4], prevNod[n5],
3171 midlNod[n1], nextNod[n41],
3172 midlNod[n4], prevNod[n41],
3173 prevNod[n15], nextNod[n15],
3174 nextNod[n45], prevNod[n45]);
3176 else if(nbSame==2) {
3177 // 2d order tetrahedron of 10 nodes
3178 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3179 // int n12,int n23,int n31,
3180 // int n14,int n24,int n34, int ID);
3181 int n1 = iNotSameNode;
3182 int n2,n3,n12,n23,n31;
3183 if(i0>0) { // reversed case
3184 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3185 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3191 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3192 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3197 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3198 prevNod[n12], prevNod[n23], prevNod[n31],
3199 midlNod[n1], nextNod[n12], nextNod[n31]);
3203 case 8: { // quadratic quadrangle
3205 // create hexahedron with 20 nodes
3206 if(i0>0) { // reversed case
3207 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3208 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3209 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3210 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3211 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3213 else { // not reversed case
3214 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3215 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3216 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3217 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3218 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3221 else if(nbSame==1) {
3222 // --- pyramid + pentahedron - can not be created since it is needed
3223 // additional middle node ot the center of face
3224 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3227 else if(nbSame==2) {
3228 // 2d order Pentahedron with 15 nodes
3229 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3230 // int n12,int n23,int n31,int n45,int n56,int n64,
3231 // int n14,int n25,int n36, int ID);
3233 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3234 // iBeforeSame is same too
3241 // iAfterSame is same too
3247 int n12,n45,n14,n25;
3248 if(i0>0) { //reversed case
3260 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3261 prevNod[n4], prevNod[n5], nextNod[n5],
3262 prevNod[n12], midlNod[n2], nextNod[n12],
3263 prevNod[n45], midlNod[n5], nextNod[n45],
3264 prevNod[n14], prevNod[n25], nextNod[n25]);
3269 // realized for extrusion only
3270 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3271 //vector<int> quantities (nbNodes + 2);
3273 //quantities[0] = nbNodes; // bottom of prism
3274 //for (int inode = 0; inode < nbNodes; inode++) {
3275 // polyedre_nodes[inode] = prevNod[inode];
3278 //quantities[1] = nbNodes; // top of prism
3279 //for (int inode = 0; inode < nbNodes; inode++) {
3280 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3283 //for (int iface = 0; iface < nbNodes; iface++) {
3284 // quantities[iface + 2] = 4;
3285 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3286 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3287 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3288 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3289 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3291 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3298 // realized for extrusion only
3299 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3300 vector<int> quantities (nbNodes + 2);
3302 quantities[0] = nbNodes; // bottom of prism
3303 for (int inode = 0; inode < nbNodes; inode++) {
3304 polyedre_nodes[inode] = prevNod[inode];
3307 quantities[1] = nbNodes; // top of prism
3308 for (int inode = 0; inode < nbNodes; inode++) {
3309 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3312 for (int iface = 0; iface < nbNodes; iface++) {
3313 quantities[iface + 2] = 4;
3314 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3315 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3316 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3317 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3318 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3320 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3324 newElems.push_back( aNewElem );
3325 myLastCreatedElems.Append(aNewElem);
3326 srcElements.Append( elem );
3329 // set new prev nodes
3330 for ( iNode = 0; iNode < nbNodes; iNode++ )
3331 prevNod[ iNode ] = nextNod[ iNode ];
3336 //=======================================================================
3338 * \brief Create 1D and 2D elements around swept elements
3339 * \param mapNewNodes - source nodes and ones generated from them
3340 * \param newElemsMap - source elements and ones generated from them
3341 * \param elemNewNodesMap - nodes generated from each node of each element
3342 * \param elemSet - all swept elements
3343 * \param nbSteps - number of sweeping steps
3344 * \param srcElements - to append elem for each generated element
3346 //=======================================================================
3348 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3349 TElemOfElemListMap & newElemsMap,
3350 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3351 TIDSortedElemSet& elemSet,
3353 SMESH_SequenceOfElemPtr& srcElements)
3355 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3356 SMESHDS_Mesh* aMesh = GetMeshDS();
3358 // Find nodes belonging to only one initial element - sweep them to get edges.
3360 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3361 for ( ; nList != mapNewNodes.end(); nList++ ) {
3362 const SMDS_MeshNode* node =
3363 static_cast<const SMDS_MeshNode*>( nList->first );
3364 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3365 int nbInitElems = 0;
3366 const SMDS_MeshElement* el = 0;
3367 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3368 while ( eIt->more() && nbInitElems < 2 ) {
3370 SMDSAbs_ElementType type = el->GetType();
3371 if ( type == SMDSAbs_Volume || type < highType ) continue;
3372 if ( type > highType ) {
3376 if ( elemSet.find(el) != elemSet.end() )
3379 if ( nbInitElems < 2 ) {
3380 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3381 if(!NotCreateEdge) {
3382 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3383 list<const SMDS_MeshElement*> newEdges;
3384 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3389 // Make a ceiling for each element ie an equal element of last new nodes.
3390 // Find free links of faces - make edges and sweep them into faces.
3392 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3393 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3394 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3395 const SMDS_MeshElement* elem = itElem->first;
3396 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3398 if ( elem->GetType() == SMDSAbs_Edge ) {
3399 // create a ceiling edge
3400 if (!elem->IsQuadratic()) {
3401 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3402 vecNewNodes[ 1 ]->second.back())) {
3403 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3404 vecNewNodes[ 1 ]->second.back()));
3405 srcElements.Append( myLastCreatedElems.Last() );
3409 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3410 vecNewNodes[ 1 ]->second.back(),
3411 vecNewNodes[ 2 ]->second.back())) {
3412 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3413 vecNewNodes[ 1 ]->second.back(),
3414 vecNewNodes[ 2 ]->second.back()));
3415 srcElements.Append( myLastCreatedElems.Last() );
3419 if ( elem->GetType() != SMDSAbs_Face )
3422 if(itElem->second.size()==0) continue;
3424 bool hasFreeLinks = false;
3426 TIDSortedElemSet avoidSet;
3427 avoidSet.insert( elem );
3429 set<const SMDS_MeshNode*> aFaceLastNodes;
3430 int iNode, nbNodes = vecNewNodes.size();
3431 if(!elem->IsQuadratic()) {
3432 // loop on the face nodes
3433 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3434 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3435 // look for free links of the face
3436 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3437 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3438 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3439 // check if a link is free
3440 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3441 hasFreeLinks = true;
3442 // make an edge and a ceiling for a new edge
3443 if ( !aMesh->FindEdge( n1, n2 )) {
3444 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3445 srcElements.Append( myLastCreatedElems.Last() );
3447 n1 = vecNewNodes[ iNode ]->second.back();
3448 n2 = vecNewNodes[ iNext ]->second.back();
3449 if ( !aMesh->FindEdge( n1, n2 )) {
3450 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3451 srcElements.Append( myLastCreatedElems.Last() );
3456 else { // elem is quadratic face
3457 int nbn = nbNodes/2;
3458 for ( iNode = 0; iNode < nbn; iNode++ ) {
3459 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3460 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3461 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3462 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3463 // check if a link is free
3464 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3465 hasFreeLinks = true;
3466 // make an edge and a ceiling for a new edge
3468 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3469 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3470 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3471 srcElements.Append( myLastCreatedElems.Last() );
3473 n1 = vecNewNodes[ iNode ]->second.back();
3474 n2 = vecNewNodes[ iNext ]->second.back();
3475 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3476 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3477 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3478 srcElements.Append( myLastCreatedElems.Last() );
3482 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3483 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3487 // sweep free links into faces
3489 if ( hasFreeLinks ) {
3490 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3491 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3493 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3494 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3495 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3496 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3498 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3499 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3501 while ( iVol++ < volNb ) v++;
3502 // find indices of free faces of a volume and their source edges
3503 list< int > freeInd;
3504 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3505 SMDS_VolumeTool vTool( *v );
3506 int iF, nbF = vTool.NbFaces();
3507 for ( iF = 0; iF < nbF; iF ++ ) {
3508 if (vTool.IsFreeFace( iF ) &&
3509 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3510 initNodeSet != faceNodeSet) // except an initial face
3512 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3514 freeInd.push_back( iF );
3515 // find source edge of a free face iF
3516 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3517 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3518 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3519 initNodeSet.begin(), initNodeSet.end(),
3520 commonNodes.begin());
3521 if ( (*v)->IsQuadratic() )
3522 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3524 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3526 if ( !srcEdges.back() )
3528 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3529 << iF << " of volume #" << vTool.ID() << endl;
3534 if ( freeInd.empty() )
3537 // create faces for all steps;
3538 // if such a face has been already created by sweep of edge,
3539 // assure that its orientation is OK
3540 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3542 vTool.SetExternalNormal();
3543 list< int >::iterator ind = freeInd.begin();
3544 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3545 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3547 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3548 int nbn = vTool.NbFaceNodes( *ind );
3550 case 3: { ///// triangle
3551 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3553 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3554 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3555 aMesh->ChangeElementNodes( f, nodes, nbn );
3558 case 4: { ///// quadrangle
3559 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3561 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3562 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3563 aMesh->ChangeElementNodes( f, nodes, nbn );
3567 if( (*v)->IsQuadratic() ) {
3568 if(nbn==6) { /////// quadratic triangle
3569 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3570 nodes[1], nodes[3], nodes[5] );
3572 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3573 nodes[1], nodes[3], nodes[5]));
3575 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3576 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3577 tmpnodes[0] = nodes[0];
3578 tmpnodes[1] = nodes[2];
3579 tmpnodes[2] = nodes[4];
3580 tmpnodes[3] = nodes[1];
3581 tmpnodes[4] = nodes[3];
3582 tmpnodes[5] = nodes[5];
3583 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3586 else { /////// quadratic quadrangle
3587 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3588 nodes[1], nodes[3], nodes[5], nodes[7] );
3590 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3591 nodes[1], nodes[3], nodes[5], nodes[7]));
3593 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3594 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3595 tmpnodes[0] = nodes[0];
3596 tmpnodes[1] = nodes[2];
3597 tmpnodes[2] = nodes[4];
3598 tmpnodes[3] = nodes[6];
3599 tmpnodes[4] = nodes[1];
3600 tmpnodes[5] = nodes[3];
3601 tmpnodes[6] = nodes[5];
3602 tmpnodes[7] = nodes[7];
3603 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3607 else { //////// polygon
3608 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3609 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3611 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3612 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3613 aMesh->ChangeElementNodes( f, nodes, nbn );
3616 while ( srcElements.Length() < myLastCreatedElems.Length() )
3617 srcElements.Append( *srcEdge );
3619 } // loop on free faces
3621 // go to the next volume
3623 while ( iVol++ < nbVolumesByStep ) v++;
3626 } // sweep free links into faces
3628 // Make a ceiling face with a normal external to a volume
3630 SMDS_VolumeTool lastVol( itElem->second.back() );
3632 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3634 lastVol.SetExternalNormal();
3635 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3636 int nbn = lastVol.NbFaceNodes( iF );
3639 if (!hasFreeLinks ||
3640 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3641 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3644 if (!hasFreeLinks ||
3645 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3646 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3649 if(itElem->second.back()->IsQuadratic()) {
3651 if (!hasFreeLinks ||
3652 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3653 nodes[1], nodes[3], nodes[5]) ) {
3654 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3655 nodes[1], nodes[3], nodes[5]));
3659 if (!hasFreeLinks ||
3660 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3661 nodes[1], nodes[3], nodes[5], nodes[7]) )
3662 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3663 nodes[1], nodes[3], nodes[5], nodes[7]));
3667 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3668 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3669 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3673 while ( srcElements.Length() < myLastCreatedElems.Length() )
3674 srcElements.Append( myLastCreatedElems.Last() );
3676 } // loop on swept elements
3679 //=======================================================================
3680 //function : RotationSweep
3682 //=======================================================================
3684 SMESH_MeshEditor::PGroupIDs
3685 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3686 const gp_Ax1& theAxis,
3687 const double theAngle,
3688 const int theNbSteps,
3689 const double theTol,
3690 const bool theMakeGroups,
3691 const bool theMakeWalls)
3693 myLastCreatedElems.Clear();
3694 myLastCreatedNodes.Clear();
3696 // source elements for each generated one
3697 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3699 MESSAGE( "RotationSweep()");
3701 aTrsf.SetRotation( theAxis, theAngle );
3703 aTrsf2.SetRotation( theAxis, theAngle/2. );
3705 gp_Lin aLine( theAxis );
3706 double aSqTol = theTol * theTol;
3708 SMESHDS_Mesh* aMesh = GetMeshDS();
3710 TNodeOfNodeListMap mapNewNodes;
3711 TElemOfVecOfNnlmiMap mapElemNewNodes;
3712 TElemOfElemListMap newElemsMap;
3715 TIDSortedElemSet::iterator itElem;
3716 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3717 const SMDS_MeshElement* elem = *itElem;
3718 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3720 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3721 newNodesItVec.reserve( elem->NbNodes() );
3723 // loop on elem nodes
3724 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3725 while ( itN->more() ) {
3726 // check if a node has been already sweeped
3727 const SMDS_MeshNode* node = cast2Node( itN->next() );
3729 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3731 aXYZ.Coord( coord[0], coord[1], coord[2] );
3732 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3734 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3735 if ( nIt == mapNewNodes.end() ) {
3736 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3737 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3740 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3742 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3743 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3744 const SMDS_MeshNode * newNode = node;
3745 for ( int i = 0; i < theNbSteps; i++ ) {
3747 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3749 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3750 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3751 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3752 myLastCreatedNodes.Append(newNode);
3753 srcNodes.Append( node );
3754 listNewNodes.push_back( newNode );
3755 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3756 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3759 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3761 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3762 myLastCreatedNodes.Append(newNode);
3763 srcNodes.Append( node );
3764 listNewNodes.push_back( newNode );
3767 listNewNodes.push_back( newNode );
3768 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3769 listNewNodes.push_back( newNode );
3776 // if current elem is quadratic and current node is not medium
3777 // we have to check - may be it is needed to insert additional nodes
3778 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3779 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3780 if(listNewNodes.size()==theNbSteps) {
3781 listNewNodes.clear();
3783 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3785 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3786 const SMDS_MeshNode * newNode = node;
3788 for(int i = 0; i<theNbSteps; i++) {
3789 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3790 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3791 cout<<" 3 AddNode: "<<newNode;
3792 myLastCreatedNodes.Append(newNode);
3793 listNewNodes.push_back( newNode );
3794 srcNodes.Append( node );
3795 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3796 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3797 cout<<" 4 AddNode: "<<newNode;
3798 myLastCreatedNodes.Append(newNode);
3799 srcNodes.Append( node );
3800 listNewNodes.push_back( newNode );
3804 listNewNodes.push_back( newNode );
3810 newNodesItVec.push_back( nIt );
3812 // make new elements
3813 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3817 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3819 PGroupIDs newGroupIDs;
3820 if ( theMakeGroups )
3821 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3827 //=======================================================================
3828 //function : CreateNode
3830 //=======================================================================
3831 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3834 const double tolnode,
3835 SMESH_SequenceOfNode& aNodes)
3837 myLastCreatedElems.Clear();
3838 myLastCreatedNodes.Clear();
3841 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3843 // try to search in sequence of existing nodes
3844 // if aNodes.Length()>0 we 'nave to use given sequence
3845 // else - use all nodes of mesh
3846 if(aNodes.Length()>0) {
3848 for(i=1; i<=aNodes.Length(); i++) {
3849 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3850 if(P1.Distance(P2)<tolnode)
3851 return aNodes.Value(i);
3855 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3856 while(itn->more()) {
3857 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3858 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3859 if(P1.Distance(P2)<tolnode)
3864 // create new node and return it
3865 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3866 myLastCreatedNodes.Append(NewNode);
3871 //=======================================================================
3872 //function : ExtrusionSweep
3874 //=======================================================================
3876 SMESH_MeshEditor::PGroupIDs
3877 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3878 const gp_Vec& theStep,
3879 const int theNbSteps,
3880 TElemOfElemListMap& newElemsMap,
3881 const bool theMakeGroups,
3883 const double theTolerance)
3885 ExtrusParam aParams;
3886 aParams.myDir = gp_Dir(theStep);
3887 aParams.myNodes.Clear();
3888 aParams.mySteps = new TColStd_HSequenceOfReal;
3890 for(i=1; i<=theNbSteps; i++)
3891 aParams.mySteps->Append(theStep.Magnitude());
3894 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3898 //=======================================================================
3899 //function : ExtrusionSweep
3901 //=======================================================================
3903 SMESH_MeshEditor::PGroupIDs
3904 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3905 ExtrusParam& theParams,
3906 TElemOfElemListMap& newElemsMap,
3907 const bool theMakeGroups,
3909 const double theTolerance)
3911 myLastCreatedElems.Clear();
3912 myLastCreatedNodes.Clear();
3914 // source elements for each generated one
3915 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3917 SMESHDS_Mesh* aMesh = GetMeshDS();
3919 int nbsteps = theParams.mySteps->Length();
3921 TNodeOfNodeListMap mapNewNodes;
3922 //TNodeOfNodeVecMap mapNewNodes;
3923 TElemOfVecOfNnlmiMap mapElemNewNodes;
3924 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3927 TIDSortedElemSet::iterator itElem;
3928 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3929 // check element type
3930 const SMDS_MeshElement* elem = *itElem;
3931 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3934 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3935 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3936 newNodesItVec.reserve( elem->NbNodes() );
3938 // loop on elem nodes
3939 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3940 while ( itN->more() )
3942 // check if a node has been already sweeped
3943 const SMDS_MeshNode* node = cast2Node( itN->next() );
3944 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3945 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3946 if ( nIt == mapNewNodes.end() ) {
3947 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3948 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3949 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3950 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3951 //vecNewNodes.reserve(nbsteps);
3954 double coord[] = { node->X(), node->Y(), node->Z() };
3955 //int nbsteps = theParams.mySteps->Length();
3956 for ( int i = 0; i < nbsteps; i++ ) {
3957 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3958 // create additional node
3959 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3960 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3961 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3962 if( theFlags & EXTRUSION_FLAG_SEW ) {
3963 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3964 theTolerance, theParams.myNodes);
3965 listNewNodes.push_back( newNode );
3968 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3969 myLastCreatedNodes.Append(newNode);
3970 srcNodes.Append( node );
3971 listNewNodes.push_back( newNode );
3974 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3975 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3976 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3977 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3978 if( theFlags & EXTRUSION_FLAG_SEW ) {
3979 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3980 theTolerance, theParams.myNodes);
3981 listNewNodes.push_back( newNode );
3982 //vecNewNodes[i]=newNode;
3985 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3986 myLastCreatedNodes.Append(newNode);
3987 srcNodes.Append( node );
3988 listNewNodes.push_back( newNode );
3989 //vecNewNodes[i]=newNode;
3994 // if current elem is quadratic and current node is not medium
3995 // we have to check - may be it is needed to insert additional nodes
3996 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3997 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3998 if(listNewNodes.size()==nbsteps) {
3999 listNewNodes.clear();
4000 double coord[] = { node->X(), node->Y(), node->Z() };
4001 for ( int i = 0; i < nbsteps; i++ ) {
4002 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4003 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4004 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4005 if( theFlags & EXTRUSION_FLAG_SEW ) {
4006 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4007 theTolerance, theParams.myNodes);
4008 listNewNodes.push_back( newNode );
4011 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4012 myLastCreatedNodes.Append(newNode);
4013 srcNodes.Append( node );
4014 listNewNodes.push_back( newNode );
4016 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4017 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4018 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4019 if( theFlags & EXTRUSION_FLAG_SEW ) {
4020 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4021 theTolerance, theParams.myNodes);
4022 listNewNodes.push_back( newNode );
4025 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4026 myLastCreatedNodes.Append(newNode);
4027 srcNodes.Append( node );
4028 listNewNodes.push_back( newNode );
4034 newNodesItVec.push_back( nIt );
4036 // make new elements
4037 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4040 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4041 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4043 PGroupIDs newGroupIDs;
4044 if ( theMakeGroups )
4045 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4051 //=======================================================================
4052 //class : SMESH_MeshEditor_PathPoint
4053 //purpose : auxiliary class
4054 //=======================================================================
4055 class SMESH_MeshEditor_PathPoint {
4057 SMESH_MeshEditor_PathPoint() {
4058 myPnt.SetCoord(99., 99., 99.);
4059 myTgt.SetCoord(1.,0.,0.);
4063 void SetPnt(const gp_Pnt& aP3D){
4066 void SetTangent(const gp_Dir& aTgt){
4069 void SetAngle(const double& aBeta){
4072 void SetParameter(const double& aPrm){
4075 const gp_Pnt& Pnt()const{
4078 const gp_Dir& Tangent()const{
4081 double Angle()const{
4084 double Parameter()const{
4096 //=======================================================================
4097 //function : ExtrusionAlongTrack
4099 //=======================================================================
4100 SMESH_MeshEditor::Extrusion_Error
4101 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4102 SMESH_subMesh* theTrack,
4103 const SMDS_MeshNode* theN1,
4104 const bool theHasAngles,
4105 list<double>& theAngles,
4106 const bool theLinearVariation,
4107 const bool theHasRefPoint,
4108 const gp_Pnt& theRefPoint,
4109 const bool theMakeGroups)
4111 myLastCreatedElems.Clear();
4112 myLastCreatedNodes.Clear();
4115 std::list<double> aPrms;
4116 TIDSortedElemSet::iterator itElem;
4119 TopoDS_Edge aTrackEdge;
4120 TopoDS_Vertex aV1, aV2;
4122 SMDS_ElemIteratorPtr aItE;
4123 SMDS_NodeIteratorPtr aItN;
4124 SMDSAbs_ElementType aTypeE;
4126 TNodeOfNodeListMap mapNewNodes;
4129 aNbE = theElements.size();
4132 return EXTR_NO_ELEMENTS;
4134 // 1.1 Track Pattern
4137 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4139 aItE = pSubMeshDS->GetElements();
4140 while ( aItE->more() ) {
4141 const SMDS_MeshElement* pE = aItE->next();
4142 aTypeE = pE->GetType();
4143 // Pattern must contain links only
4144 if ( aTypeE != SMDSAbs_Edge )
4145 return EXTR_PATH_NOT_EDGE;
4148 list<SMESH_MeshEditor_PathPoint> fullList;
4150 const TopoDS_Shape& aS = theTrack->GetSubShape();
4151 // Sub shape for the Pattern must be an Edge or Wire
4152 if( aS.ShapeType() == TopAbs_EDGE ) {
4153 aTrackEdge = TopoDS::Edge( aS );
4154 // the Edge must not be degenerated
4155 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4156 return EXTR_BAD_PATH_SHAPE;
4157 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4158 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4159 const SMDS_MeshNode* aN1 = aItN->next();
4160 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4161 const SMDS_MeshNode* aN2 = aItN->next();
4162 // starting node must be aN1 or aN2
4163 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4164 return EXTR_BAD_STARTING_NODE;
4165 aItN = pSubMeshDS->GetNodes();
4166 while ( aItN->more() ) {
4167 const SMDS_MeshNode* pNode = aItN->next();
4168 const SMDS_EdgePosition* pEPos =
4169 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4170 double aT = pEPos->GetUParameter();
4171 aPrms.push_back( aT );
4173 //Extrusion_Error err =
4174 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4176 else if( aS.ShapeType() == TopAbs_WIRE ) {
4177 list< SMESH_subMesh* > LSM;
4178 TopTools_SequenceOfShape Edges;
4179 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4180 while(itSM->more()) {
4181 SMESH_subMesh* SM = itSM->next();
4183 const TopoDS_Shape& aS = SM->GetSubShape();
4186 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4187 int startNid = theN1->GetID();
4188 TColStd_MapOfInteger UsedNums;
4189 int NbEdges = Edges.Length();
4191 for(; i<=NbEdges; i++) {
4193 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4194 for(; itLSM!=LSM.end(); itLSM++) {
4196 if(UsedNums.Contains(k)) continue;
4197 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4198 SMESH_subMesh* locTrack = *itLSM;
4199 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4200 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4201 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4202 const SMDS_MeshNode* aN1 = aItN->next();
4203 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4204 const SMDS_MeshNode* aN2 = aItN->next();
4205 // starting node must be aN1 or aN2
4206 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4207 // 2. Collect parameters on the track edge
4209 aItN = locMeshDS->GetNodes();
4210 while ( aItN->more() ) {
4211 const SMDS_MeshNode* pNode = aItN->next();
4212 const SMDS_EdgePosition* pEPos =
4213 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4214 double aT = pEPos->GetUParameter();
4215 aPrms.push_back( aT );
4217 list<SMESH_MeshEditor_PathPoint> LPP;
4218 //Extrusion_Error err =
4219 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4220 LLPPs.push_back(LPP);
4222 // update startN for search following egde
4223 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4224 else startNid = aN1->GetID();
4228 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4229 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4230 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4231 for(; itPP!=firstList.end(); itPP++) {
4232 fullList.push_back( *itPP );
4234 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4235 fullList.pop_back();
4237 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4238 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4239 itPP = currList.begin();
4240 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4241 gp_Dir D1 = PP1.Tangent();
4242 gp_Dir D2 = PP2.Tangent();
4243 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4244 (D1.Z()+D2.Z())/2 ) );
4245 PP1.SetTangent(Dnew);
4246 fullList.push_back(PP1);
4248 for(; itPP!=firstList.end(); itPP++) {
4249 fullList.push_back( *itPP );
4251 PP1 = fullList.back();
4252 fullList.pop_back();
4254 // if wire not closed
4255 fullList.push_back(PP1);
4259 return EXTR_BAD_PATH_SHAPE;
4262 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4263 theHasRefPoint, theRefPoint, theMakeGroups);
4267 //=======================================================================
4268 //function : ExtrusionAlongTrack
4270 //=======================================================================
4271 SMESH_MeshEditor::Extrusion_Error
4272 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4273 SMESH_Mesh* theTrack,
4274 const SMDS_MeshNode* theN1,
4275 const bool theHasAngles,
4276 list<double>& theAngles,
4277 const bool theLinearVariation,
4278 const bool theHasRefPoint,
4279 const gp_Pnt& theRefPoint,
4280 const bool theMakeGroups)
4282 myLastCreatedElems.Clear();
4283 myLastCreatedNodes.Clear();
4286 std::list<double> aPrms;
4287 TIDSortedElemSet::iterator itElem;
4290 TopoDS_Edge aTrackEdge;
4291 TopoDS_Vertex aV1, aV2;
4293 SMDS_ElemIteratorPtr aItE;
4294 SMDS_NodeIteratorPtr aItN;
4295 SMDSAbs_ElementType aTypeE;
4297 TNodeOfNodeListMap mapNewNodes;
4300 aNbE = theElements.size();
4303 return EXTR_NO_ELEMENTS;
4305 // 1.1 Track Pattern
4308 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4310 aItE = pMeshDS->elementsIterator();
4311 while ( aItE->more() ) {
4312 const SMDS_MeshElement* pE = aItE->next();
4313 aTypeE = pE->GetType();
4314 // Pattern must contain links only
4315 if ( aTypeE != SMDSAbs_Edge )
4316 return EXTR_PATH_NOT_EDGE;
4319 list<SMESH_MeshEditor_PathPoint> fullList;
4321 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4322 // Sub shape for the Pattern must be an Edge or Wire
4323 if( aS.ShapeType() == TopAbs_EDGE ) {
4324 aTrackEdge = TopoDS::Edge( aS );
4325 // the Edge must not be degenerated
4326 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4327 return EXTR_BAD_PATH_SHAPE;
4328 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4329 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4330 const SMDS_MeshNode* aN1 = aItN->next();
4331 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4332 const SMDS_MeshNode* aN2 = aItN->next();
4333 // starting node must be aN1 or aN2
4334 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4335 return EXTR_BAD_STARTING_NODE;
4336 aItN = pMeshDS->nodesIterator();
4337 while ( aItN->more() ) {
4338 const SMDS_MeshNode* pNode = aItN->next();
4339 if( pNode==aN1 || pNode==aN2 ) continue;
4340 const SMDS_EdgePosition* pEPos =
4341 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4342 double aT = pEPos->GetUParameter();
4343 aPrms.push_back( aT );
4345 //Extrusion_Error err =
4346 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4348 else if( aS.ShapeType() == TopAbs_WIRE ) {
4349 list< SMESH_subMesh* > LSM;
4350 TopTools_SequenceOfShape Edges;
4351 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4352 for(; eExp.More(); eExp.Next()) {
4353 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4354 if( BRep_Tool::Degenerated(E) ) continue;
4355 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4361 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4362 int startNid = theN1->GetID();
4363 TColStd_MapOfInteger UsedNums;
4364 int NbEdges = Edges.Length();
4366 for(; i<=NbEdges; i++) {
4368 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4369 for(; itLSM!=LSM.end(); itLSM++) {
4371 if(UsedNums.Contains(k)) continue;
4372 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4373 SMESH_subMesh* locTrack = *itLSM;
4374 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4375 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4376 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4377 const SMDS_MeshNode* aN1 = aItN->next();
4378 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4379 const SMDS_MeshNode* aN2 = aItN->next();
4380 // starting node must be aN1 or aN2
4381 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4382 // 2. Collect parameters on the track edge
4384 aItN = locMeshDS->GetNodes();
4385 while ( aItN->more() ) {
4386 const SMDS_MeshNode* pNode = aItN->next();
4387 const SMDS_EdgePosition* pEPos =
4388 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4389 double aT = pEPos->GetUParameter();
4390 aPrms.push_back( aT );
4392 list<SMESH_MeshEditor_PathPoint> LPP;
4393 //Extrusion_Error err =
4394 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4395 LLPPs.push_back(LPP);
4397 // update startN for search following egde
4398 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4399 else startNid = aN1->GetID();
4403 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4404 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4405 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4406 for(; itPP!=firstList.end(); itPP++) {
4407 fullList.push_back( *itPP );
4409 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4410 fullList.pop_back();
4412 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4413 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4414 itPP = currList.begin();
4415 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4416 gp_Pnt P1 = PP1.Pnt();
4417 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4418 gp_Pnt P2 = PP2.Pnt();
4419 gp_Dir D1 = PP1.Tangent();
4420 gp_Dir D2 = PP2.Tangent();
4421 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4422 (D1.Z()+D2.Z())/2 ) );
4423 PP1.SetTangent(Dnew);
4424 fullList.push_back(PP1);
4426 for(; itPP!=currList.end(); itPP++) {
4427 fullList.push_back( *itPP );
4429 PP1 = fullList.back();
4430 fullList.pop_back();
4432 // if wire not closed
4433 fullList.push_back(PP1);
4437 return EXTR_BAD_PATH_SHAPE;
4440 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4441 theHasRefPoint, theRefPoint, theMakeGroups);
4445 //=======================================================================
4446 //function : MakeEdgePathPoints
4447 //purpose : auxilary for ExtrusionAlongTrack
4448 //=======================================================================
4449 SMESH_MeshEditor::Extrusion_Error
4450 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4451 const TopoDS_Edge& aTrackEdge,
4453 list<SMESH_MeshEditor_PathPoint>& LPP)
4455 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4457 aTolVec2=aTolVec*aTolVec;
4459 TopoDS_Vertex aV1, aV2;
4460 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4461 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4462 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4463 // 2. Collect parameters on the track edge
4464 aPrms.push_front( aT1 );
4465 aPrms.push_back( aT2 );
4468 if( FirstIsStart ) {
4479 SMESH_MeshEditor_PathPoint aPP;
4480 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4481 std::list<double>::iterator aItD = aPrms.begin();
4482 for(; aItD != aPrms.end(); ++aItD) {
4486 aC3D->D1( aT, aP3D, aVec );
4487 aL2 = aVec.SquareMagnitude();
4488 if ( aL2 < aTolVec2 )
4489 return EXTR_CANT_GET_TANGENT;
4490 gp_Dir aTgt( aVec );
4492 aPP.SetTangent( aTgt );
4493 aPP.SetParameter( aT );
4500 //=======================================================================
4501 //function : MakeExtrElements
4502 //purpose : auxilary for ExtrusionAlongTrack
4503 //=======================================================================
4504 SMESH_MeshEditor::Extrusion_Error
4505 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4506 list<SMESH_MeshEditor_PathPoint>& fullList,
4507 const bool theHasAngles,
4508 list<double>& theAngles,
4509 const bool theLinearVariation,
4510 const bool theHasRefPoint,
4511 const gp_Pnt& theRefPoint,
4512 const bool theMakeGroups)
4514 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4515 int aNbTP = fullList.size();
4516 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4518 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4519 LinearAngleVariation(aNbTP-1, theAngles);
4521 vector<double> aAngles( aNbTP );
4523 for(; j<aNbTP; ++j) {
4526 if ( theHasAngles ) {
4528 std::list<double>::iterator aItD = theAngles.begin();
4529 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4531 aAngles[j] = anAngle;
4534 // fill vector of path points with angles
4535 //aPPs.resize(fullList.size());
4537 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4538 for(; itPP!=fullList.end(); itPP++) {
4540 SMESH_MeshEditor_PathPoint PP = *itPP;
4541 PP.SetAngle(aAngles[j]);
4545 TNodeOfNodeListMap mapNewNodes;
4546 TElemOfVecOfNnlmiMap mapElemNewNodes;
4547 TElemOfElemListMap newElemsMap;
4548 TIDSortedElemSet::iterator itElem;
4551 SMDSAbs_ElementType aTypeE;
4552 // source elements for each generated one
4553 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4555 // 3. Center of rotation aV0
4556 gp_Pnt aV0 = theRefPoint;
4558 if ( !theHasRefPoint ) {
4560 aGC.SetCoord( 0.,0.,0. );
4562 itElem = theElements.begin();
4563 for ( ; itElem != theElements.end(); itElem++ ) {
4564 const SMDS_MeshElement* elem = *itElem;
4566 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4567 while ( itN->more() ) {
4568 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4573 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4574 list<const SMDS_MeshNode*> aLNx;
4575 mapNewNodes[node] = aLNx;
4577 gp_XYZ aXYZ( aX, aY, aZ );
4585 } // if (!theHasRefPoint) {
4586 mapNewNodes.clear();
4588 // 4. Processing the elements
4589 SMESHDS_Mesh* aMesh = GetMeshDS();
4591 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4592 // check element type
4593 const SMDS_MeshElement* elem = *itElem;
4594 aTypeE = elem->GetType();
4595 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4598 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4599 newNodesItVec.reserve( elem->NbNodes() );
4601 // loop on elem nodes
4603 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4604 while ( itN->more() )
4607 // check if a node has been already processed
4608 const SMDS_MeshNode* node =
4609 static_cast<const SMDS_MeshNode*>( itN->next() );
4610 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4611 if ( nIt == mapNewNodes.end() ) {
4612 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4613 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4616 aX = node->X(); aY = node->Y(); aZ = node->Z();
4618 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4619 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4620 gp_Ax1 anAx1, anAxT1T0;
4621 gp_Dir aDT1x, aDT0x, aDT1T0;
4626 aPN0.SetCoord(aX, aY, aZ);
4628 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4630 aDT0x= aPP0.Tangent();
4631 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4633 for ( j = 1; j < aNbTP; ++j ) {
4634 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4636 aDT1x = aPP1.Tangent();
4637 aAngle1x = aPP1.Angle();
4639 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4641 gp_Vec aV01x( aP0x, aP1x );
4642 aTrsf.SetTranslation( aV01x );
4645 aV1x = aV0x.Transformed( aTrsf );
4646 aPN1 = aPN0.Transformed( aTrsf );
4648 // rotation 1 [ T1,T0 ]
4649 aAngleT1T0=-aDT1x.Angle( aDT0x );
4650 if (fabs(aAngleT1T0) > aTolAng) {
4652 anAxT1T0.SetLocation( aV1x );
4653 anAxT1T0.SetDirection( aDT1T0 );
4654 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4656 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4660 if ( theHasAngles ) {
4661 anAx1.SetLocation( aV1x );
4662 anAx1.SetDirection( aDT1x );
4663 aTrsfRot.SetRotation( anAx1, aAngle1x );
4665 aPN1 = aPN1.Transformed( aTrsfRot );
4669 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4670 // create additional node
4671 double x = ( aPN1.X() + aPN0.X() )/2.;
4672 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4673 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4674 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4675 myLastCreatedNodes.Append(newNode);
4676 srcNodes.Append( node );
4677 listNewNodes.push_back( newNode );
4682 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4683 myLastCreatedNodes.Append(newNode);
4684 srcNodes.Append( node );
4685 listNewNodes.push_back( newNode );
4695 // if current elem is quadratic and current node is not medium
4696 // we have to check - may be it is needed to insert additional nodes
4697 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4698 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4699 if(listNewNodes.size()==aNbTP-1) {
4700 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4701 gp_XYZ P(node->X(), node->Y(), node->Z());
4702 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4704 for(i=0; i<aNbTP-1; i++) {
4705 const SMDS_MeshNode* N = *it;
4706 double x = ( N->X() + P.X() )/2.;
4707 double y = ( N->Y() + P.Y() )/2.;
4708 double z = ( N->Z() + P.Z() )/2.;
4709 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4710 srcNodes.Append( node );
4711 myLastCreatedNodes.Append(newN);
4714 P = gp_XYZ(N->X(),N->Y(),N->Z());
4716 listNewNodes.clear();
4717 for(i=0; i<2*(aNbTP-1); i++) {
4718 listNewNodes.push_back(aNodes[i]);
4724 newNodesItVec.push_back( nIt );
4726 // make new elements
4727 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4728 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4729 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4732 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4734 if ( theMakeGroups )
4735 generateGroups( srcNodes, srcElems, "extruded");
4741 //=======================================================================
4742 //function : LinearAngleVariation
4743 //purpose : auxilary for ExtrusionAlongTrack
4744 //=======================================================================
4745 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4746 list<double>& Angles)
4748 int nbAngles = Angles.size();
4749 if( nbSteps > nbAngles ) {
4750 vector<double> theAngles(nbAngles);
4751 list<double>::iterator it = Angles.begin();
4753 for(; it!=Angles.end(); it++) {
4755 theAngles[i] = (*it);
4758 double rAn2St = double( nbAngles ) / double( nbSteps );
4759 double angPrev = 0, angle;
4760 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4761 double angCur = rAn2St * ( iSt+1 );
4762 double angCurFloor = floor( angCur );
4763 double angPrevFloor = floor( angPrev );
4764 if ( angPrevFloor == angCurFloor )
4765 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4767 int iP = int( angPrevFloor );
4768 double angPrevCeil = ceil(angPrev);
4769 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4771 int iC = int( angCurFloor );
4772 if ( iC < nbAngles )
4773 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4775 iP = int( angPrevCeil );
4777 angle += theAngles[ iC ];
4779 res.push_back(angle);
4784 for(; it!=res.end(); it++)
4785 Angles.push_back( *it );
4790 //=======================================================================
4791 //function : Transform
4793 //=======================================================================
4795 SMESH_MeshEditor::PGroupIDs
4796 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4797 const gp_Trsf& theTrsf,
4799 const bool theMakeGroups,
4800 SMESH_Mesh* theTargetMesh)
4802 myLastCreatedElems.Clear();
4803 myLastCreatedNodes.Clear();
4805 bool needReverse = false;
4806 string groupPostfix;
4807 switch ( theTrsf.Form() ) {
4812 groupPostfix = "mirrored";
4815 groupPostfix = "rotated";
4817 case gp_Translation:
4818 groupPostfix = "translated";
4821 groupPostfix = "scaled";
4824 needReverse = false;
4825 groupPostfix = "transformed";
4828 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4829 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4830 SMESHDS_Mesh* aMesh = GetMeshDS();
4833 // map old node to new one
4834 TNodeNodeMap nodeMap;
4836 // elements sharing moved nodes; those of them which have all
4837 // nodes mirrored but are not in theElems are to be reversed
4838 TIDSortedElemSet inverseElemSet;
4840 // source elements for each generated one
4841 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4844 TIDSortedElemSet::iterator itElem;
4845 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4846 const SMDS_MeshElement* elem = *itElem;
4850 // loop on elem nodes
4851 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4852 while ( itN->more() ) {
4854 // check if a node has been already transformed
4855 const SMDS_MeshNode* node = cast2Node( itN->next() );
4856 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4857 nodeMap.insert( make_pair ( node, node ));
4858 if ( !n2n_isnew.second )
4862 coord[0] = node->X();
4863 coord[1] = node->Y();
4864 coord[2] = node->Z();
4865 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4866 if ( theTargetMesh ) {
4867 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4868 n2n_isnew.first->second = newNode;
4869 myLastCreatedNodes.Append(newNode);
4870 srcNodes.Append( node );
4872 else if ( theCopy ) {
4873 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4874 n2n_isnew.first->second = newNode;
4875 myLastCreatedNodes.Append(newNode);
4876 srcNodes.Append( node );
4879 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4880 // node position on shape becomes invalid
4881 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4882 ( SMDS_SpacePosition::originSpacePosition() );
4885 // keep inverse elements
4886 if ( !theCopy && !theTargetMesh && needReverse ) {
4887 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4888 while ( invElemIt->more() ) {
4889 const SMDS_MeshElement* iel = invElemIt->next();
4890 inverseElemSet.insert( iel );
4896 // either create new elements or reverse mirrored ones
4897 if ( !theCopy && !needReverse && !theTargetMesh )
4900 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4901 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4902 theElems.insert( *invElemIt );
4904 // replicate or reverse elements
4907 REV_TETRA = 0, // = nbNodes - 4
4908 REV_PYRAMID = 1, // = nbNodes - 4
4909 REV_PENTA = 2, // = nbNodes - 4
4911 REV_HEXA = 4, // = nbNodes - 4
4915 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4916 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4917 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4918 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4919 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4920 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4923 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4925 const SMDS_MeshElement* elem = *itElem;
4926 if ( !elem || elem->GetType() == SMDSAbs_Node )
4929 int nbNodes = elem->NbNodes();
4930 int elemType = elem->GetType();
4932 if (elem->IsPoly()) {
4933 // Polygon or Polyhedral Volume
4934 switch ( elemType ) {
4937 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4939 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4940 while (itN->more()) {
4941 const SMDS_MeshNode* node =
4942 static_cast<const SMDS_MeshNode*>(itN->next());
4943 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4944 if (nodeMapIt == nodeMap.end())
4945 break; // not all nodes transformed
4947 // reverse mirrored faces and volumes
4948 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4950 poly_nodes[iNode] = (*nodeMapIt).second;
4954 if ( iNode != nbNodes )
4955 continue; // not all nodes transformed
4957 if ( theTargetMesh ) {
4958 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4959 srcElems.Append( elem );
4961 else if ( theCopy ) {
4962 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4963 srcElems.Append( elem );
4966 aMesh->ChangePolygonNodes(elem, poly_nodes);
4970 case SMDSAbs_Volume:
4972 // ATTENTION: Reversing is not yet done!!!
4973 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4974 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4976 MESSAGE("Warning: bad volumic element");
4980 vector<const SMDS_MeshNode*> poly_nodes;
4981 vector<int> quantities;
4983 bool allTransformed = true;
4984 int nbFaces = aPolyedre->NbFaces();
4985 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4986 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4987 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4988 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4989 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4990 if (nodeMapIt == nodeMap.end()) {
4991 allTransformed = false; // not all nodes transformed
4993 poly_nodes.push_back((*nodeMapIt).second);
4996 quantities.push_back(nbFaceNodes);
4998 if ( !allTransformed )
4999 continue; // not all nodes transformed
5001 if ( theTargetMesh ) {
5002 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5003 srcElems.Append( elem );
5005 else if ( theCopy ) {
5006 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5007 srcElems.Append( elem );
5010 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5020 int* i = index[ FORWARD ];
5021 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5022 if ( elemType == SMDSAbs_Face )
5023 i = index[ REV_FACE ];
5025 i = index[ nbNodes - 4 ];
5027 if(elem->IsQuadratic()) {
5028 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5031 if(nbNodes==3) { // quadratic edge
5032 static int anIds[] = {1,0,2};
5035 else if(nbNodes==6) { // quadratic triangle
5036 static int anIds[] = {0,2,1,5,4,3};
5039 else if(nbNodes==8) { // quadratic quadrangle
5040 static int anIds[] = {0,3,2,1,7,6,5,4};
5043 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5044 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5047 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5048 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5051 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5052 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5055 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5056 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5062 // find transformed nodes
5063 vector<const SMDS_MeshNode*> nodes(nbNodes);
5065 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5066 while ( itN->more() ) {
5067 const SMDS_MeshNode* node =
5068 static_cast<const SMDS_MeshNode*>( itN->next() );
5069 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5070 if ( nodeMapIt == nodeMap.end() )
5071 break; // not all nodes transformed
5072 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5074 if ( iNode != nbNodes )
5075 continue; // not all nodes transformed
5077 if ( theTargetMesh ) {
5078 if ( SMDS_MeshElement* copy =
5079 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5080 myLastCreatedElems.Append( copy );
5081 srcElems.Append( elem );
5084 else if ( theCopy ) {
5085 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5086 myLastCreatedElems.Append( copy );
5087 srcElems.Append( elem );
5091 // reverse element as it was reversed by transformation
5093 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5097 PGroupIDs newGroupIDs;
5099 if ( theMakeGroups && theCopy ||
5100 theMakeGroups && theTargetMesh )
5101 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5107 //=======================================================================
5110 //=======================================================================
5112 SMESH_MeshEditor::PGroupIDs
5113 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5114 const gp_Pnt& thePoint,
5115 const std::list<double>& theScaleFact,
5117 const bool theMakeGroups,
5118 SMESH_Mesh* theTargetMesh)
5120 myLastCreatedElems.Clear();
5121 myLastCreatedNodes.Clear();
5123 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5124 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5125 SMESHDS_Mesh* aMesh = GetMeshDS();
5127 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5128 std::list<double>::const_iterator itS = theScaleFact.begin();
5130 if(theScaleFact.size()==1) {
5134 if(theScaleFact.size()==2) {
5139 if(theScaleFact.size()>2) {
5146 // map old node to new one
5147 TNodeNodeMap nodeMap;
5149 // elements sharing moved nodes; those of them which have all
5150 // nodes mirrored but are not in theElems are to be reversed
5151 TIDSortedElemSet inverseElemSet;
5153 // source elements for each generated one
5154 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5157 TIDSortedElemSet::iterator itElem;
5158 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5159 const SMDS_MeshElement* elem = *itElem;
5163 // loop on elem nodes
5164 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5165 while ( itN->more() ) {
5167 // check if a node has been already transformed
5168 const SMDS_MeshNode* node = cast2Node( itN->next() );
5169 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5170 nodeMap.insert( make_pair ( node, node ));
5171 if ( !n2n_isnew.second )
5175 //coord[0] = node->X();
5176 //coord[1] = node->Y();
5177 //coord[2] = node->Z();
5178 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5179 double dx = (node->X() - thePoint.X()) * scaleX;
5180 double dy = (node->Y() - thePoint.Y()) * scaleY;
5181 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5182 if ( theTargetMesh ) {
5183 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5184 const SMDS_MeshNode * newNode =
5185 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5186 n2n_isnew.first->second = newNode;
5187 myLastCreatedNodes.Append(newNode);
5188 srcNodes.Append( node );
5190 else if ( theCopy ) {
5191 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5192 const SMDS_MeshNode * newNode =
5193 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5194 n2n_isnew.first->second = newNode;
5195 myLastCreatedNodes.Append(newNode);
5196 srcNodes.Append( node );
5199 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5200 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5201 // node position on shape becomes invalid
5202 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5203 ( SMDS_SpacePosition::originSpacePosition() );
5206 // keep inverse elements
5207 //if ( !theCopy && !theTargetMesh && needReverse ) {
5208 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5209 // while ( invElemIt->more() ) {
5210 // const SMDS_MeshElement* iel = invElemIt->next();
5211 // inverseElemSet.insert( iel );
5217 // either create new elements or reverse mirrored ones
5218 //if ( !theCopy && !needReverse && !theTargetMesh )
5219 if ( !theCopy && !theTargetMesh )
5222 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5223 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5224 theElems.insert( *invElemIt );
5226 // replicate or reverse elements
5229 REV_TETRA = 0, // = nbNodes - 4
5230 REV_PYRAMID = 1, // = nbNodes - 4
5231 REV_PENTA = 2, // = nbNodes - 4
5233 REV_HEXA = 4, // = nbNodes - 4
5237 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5238 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5239 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5240 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5241 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5242 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5245 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5247 const SMDS_MeshElement* elem = *itElem;
5248 if ( !elem || elem->GetType() == SMDSAbs_Node )
5251 int nbNodes = elem->NbNodes();
5252 int elemType = elem->GetType();
5254 if (elem->IsPoly()) {
5255 // Polygon or Polyhedral Volume
5256 switch ( elemType ) {
5259 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5261 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5262 while (itN->more()) {
5263 const SMDS_MeshNode* node =
5264 static_cast<const SMDS_MeshNode*>(itN->next());
5265 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5266 if (nodeMapIt == nodeMap.end())
5267 break; // not all nodes transformed
5268 //if (needReverse) {
5269 // // reverse mirrored faces and volumes
5270 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5272 poly_nodes[iNode] = (*nodeMapIt).second;
5276 if ( iNode != nbNodes )
5277 continue; // not all nodes transformed
5279 if ( theTargetMesh ) {
5280 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5281 srcElems.Append( elem );
5283 else if ( theCopy ) {
5284 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5285 srcElems.Append( elem );
5288 aMesh->ChangePolygonNodes(elem, poly_nodes);
5292 case SMDSAbs_Volume:
5294 // ATTENTION: Reversing is not yet done!!!
5295 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5296 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5298 MESSAGE("Warning: bad volumic element");
5302 vector<const SMDS_MeshNode*> poly_nodes;
5303 vector<int> quantities;
5305 bool allTransformed = true;
5306 int nbFaces = aPolyedre->NbFaces();
5307 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5308 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5309 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5310 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5311 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5312 if (nodeMapIt == nodeMap.end()) {
5313 allTransformed = false; // not all nodes transformed
5315 poly_nodes.push_back((*nodeMapIt).second);
5318 quantities.push_back(nbFaceNodes);
5320 if ( !allTransformed )
5321 continue; // not all nodes transformed
5323 if ( theTargetMesh ) {
5324 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5325 srcElems.Append( elem );
5327 else if ( theCopy ) {
5328 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5329 srcElems.Append( elem );
5332 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5342 int* i = index[ FORWARD ];
5343 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5344 // if ( elemType == SMDSAbs_Face )
5345 // i = index[ REV_FACE ];
5347 // i = index[ nbNodes - 4 ];
5349 if(elem->IsQuadratic()) {
5350 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5353 // if(nbNodes==3) { // quadratic edge
5354 // static int anIds[] = {1,0,2};
5357 // else if(nbNodes==6) { // quadratic triangle
5358 // static int anIds[] = {0,2,1,5,4,3};
5361 // else if(nbNodes==8) { // quadratic quadrangle
5362 // static int anIds[] = {0,3,2,1,7,6,5,4};
5365 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5366 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5369 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5370 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5373 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5374 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5377 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5378 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5384 // find transformed nodes
5385 vector<const SMDS_MeshNode*> nodes(nbNodes);
5387 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5388 while ( itN->more() ) {
5389 const SMDS_MeshNode* node =
5390 static_cast<const SMDS_MeshNode*>( itN->next() );
5391 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5392 if ( nodeMapIt == nodeMap.end() )
5393 break; // not all nodes transformed
5394 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5396 if ( iNode != nbNodes )
5397 continue; // not all nodes transformed
5399 if ( theTargetMesh ) {
5400 if ( SMDS_MeshElement* copy =
5401 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5402 myLastCreatedElems.Append( copy );
5403 srcElems.Append( elem );
5406 else if ( theCopy ) {
5407 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5408 myLastCreatedElems.Append( copy );
5409 srcElems.Append( elem );
5413 // reverse element as it was reversed by transformation
5415 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5419 PGroupIDs newGroupIDs;
5421 if ( theMakeGroups && theCopy ||
5422 theMakeGroups && theTargetMesh ) {
5423 string groupPostfix = "scaled";
5424 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5431 //=======================================================================
5433 * \brief Create groups of elements made during transformation
5434 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5435 * \param elemGens - elements making corresponding myLastCreatedElems
5436 * \param postfix - to append to names of new groups
5438 //=======================================================================
5440 SMESH_MeshEditor::PGroupIDs
5441 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5442 const SMESH_SequenceOfElemPtr& elemGens,
5443 const std::string& postfix,
5444 SMESH_Mesh* targetMesh)
5446 PGroupIDs newGroupIDs( new list<int> );
5447 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5449 // Sort existing groups by types and collect their names
5451 // to store an old group and a generated new one
5452 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5453 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5455 set< string > groupNames;
5457 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5458 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5459 while ( groupIt->more() ) {
5460 SMESH_Group * group = groupIt->next();
5461 if ( !group ) continue;
5462 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5463 if ( !groupDS || groupDS->IsEmpty() ) continue;
5464 groupNames.insert( group->GetName() );
5465 groupDS->SetStoreName( group->GetName() );
5466 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5471 // loop on nodes and elements
5472 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5474 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5475 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5476 if ( gens.Length() != elems.Length() )
5477 throw SALOME_Exception(LOCALIZED("invalid args"));
5479 // loop on created elements
5480 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5482 const SMDS_MeshElement* sourceElem = gens( iElem );
5483 if ( !sourceElem ) {
5484 MESSAGE("generateGroups(): NULL source element");
5487 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5488 if ( groupsOldNew.empty() ) {
5489 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5490 ++iElem; // skip all elements made by sourceElem
5493 // collect all elements made by sourceElem
5494 list< const SMDS_MeshElement* > resultElems;
5495 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5496 if ( resElem != sourceElem )
5497 resultElems.push_back( resElem );
5498 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5499 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5500 if ( resElem != sourceElem )
5501 resultElems.push_back( resElem );
5502 // do not generate element groups from node ones
5503 if ( sourceElem->GetType() == SMDSAbs_Node &&
5504 elems( iElem )->GetType() != SMDSAbs_Node )
5507 // add resultElems to groups made by ones the sourceElem belongs to
5508 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5509 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5511 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5512 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5514 SMDS_MeshGroup* & newGroup = gOldNew->second;
5515 if ( !newGroup )// create a new group
5518 string name = oldGroup->GetStoreName();
5519 if ( !targetMesh ) {
5523 while ( !groupNames.insert( name ).second ) // name exists
5529 TCollection_AsciiString nbStr(nb+1);
5530 name.resize( name.rfind('_')+1 );
5531 name += nbStr.ToCString();
5538 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5540 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5541 newGroup = & groupDS->SMDSGroup();
5542 newGroupIDs->push_back( id );
5545 // fill in a new group
5546 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5547 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5548 newGroup->Add( *resElemIt );
5551 } // loop on created elements
5552 }// loop on nodes and elements
5557 //================================================================================
5559 * \brief Return list of group of nodes close to each other within theTolerance
5560 * Search among theNodes or in the whole mesh if theNodes is empty using
5561 * an Octree algorithm
5563 //================================================================================
5565 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5566 const double theTolerance,
5567 TListOfListOfNodes & theGroupsOfNodes)
5569 myLastCreatedElems.Clear();
5570 myLastCreatedNodes.Clear();
5572 set<const SMDS_MeshNode*> nodes;
5573 if ( theNodes.empty() )
5574 { // get all nodes in the mesh
5575 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5576 while ( nIt->more() )
5577 nodes.insert( nodes.end(),nIt->next());
5582 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5586 //=======================================================================
5588 * \brief Implementation of search for the node closest to point
5590 //=======================================================================
5592 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5594 //---------------------------------------------------------------------
5596 * \brief Constructor
5598 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5600 myMesh = ( SMESHDS_Mesh* ) theMesh;
5602 set<const SMDS_MeshNode*> nodes;
5604 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5605 while ( nIt->more() )
5606 nodes.insert( nodes.end(), nIt->next() );
5608 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5610 // get max size of a leaf box
5611 SMESH_OctreeNode* tree = myOctreeNode;
5612 while ( !tree->isLeaf() )
5614 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5618 myHalfLeafSize = tree->maxSize() / 2.;
5621 //---------------------------------------------------------------------
5623 * \brief Move node and update myOctreeNode accordingly
5625 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5627 myOctreeNode->UpdateByMoveNode( node, toPnt );
5628 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5631 //---------------------------------------------------------------------
5633 * \brief Do it's job
5635 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5637 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5638 map<double, const SMDS_MeshNode*> dist2Nodes;
5639 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5640 if ( !dist2Nodes.empty() )
5641 return dist2Nodes.begin()->second;
5642 list<const SMDS_MeshNode*> nodes;
5643 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5645 double minSqDist = DBL_MAX;
5646 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5648 // sort leafs by their distance from thePnt
5649 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5650 TDistTreeMap treeMap;
5651 list< SMESH_OctreeNode* > treeList;
5652 list< SMESH_OctreeNode* >::iterator trIt;
5653 treeList.push_back( myOctreeNode );
5655 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5656 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5658 SMESH_OctreeNode* tree = *trIt;
5659 if ( !tree->isLeaf() ) // put children to the queue
5661 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5662 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5663 while ( cIt->more() )
5664 treeList.push_back( cIt->next() );
5666 else if ( tree->NbNodes() ) // put a tree to the treeMap
5668 const Bnd_B3d& box = tree->getBox();
5669 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5670 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5671 if ( !it_in.second ) // not unique distance to box center
5672 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5675 // find distance after which there is no sense to check tree's
5676 double sqLimit = DBL_MAX;
5677 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5678 if ( treeMap.size() > 5 ) {
5679 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5680 const Bnd_B3d& box = closestTree->getBox();
5681 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5682 sqLimit = limit * limit;
5684 // get all nodes from trees
5685 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5686 if ( sqDist_tree->first > sqLimit )
5688 SMESH_OctreeNode* tree = sqDist_tree->second;
5689 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5692 // find closest among nodes
5693 minSqDist = DBL_MAX;
5694 const SMDS_MeshNode* closestNode = 0;
5695 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5696 for ( ; nIt != nodes.end(); ++nIt ) {
5697 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5698 if ( minSqDist > sqDist ) {
5706 //---------------------------------------------------------------------
5710 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5712 //---------------------------------------------------------------------
5714 * \brief Return the node tree
5716 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5719 SMESH_OctreeNode* myOctreeNode;
5720 SMESHDS_Mesh* myMesh;
5721 double myHalfLeafSize; // max size of a leaf box
5724 //=======================================================================
5726 * \brief Return SMESH_NodeSearcher
5728 //=======================================================================
5730 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5732 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5735 // ========================================================================
5736 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5738 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5739 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5740 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5742 //=======================================================================
5744 * \brief Octal tree of bounding boxes of elements
5746 //=======================================================================
5748 class ElementBndBoxTree : public SMESH_Octree
5752 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5753 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5754 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5755 ~ElementBndBoxTree();
5758 ElementBndBoxTree() {}
5759 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5760 void buildChildrenData();
5761 Bnd_B3d* buildRootBox();
5763 //!< Bounding box of element
5764 struct ElementBox : public Bnd_B3d
5766 const SMDS_MeshElement* _element;
5767 int _refCount; // an ElementBox can be included in several tree branches
5768 ElementBox(const SMDS_MeshElement* elem);
5770 vector< ElementBox* > _elements;
5773 //================================================================================
5775 * \brief ElementBndBoxTree creation
5777 //================================================================================
5779 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5780 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5782 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5783 _elements.reserve( nbElems );
5785 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5786 while ( elemIt->more() )
5787 _elements.push_back( new ElementBox( elemIt->next() ));
5789 if ( _elements.size() > MaxNbElemsInLeaf )
5795 //================================================================================
5799 //================================================================================
5801 ElementBndBoxTree::~ElementBndBoxTree()
5803 for ( int i = 0; i < _elements.size(); ++i )
5804 if ( --_elements[i]->_refCount <= 0 )
5805 delete _elements[i];
5808 //================================================================================
5810 * \brief Return the maximal box
5812 //================================================================================
5814 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5816 Bnd_B3d* box = new Bnd_B3d;
5817 for ( int i = 0; i < _elements.size(); ++i )
5818 box->Add( *_elements[i] );
5822 //================================================================================
5824 * \brief Redistrubute element boxes among children
5826 //================================================================================
5828 void ElementBndBoxTree::buildChildrenData()
5830 for ( int i = 0; i < _elements.size(); ++i )
5832 for (int j = 0; j < 8; j++)
5834 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5836 _elements[i]->_refCount++;
5837 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5840 _elements[i]->_refCount--;
5844 for (int j = 0; j < 8; j++)
5846 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5847 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5848 child->myIsLeaf = true;
5850 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5851 child->_elements.resize( child->_elements.size() ); // compact
5855 //================================================================================
5857 * \brief Return elements which can include the point
5859 //================================================================================
5861 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5862 TIDSortedElemSet& foundElems)
5864 if ( level() && getBox().IsOut( point.XYZ() ))
5869 for ( int i = 0; i < _elements.size(); ++i )
5870 if ( !_elements[i]->IsOut( point.XYZ() ))
5871 foundElems.insert( _elements[i]->_element );
5875 for (int i = 0; i < 8; i++)
5876 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5880 //================================================================================
5882 * \brief Return elements which can be intersected by the line
5884 //================================================================================
5886 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
5887 TIDSortedElemSet& foundElems)
5889 if ( level() && getBox().IsOut( line ))
5894 for ( int i = 0; i < _elements.size(); ++i )
5895 if ( !_elements[i]->IsOut( line ))
5896 foundElems.insert( _elements[i]->_element );
5900 for (int i = 0; i < 8; i++)
5901 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
5905 //================================================================================
5907 * \brief Construct the element box
5909 //================================================================================
5911 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5915 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5916 while ( nIt->more() )
5917 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5918 Enlarge( NodeRadius );
5923 //=======================================================================
5925 * \brief Implementation of search for the elements by point and
5926 * of classification of point in 2D mesh
5928 //=======================================================================
5930 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5932 SMESHDS_Mesh* _mesh;
5933 ElementBndBoxTree* _ebbTree;
5934 SMESH_NodeSearcherImpl* _nodeSearcher;
5935 SMDSAbs_ElementType _elementType;
5937 set<const SMDS_MeshElement*> _internalFaces;
5939 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
5940 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1) {}
5941 ~SMESH_ElementSearcherImpl()
5943 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5944 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5946 virtual int FindElementsByPoint(const gp_Pnt& point,
5947 SMDSAbs_ElementType type,
5948 vector< const SMDS_MeshElement* >& foundElements);
5949 virtual TopAbs_State GetPointState(const gp_Pnt& point);
5951 struct TInters //!< data of intersection of the line and the mesh face
5953 const SMDS_MeshElement* _face;
5955 bool _coincides; //!< the line lays in face plane
5956 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
5957 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
5959 double getTolerance();
5960 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
5961 const double tolerance, double & param);
5962 void findOuterBoundary();
5963 bool isOuterBoundary(const SMDS_MeshElement* face) const { return !_internalFaces.count(face);}
5966 //=======================================================================
5968 * \brief define tolerance for search
5970 //=======================================================================
5972 double SMESH_ElementSearcherImpl::getTolerance()
5974 if ( _tolerance < 0 )
5976 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5979 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5981 double boxSize = _nodeSearcher->getTree()->maxSize();
5982 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
5984 else if ( _ebbTree && meshInfo.NbElements() > 0 )
5986 double boxSize = _ebbTree->maxSize();
5987 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
5989 if ( _tolerance == 0 )
5991 // define tolerance by size of a most complex element
5992 int complexType = SMDSAbs_Volume;
5993 while ( complexType > SMDSAbs_All &&
5994 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
5996 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
5999 if ( complexType == int( SMDSAbs_Node ))
6001 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6003 if ( meshInfo.NbNodes() > 2 )
6004 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6008 const SMDS_MeshElement* elem =
6009 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6010 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6011 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6012 while ( nodeIt->more() )
6014 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6015 elemSize = max( dist, elemSize );
6018 _tolerance = 1e-6 * elemSize;
6024 //================================================================================
6026 * \brief Find intersection of the line and an edge of face and return parameter on line
6028 //================================================================================
6030 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6031 const SMDS_MeshElement* face,
6038 GeomAPI_ExtremaCurveCurve anExtCC;
6039 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6041 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6042 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6044 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6045 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6046 anExtCC.Init( lineCurve, edge);
6047 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6049 Quantity_Parameter pl, pe;
6050 anExtCC.LowerDistanceParameters( pl, pe );
6052 if ( ++nbInts == 2 )
6056 if ( nbInts > 0 ) param /= nbInts;
6059 //================================================================================
6061 * \brief Find all faces belonging to the outer boundary of mesh
6063 //================================================================================
6065 void SMESH_ElementSearcherImpl::findOuterBoundary()
6070 //=======================================================================
6072 * \brief Find elements of given type where the given point is IN or ON.
6073 * Returns nb of found elements and elements them-selves.
6075 * 'ALL' type means elements of any type excluding nodes and 0D elements
6077 //=======================================================================
6079 int SMESH_ElementSearcherImpl::
6080 FindElementsByPoint(const gp_Pnt& point,
6081 SMDSAbs_ElementType type,
6082 vector< const SMDS_MeshElement* >& foundElements)
6084 foundElements.clear();
6086 double tolerance = getTolerance();
6088 // =================================================================================
6089 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6091 if ( !_nodeSearcher )
6092 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6094 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6095 if ( !closeNode ) return foundElements.size();
6097 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6098 return foundElements.size(); // to far from any node
6100 if ( type == SMDSAbs_Node )
6102 foundElements.push_back( closeNode );
6106 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6107 while ( elemIt->more() )
6108 foundElements.push_back( elemIt->next() );
6111 // =================================================================================
6112 else // elements more complex than 0D
6114 if ( !_ebbTree || _elementType != type )
6116 if ( _ebbTree ) delete _ebbTree;
6117 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6119 TIDSortedElemSet suspectElems;
6120 _ebbTree->getElementsNearPoint( point, suspectElems );
6121 TIDSortedElemSet::iterator elem = suspectElems.begin();
6122 for ( ; elem != suspectElems.end(); ++elem )
6123 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6124 foundElements.push_back( *elem );
6126 return foundElements.size();
6129 //================================================================================
6131 * \brief Classify the given point in the closed 2D mesh
6133 //================================================================================
6135 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6137 double tolerance = getTolerance();
6138 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6140 if ( _ebbTree ) delete _ebbTree;
6141 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6143 // algo: analyse transition of a line starting at the point through mesh boundary;
6144 // try several lines, if none of attemps gives a clear answer, we give up as the
6145 // task can be too complex including internal boundaries, concave surfaces etc.
6147 const int nbAxes = 3;
6148 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6149 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6150 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6151 multimap< int, int > nbInt2Axis; // to find the simplest case
6152 for ( int axis = 0; axis < nbAxes; ++axis )
6154 gp_Ax1 lineAxis( point, axisDir[axis]);
6155 gp_Lin line ( lineAxis );
6157 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6158 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6160 // Intersect faces with the line
6162 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6163 TIDSortedElemSet::iterator face = suspectFaces.begin();
6164 for ( ; face != suspectFaces.end(); ++face )
6168 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6169 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6172 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6173 if ( !intersection.IsDone() )
6175 if ( intersection.IsInQuadric() )
6177 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6179 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6181 gp_Pnt intersectionPoint = intersection.Point(1);
6182 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6183 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6186 // Analyse intersections roughly
6188 int nbInter = u2inters.size();
6192 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6194 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6196 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6199 if ( (f<0) == (l<0) )
6202 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6203 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6204 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6207 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6209 } // three attempts - loop on CS axes
6211 // Analyse intersections thoroughly
6212 // We make two loops, on the first one we correctly exclude touching intersections,
6213 // on the second, we additionally just throw away intersections with small angles
6215 for ( int angleCheck = 0; angleCheck < 2; ++angleCheck )
6217 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6218 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6220 int axis = nb_axis->second;
6221 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6223 gp_Ax1 lineAxis( point, axisDir[axis]);
6224 gp_Lin line ( lineAxis );
6226 // add tangent intersections to u2inters
6228 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6229 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6230 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6231 u2inters.insert(make_pair( param, *tgtInt ));
6232 tangentInters[ axis ].clear();
6234 // Count intersections before and after the point excluding touching ones.
6236 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6237 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6238 map< double, TInters >::iterator u_int2 = u2inters.begin(), u_int1 = u_int2++;
6239 bool ok = ! u_int1->second._coincides;
6240 while ( ok && u_int1 != u2inters.end() )
6242 // skip intersections at the same point (if line pass through edge or node)
6244 double u = u_int1->first;
6245 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6251 // skip tangent intersections
6253 const SMDS_MeshElement* prevFace = u_int1->second._face;
6254 while ( ok && u_int2->second._coincides )
6256 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6262 ok = ( u_int2 != u2inters.end() );
6267 // skip intersections at the same point after tangent intersections
6270 double u = u_int2->first;
6272 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6279 bool touchingInt = false;
6280 if ( nbSamePnt + nbTgt > 0 )
6282 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6283 map< double, TInters >::iterator u_int = u_int1;
6284 for ( ; u_int != u_int2; ++u_int )
6286 if ( u_int->second._coincides ) continue;
6287 double dot = u_int->second._faceNorm * line.Direction();
6288 if ( dot > maxDot ) maxDot = dot;
6289 if ( dot < minDot ) minDot = dot;
6291 touchingInt = ( minDot*maxDot < 0 );
6293 // throw away intersection with lower angles
6294 if ( !touchingInt && angleCheck )
6296 const double angTol = 2 * Standard_PI180, normAng = Standard_PI / 2;
6297 double angle = u_int1->second._faceNorm.Angle( line.Direction() );
6298 touchingInt = ( fabs( angle - normAng ) < angTol );
6311 u_int1 = u_int2++; // to next intersection
6313 } // loop on intersections with one line
6317 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6320 if ( nbIntBeforePoint + nbIntAfterPoint == 1 )
6321 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6323 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6324 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6326 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6329 if ( (f<0) == (l<0) )
6332 } // loop on intersections of the tree lines - thorough analysis
6333 } // two attempts - with and w/o angleCheck
6335 return TopAbs_UNKNOWN;
6338 //=======================================================================
6340 * \brief Return SMESH_ElementSearcher
6342 //=======================================================================
6344 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6346 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6349 //=======================================================================
6351 * \brief Return true if the point is IN or ON of the element
6353 //=======================================================================
6355 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6357 if ( element->GetType() == SMDSAbs_Volume)
6359 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6362 // get ordered nodes
6364 vector< gp_XYZ > xyz;
6366 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6367 if ( element->IsQuadratic() )
6368 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6369 nodeIt = f->interlacedNodesElemIterator();
6370 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6371 nodeIt = e->interlacedNodesElemIterator();
6373 while ( nodeIt->more() )
6374 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6376 int i, nbNodes = element->NbNodes();
6378 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6380 // compute face normal
6381 gp_Vec faceNorm(0,0,0);
6382 xyz.push_back( xyz.front() );
6383 for ( i = 0; i < nbNodes; ++i )
6385 gp_Vec edge1( xyz[i+1], xyz[i]);
6386 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6387 faceNorm += edge1 ^ edge2;
6389 double normSize = faceNorm.Magnitude();
6390 if ( normSize <= tol )
6392 // degenerated face: point is out if it is out of all face edges
6393 for ( i = 0; i < nbNodes; ++i )
6395 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6396 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6397 SMDS_MeshEdge edge( &n1, &n2 );
6398 if ( !isOut( &edge, point, tol ))
6403 faceNorm /= normSize;
6405 // check if the point lays on face plane
6406 gp_Vec n2p( xyz[0], point );
6407 if ( fabs( n2p * faceNorm ) > tol )
6408 return true; // not on face plane
6410 // check if point is out of face boundary:
6411 // define it by closest transition of a ray point->infinity through face boundary
6412 // on the face plane.
6413 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6414 // to find intersections of the ray with the boundary.
6416 gp_Vec plnNorm = ray ^ faceNorm;
6417 normSize = plnNorm.Magnitude();
6418 if ( normSize <= tol ) return false; // point coincides with the first node
6419 plnNorm /= normSize;
6420 // for each node of the face, compute its signed distance to the plane
6421 vector<double> dist( nbNodes + 1);
6422 for ( i = 0; i < nbNodes; ++i )
6424 gp_Vec n2p( xyz[i], point );
6425 dist[i] = n2p * plnNorm;
6427 dist.back() = dist.front();
6428 // find the closest intersection
6430 double rClosest, distClosest = 1e100;;
6432 for ( i = 0; i < nbNodes; ++i )
6435 if ( fabs( dist[i]) < tol )
6437 else if ( fabs( dist[i+1]) < tol )
6439 else if ( dist[i] * dist[i+1] < 0 )
6440 r = dist[i] / ( dist[i] - dist[i+1] );
6442 continue; // no intersection
6443 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6444 gp_Vec p2int ( point, pInt);
6445 if ( p2int * ray > -tol ) // right half-space
6447 double intDist = p2int.SquareMagnitude();
6448 if ( intDist < distClosest )
6453 distClosest = intDist;
6458 return true; // no intesections - out
6460 // analyse transition
6461 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6462 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6463 gp_Vec p2int ( point, pClosest );
6464 bool out = (edgeNorm * p2int) < -tol;
6465 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6468 // ray pass through a face node; analyze transition through an adjacent edge
6469 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6470 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6471 gp_Vec edgeAdjacent( p1, p2 );
6472 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6473 bool out2 = (edgeNorm2 * p2int) < -tol;
6475 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6476 return covexCorner ? (out || out2) : (out && out2);
6478 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6480 // point is out of edge if it is NOT ON any straight part of edge
6481 // (we consider quadratic edge as being composed of two straight parts)
6482 for ( i = 1; i < nbNodes; ++i )
6484 gp_Vec edge( xyz[i-1], xyz[i]);
6485 gp_Vec n1p ( xyz[i-1], point);
6486 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6489 gp_Vec n2p( xyz[i], point );
6490 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6492 return false; // point is ON this part
6496 // Node or 0D element -------------------------------------------------------------------------
6498 gp_Vec n2p ( xyz[0], point );
6499 return n2p.Magnitude() <= tol;
6504 //=======================================================================
6505 //function : SimplifyFace
6507 //=======================================================================
6508 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6509 vector<const SMDS_MeshNode *>& poly_nodes,
6510 vector<int>& quantities) const
6512 int nbNodes = faceNodes.size();
6517 set<const SMDS_MeshNode*> nodeSet;
6519 // get simple seq of nodes
6520 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6521 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6522 int iSimple = 0, nbUnique = 0;
6524 simpleNodes[iSimple++] = faceNodes[0];
6526 for (int iCur = 1; iCur < nbNodes; iCur++) {
6527 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6528 simpleNodes[iSimple++] = faceNodes[iCur];
6529 if (nodeSet.insert( faceNodes[iCur] ).second)
6533 int nbSimple = iSimple;
6534 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6544 bool foundLoop = (nbSimple > nbUnique);
6547 set<const SMDS_MeshNode*> loopSet;
6548 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6549 const SMDS_MeshNode* n = simpleNodes[iSimple];
6550 if (!loopSet.insert( n ).second) {
6554 int iC = 0, curLast = iSimple;
6555 for (; iC < curLast; iC++) {
6556 if (simpleNodes[iC] == n) break;
6558 int loopLen = curLast - iC;
6560 // create sub-element
6562 quantities.push_back(loopLen);
6563 for (; iC < curLast; iC++) {
6564 poly_nodes.push_back(simpleNodes[iC]);
6567 // shift the rest nodes (place from the first loop position)
6568 for (iC = curLast + 1; iC < nbSimple; iC++) {
6569 simpleNodes[iC - loopLen] = simpleNodes[iC];
6571 nbSimple -= loopLen;
6574 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6575 } // while (foundLoop)
6579 quantities.push_back(iSimple);
6580 for (int i = 0; i < iSimple; i++)
6581 poly_nodes.push_back(simpleNodes[i]);
6587 //=======================================================================
6588 //function : MergeNodes
6589 //purpose : In each group, the cdr of nodes are substituted by the first one
6591 //=======================================================================
6593 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6595 myLastCreatedElems.Clear();
6596 myLastCreatedNodes.Clear();
6598 SMESHDS_Mesh* aMesh = GetMeshDS();
6600 TNodeNodeMap nodeNodeMap; // node to replace - new node
6601 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6602 list< int > rmElemIds, rmNodeIds;
6604 // Fill nodeNodeMap and elems
6606 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6607 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6608 list<const SMDS_MeshNode*>& nodes = *grIt;
6609 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6610 const SMDS_MeshNode* nToKeep = *nIt;
6611 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6612 const SMDS_MeshNode* nToRemove = *nIt;
6613 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6614 if ( nToRemove != nToKeep ) {
6615 rmNodeIds.push_back( nToRemove->GetID() );
6616 AddToSameGroups( nToKeep, nToRemove, aMesh );
6619 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6620 while ( invElemIt->more() ) {
6621 const SMDS_MeshElement* elem = invElemIt->next();
6626 // Change element nodes or remove an element
6628 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6629 for ( ; eIt != elems.end(); eIt++ ) {
6630 const SMDS_MeshElement* elem = *eIt;
6631 int nbNodes = elem->NbNodes();
6632 int aShapeId = FindShape( elem );
6634 set<const SMDS_MeshNode*> nodeSet;
6635 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6636 int iUnique = 0, iCur = 0, nbRepl = 0;
6637 vector<int> iRepl( nbNodes );
6639 // get new seq of nodes
6640 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6641 while ( itN->more() ) {
6642 const SMDS_MeshNode* n =
6643 static_cast<const SMDS_MeshNode*>( itN->next() );
6645 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6646 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6648 // BUG 0020185: begin
6650 bool stopRecur = false;
6651 set<const SMDS_MeshNode*> nodesRecur;
6652 nodesRecur.insert(n);
6653 while (!stopRecur) {
6654 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6655 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6656 n = (*nnIt_i).second;
6657 if (!nodesRecur.insert(n).second) {
6658 // error: recursive dependancy
6667 iRepl[ nbRepl++ ] = iCur;
6669 curNodes[ iCur ] = n;
6670 bool isUnique = nodeSet.insert( n ).second;
6672 uniqueNodes[ iUnique++ ] = n;
6676 // Analyse element topology after replacement
6679 int nbUniqueNodes = nodeSet.size();
6680 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6681 // Polygons and Polyhedral volumes
6682 if (elem->IsPoly()) {
6684 if (elem->GetType() == SMDSAbs_Face) {
6686 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6688 for (; inode < nbNodes; inode++) {
6689 face_nodes[inode] = curNodes[inode];
6692 vector<const SMDS_MeshNode *> polygons_nodes;
6693 vector<int> quantities;
6694 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6698 for (int iface = 0; iface < nbNew - 1; iface++) {
6699 int nbNodes = quantities[iface];
6700 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6701 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6702 poly_nodes[ii] = polygons_nodes[inode];
6704 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6705 myLastCreatedElems.Append(newElem);
6707 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6709 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6712 rmElemIds.push_back(elem->GetID());
6716 else if (elem->GetType() == SMDSAbs_Volume) {
6717 // Polyhedral volume
6718 if (nbUniqueNodes < 4) {
6719 rmElemIds.push_back(elem->GetID());
6722 // each face has to be analized in order to check volume validity
6723 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6724 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6726 int nbFaces = aPolyedre->NbFaces();
6728 vector<const SMDS_MeshNode *> poly_nodes;
6729 vector<int> quantities;
6731 for (int iface = 1; iface <= nbFaces; iface++) {
6732 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6733 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6735 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6736 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6737 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6738 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6739 faceNode = (*nnIt).second;
6741 faceNodes[inode - 1] = faceNode;
6744 SimplifyFace(faceNodes, poly_nodes, quantities);
6747 if (quantities.size() > 3) {
6748 // to be done: remove coincident faces
6751 if (quantities.size() > 3)
6752 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6754 rmElemIds.push_back(elem->GetID());
6758 rmElemIds.push_back(elem->GetID());
6769 switch ( nbNodes ) {
6770 case 2: ///////////////////////////////////// EDGE
6771 isOk = false; break;
6772 case 3: ///////////////////////////////////// TRIANGLE
6773 isOk = false; break;
6775 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6777 else { //////////////////////////////////// QUADRANGLE
6778 if ( nbUniqueNodes < 3 )
6780 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6781 isOk = false; // opposite nodes stick
6784 case 6: ///////////////////////////////////// PENTAHEDRON
6785 if ( nbUniqueNodes == 4 ) {
6786 // ---------------------------------> tetrahedron
6788 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6789 // all top nodes stick: reverse a bottom
6790 uniqueNodes[ 0 ] = curNodes [ 1 ];
6791 uniqueNodes[ 1 ] = curNodes [ 0 ];
6793 else if (nbRepl == 3 &&
6794 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6795 // all bottom nodes stick: set a top before
6796 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6797 uniqueNodes[ 0 ] = curNodes [ 3 ];
6798 uniqueNodes[ 1 ] = curNodes [ 4 ];
6799 uniqueNodes[ 2 ] = curNodes [ 5 ];
6801 else if (nbRepl == 4 &&
6802 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6803 // a lateral face turns into a line: reverse a bottom
6804 uniqueNodes[ 0 ] = curNodes [ 1 ];
6805 uniqueNodes[ 1 ] = curNodes [ 0 ];
6810 else if ( nbUniqueNodes == 5 ) {
6811 // PENTAHEDRON --------------------> 2 tetrahedrons
6812 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6813 // a bottom node sticks with a linked top one
6815 SMDS_MeshElement* newElem =
6816 aMesh->AddVolume(curNodes[ 3 ],
6819 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6820 myLastCreatedElems.Append(newElem);
6822 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6823 // 2. : reverse a bottom
6824 uniqueNodes[ 0 ] = curNodes [ 1 ];
6825 uniqueNodes[ 1 ] = curNodes [ 0 ];
6835 if(elem->IsQuadratic()) { // Quadratic quadrangle
6848 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6849 uniqueNodes[0] = curNodes[0];
6850 uniqueNodes[1] = curNodes[2];
6851 uniqueNodes[2] = curNodes[3];
6852 uniqueNodes[3] = curNodes[5];
6853 uniqueNodes[4] = curNodes[6];
6854 uniqueNodes[5] = curNodes[7];
6857 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6858 uniqueNodes[0] = curNodes[0];
6859 uniqueNodes[1] = curNodes[1];
6860 uniqueNodes[2] = curNodes[2];
6861 uniqueNodes[3] = curNodes[4];
6862 uniqueNodes[4] = curNodes[5];
6863 uniqueNodes[5] = curNodes[6];
6866 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6867 uniqueNodes[0] = curNodes[1];
6868 uniqueNodes[1] = curNodes[2];
6869 uniqueNodes[2] = curNodes[3];
6870 uniqueNodes[3] = curNodes[5];
6871 uniqueNodes[4] = curNodes[6];
6872 uniqueNodes[5] = curNodes[0];
6875 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6876 uniqueNodes[0] = curNodes[0];
6877 uniqueNodes[1] = curNodes[1];
6878 uniqueNodes[2] = curNodes[3];
6879 uniqueNodes[3] = curNodes[4];
6880 uniqueNodes[4] = curNodes[6];
6881 uniqueNodes[5] = curNodes[7];
6884 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
6885 uniqueNodes[0] = curNodes[0];
6886 uniqueNodes[1] = curNodes[2];
6887 uniqueNodes[2] = curNodes[3];
6888 uniqueNodes[3] = curNodes[1];
6889 uniqueNodes[4] = curNodes[6];
6890 uniqueNodes[5] = curNodes[7];
6893 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
6894 uniqueNodes[0] = curNodes[0];
6895 uniqueNodes[1] = curNodes[1];
6896 uniqueNodes[2] = curNodes[2];
6897 uniqueNodes[3] = curNodes[4];
6898 uniqueNodes[4] = curNodes[5];
6899 uniqueNodes[5] = curNodes[7];
6902 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
6903 uniqueNodes[0] = curNodes[0];
6904 uniqueNodes[1] = curNodes[1];
6905 uniqueNodes[2] = curNodes[3];
6906 uniqueNodes[3] = curNodes[4];
6907 uniqueNodes[4] = curNodes[2];
6908 uniqueNodes[5] = curNodes[7];
6911 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
6912 uniqueNodes[0] = curNodes[0];
6913 uniqueNodes[1] = curNodes[1];
6914 uniqueNodes[2] = curNodes[2];
6915 uniqueNodes[3] = curNodes[4];
6916 uniqueNodes[4] = curNodes[5];
6917 uniqueNodes[5] = curNodes[3];
6923 //////////////////////////////////// HEXAHEDRON
6925 SMDS_VolumeTool hexa (elem);
6926 hexa.SetExternalNormal();
6927 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
6928 //////////////////////// ---> tetrahedron
6929 for ( int iFace = 0; iFace < 6; iFace++ ) {
6930 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6931 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6932 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6933 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6934 // one face turns into a point ...
6935 int iOppFace = hexa.GetOppFaceIndex( iFace );
6936 ind = hexa.GetFaceNodesIndices( iOppFace );
6938 iUnique = 2; // reverse a tetrahedron bottom
6939 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
6940 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6942 else if ( iUnique >= 0 )
6943 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6945 if ( nbStick == 1 ) {
6946 // ... and the opposite one - into a triangle.
6948 ind = hexa.GetFaceNodesIndices( iFace );
6949 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
6956 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
6957 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
6958 for ( int iFace = 0; iFace < 6; iFace++ ) {
6959 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
6960 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
6961 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
6962 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
6963 // one face turns into a point ...
6964 int iOppFace = hexa.GetOppFaceIndex( iFace );
6965 ind = hexa.GetFaceNodesIndices( iOppFace );
6967 iUnique = 2; // reverse a tetrahedron 1 bottom
6968 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
6969 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
6971 else if ( iUnique >= 0 )
6972 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
6974 if ( nbStick == 0 ) {
6975 // ... and the opposite one is a quadrangle
6977 const int* indTop = hexa.GetFaceNodesIndices( iFace );
6978 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
6981 SMDS_MeshElement* newElem =
6982 aMesh->AddVolume(curNodes[ind[ 0 ]],
6985 curNodes[indTop[ 0 ]]);
6986 myLastCreatedElems.Append(newElem);
6988 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6995 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
6996 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
6997 // find indices of quad and tri faces
6998 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
6999 for ( iFace = 0; iFace < 6; iFace++ ) {
7000 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7002 for ( iCur = 0; iCur < 4; iCur++ )
7003 nodeSet.insert( curNodes[ind[ iCur ]] );
7004 nbUniqueNodes = nodeSet.size();
7005 if ( nbUniqueNodes == 3 )
7006 iTriFace[ nbTri++ ] = iFace;
7007 else if ( nbUniqueNodes == 4 )
7008 iQuadFace[ nbQuad++ ] = iFace;
7010 if (nbQuad == 2 && nbTri == 4 &&
7011 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7012 // 2 opposite quadrangles stuck with a diagonal;
7013 // sample groups of merged indices: (0-4)(2-6)
7014 // --------------------------------------------> 2 tetrahedrons
7015 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7016 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7017 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7018 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7019 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7020 // stuck with 0-2 diagonal
7028 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7029 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7030 // stuck with 1-3 diagonal
7042 uniqueNodes[ 0 ] = curNodes [ i0 ];
7043 uniqueNodes[ 1 ] = curNodes [ i1d ];
7044 uniqueNodes[ 2 ] = curNodes [ i3d ];
7045 uniqueNodes[ 3 ] = curNodes [ i0t ];
7048 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7052 myLastCreatedElems.Append(newElem);
7054 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7057 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7058 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7059 // --------------------------------------------> prism
7060 // find 2 opposite triangles
7062 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7063 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7064 // find indices of kept and replaced nodes
7065 // and fill unique nodes of 2 opposite triangles
7066 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7067 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7068 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7069 // fill unique nodes
7072 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7073 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7074 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7076 // iCur of a linked node of the opposite face (make normals co-directed):
7077 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7078 // check that correspondent corners of triangles are linked
7079 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7082 uniqueNodes[ iUnique ] = n;
7083 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7092 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7098 } // switch ( nbNodes )
7100 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7103 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7104 // Change nodes of polyedre
7105 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7106 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7108 int nbFaces = aPolyedre->NbFaces();
7110 vector<const SMDS_MeshNode *> poly_nodes;
7111 vector<int> quantities (nbFaces);
7113 for (int iface = 1; iface <= nbFaces; iface++) {
7114 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7115 quantities[iface - 1] = nbFaceNodes;
7117 for (inode = 1; inode <= nbFaceNodes; inode++) {
7118 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7120 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7121 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7122 curNode = (*nnIt).second;
7124 poly_nodes.push_back(curNode);
7127 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7131 // Change regular element or polygon
7132 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7136 // Remove invalid regular element or invalid polygon
7137 rmElemIds.push_back( elem->GetID() );
7140 } // loop on elements
7142 // Remove equal nodes and bad elements
7144 Remove( rmNodeIds, true );
7145 Remove( rmElemIds, false );
7150 // ========================================================
7151 // class : SortableElement
7152 // purpose : allow sorting elements basing on their nodes
7153 // ========================================================
7154 class SortableElement : public set <const SMDS_MeshElement*>
7158 SortableElement( const SMDS_MeshElement* theElem )
7161 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7162 while ( nodeIt->more() )
7163 this->insert( nodeIt->next() );
7166 const SMDS_MeshElement* Get() const
7169 void Set(const SMDS_MeshElement* e) const
7174 mutable const SMDS_MeshElement* myElem;
7177 //=======================================================================
7178 //function : FindEqualElements
7179 //purpose : Return list of group of elements built on the same nodes.
7180 // Search among theElements or in the whole mesh if theElements is empty
7181 //=======================================================================
7182 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7183 TListOfListOfElementsID & theGroupsOfElementsID)
7185 myLastCreatedElems.Clear();
7186 myLastCreatedNodes.Clear();
7188 typedef set<const SMDS_MeshElement*> TElemsSet;
7189 typedef map< SortableElement, int > TMapOfNodeSet;
7190 typedef list<int> TGroupOfElems;
7193 if ( theElements.empty() )
7194 { // get all elements in the mesh
7195 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7196 while ( eIt->more() )
7197 elems.insert( elems.end(), eIt->next());
7200 elems = theElements;
7202 vector< TGroupOfElems > arrayOfGroups;
7203 TGroupOfElems groupOfElems;
7204 TMapOfNodeSet mapOfNodeSet;
7206 TElemsSet::iterator elemIt = elems.begin();
7207 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7208 const SMDS_MeshElement* curElem = *elemIt;
7209 SortableElement SE(curElem);
7212 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7213 if( !(pp.second) ) {
7214 TMapOfNodeSet::iterator& itSE = pp.first;
7215 ind = (*itSE).second;
7216 arrayOfGroups[ind].push_back(curElem->GetID());
7219 groupOfElems.clear();
7220 groupOfElems.push_back(curElem->GetID());
7221 arrayOfGroups.push_back(groupOfElems);
7226 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7227 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7228 groupOfElems = *groupIt;
7229 if ( groupOfElems.size() > 1 ) {
7230 groupOfElems.sort();
7231 theGroupsOfElementsID.push_back(groupOfElems);
7236 //=======================================================================
7237 //function : MergeElements
7238 //purpose : In each given group, substitute all elements by the first one.
7239 //=======================================================================
7241 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7243 myLastCreatedElems.Clear();
7244 myLastCreatedNodes.Clear();
7246 typedef list<int> TListOfIDs;
7247 TListOfIDs rmElemIds; // IDs of elems to remove
7249 SMESHDS_Mesh* aMesh = GetMeshDS();
7251 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7252 while ( groupsIt != theGroupsOfElementsID.end() ) {
7253 TListOfIDs& aGroupOfElemID = *groupsIt;
7254 aGroupOfElemID.sort();
7255 int elemIDToKeep = aGroupOfElemID.front();
7256 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7257 aGroupOfElemID.pop_front();
7258 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7259 while ( idIt != aGroupOfElemID.end() ) {
7260 int elemIDToRemove = *idIt;
7261 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7262 // add the kept element in groups of removed one (PAL15188)
7263 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7264 rmElemIds.push_back( elemIDToRemove );
7270 Remove( rmElemIds, false );
7273 //=======================================================================
7274 //function : MergeEqualElements
7275 //purpose : Remove all but one of elements built on the same nodes.
7276 //=======================================================================
7278 void SMESH_MeshEditor::MergeEqualElements()
7280 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7281 to merge equal elements in the whole mesh */
7282 TListOfListOfElementsID aGroupsOfElementsID;
7283 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7284 MergeElements(aGroupsOfElementsID);
7287 //=======================================================================
7288 //function : FindFaceInSet
7289 //purpose : Return a face having linked nodes n1 and n2 and which is
7290 // - not in avoidSet,
7291 // - in elemSet provided that !elemSet.empty()
7292 // i1 and i2 optionally returns indices of n1 and n2
7293 //=======================================================================
7295 const SMDS_MeshElement*
7296 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7297 const SMDS_MeshNode* n2,
7298 const TIDSortedElemSet& elemSet,
7299 const TIDSortedElemSet& avoidSet,
7305 const SMDS_MeshElement* face = 0;
7307 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7308 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7310 const SMDS_MeshElement* elem = invElemIt->next();
7311 if (avoidSet.count( elem ))
7313 if ( !elemSet.empty() && !elemSet.count( elem ))
7316 i1 = elem->GetNodeIndex( n1 );
7317 // find a n2 linked to n1
7318 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7319 for ( int di = -1; di < 2 && !face; di += 2 )
7321 i2 = (i1+di+nbN) % nbN;
7322 if ( elem->GetNode( i2 ) == n2 )
7325 if ( !face && elem->IsQuadratic())
7327 // analysis for quadratic elements using all nodes
7328 const SMDS_QuadraticFaceOfNodes* F =
7329 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7330 // use special nodes iterator
7331 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7332 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7333 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7335 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7336 if ( n1 == prevN && n2 == n )
7340 else if ( n2 == prevN && n1 == n )
7342 face = elem; swap( i1, i2 );
7348 if ( n1ind ) *n1ind = i1;
7349 if ( n2ind ) *n2ind = i2;
7353 //=======================================================================
7354 //function : findAdjacentFace
7356 //=======================================================================
7358 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7359 const SMDS_MeshNode* n2,
7360 const SMDS_MeshElement* elem)
7362 TIDSortedElemSet elemSet, avoidSet;
7364 avoidSet.insert ( elem );
7365 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7368 //=======================================================================
7369 //function : FindFreeBorder
7371 //=======================================================================
7373 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7375 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7376 const SMDS_MeshNode* theSecondNode,
7377 const SMDS_MeshNode* theLastNode,
7378 list< const SMDS_MeshNode* > & theNodes,
7379 list< const SMDS_MeshElement* >& theFaces)
7381 if ( !theFirstNode || !theSecondNode )
7383 // find border face between theFirstNode and theSecondNode
7384 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7388 theFaces.push_back( curElem );
7389 theNodes.push_back( theFirstNode );
7390 theNodes.push_back( theSecondNode );
7392 //vector<const SMDS_MeshNode*> nodes;
7393 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7394 TIDSortedElemSet foundElems;
7395 bool needTheLast = ( theLastNode != 0 );
7397 while ( nStart != theLastNode ) {
7398 if ( nStart == theFirstNode )
7399 return !needTheLast;
7401 // find all free border faces sharing form nStart
7403 list< const SMDS_MeshElement* > curElemList;
7404 list< const SMDS_MeshNode* > nStartList;
7405 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7406 while ( invElemIt->more() ) {
7407 const SMDS_MeshElement* e = invElemIt->next();
7408 if ( e == curElem || foundElems.insert( e ).second ) {
7410 int iNode = 0, nbNodes = e->NbNodes();
7411 //const SMDS_MeshNode* nodes[nbNodes+1];
7412 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7414 if(e->IsQuadratic()) {
7415 const SMDS_QuadraticFaceOfNodes* F =
7416 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7417 // use special nodes iterator
7418 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7419 while( anIter->more() ) {
7420 nodes[ iNode++ ] = anIter->next();
7424 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7425 while ( nIt->more() )
7426 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7428 nodes[ iNode ] = nodes[ 0 ];
7430 for ( iNode = 0; iNode < nbNodes; iNode++ )
7431 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7432 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7433 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7435 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7436 curElemList.push_back( e );
7440 // analyse the found
7442 int nbNewBorders = curElemList.size();
7443 if ( nbNewBorders == 0 ) {
7444 // no free border furthermore
7445 return !needTheLast;
7447 else if ( nbNewBorders == 1 ) {
7448 // one more element found
7450 nStart = nStartList.front();
7451 curElem = curElemList.front();
7452 theFaces.push_back( curElem );
7453 theNodes.push_back( nStart );
7456 // several continuations found
7457 list< const SMDS_MeshElement* >::iterator curElemIt;
7458 list< const SMDS_MeshNode* >::iterator nStartIt;
7459 // check if one of them reached the last node
7460 if ( needTheLast ) {
7461 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7462 curElemIt!= curElemList.end();
7463 curElemIt++, nStartIt++ )
7464 if ( *nStartIt == theLastNode ) {
7465 theFaces.push_back( *curElemIt );
7466 theNodes.push_back( *nStartIt );
7470 // find the best free border by the continuations
7471 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7472 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7473 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7474 curElemIt!= curElemList.end();
7475 curElemIt++, nStartIt++ )
7477 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7478 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7479 // find one more free border
7480 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7484 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7485 // choice: clear a worse one
7486 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7487 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7488 contNodes[ iWorse ].clear();
7489 contFaces[ iWorse ].clear();
7492 if ( contNodes[0].empty() && contNodes[1].empty() )
7495 // append the best free border
7496 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7497 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7498 theNodes.pop_back(); // remove nIgnore
7499 theNodes.pop_back(); // remove nStart
7500 theFaces.pop_back(); // remove curElem
7501 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7502 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7503 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7504 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7507 } // several continuations found
7508 } // while ( nStart != theLastNode )
7513 //=======================================================================
7514 //function : CheckFreeBorderNodes
7515 //purpose : Return true if the tree nodes are on a free border
7516 //=======================================================================
7518 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7519 const SMDS_MeshNode* theNode2,
7520 const SMDS_MeshNode* theNode3)
7522 list< const SMDS_MeshNode* > nodes;
7523 list< const SMDS_MeshElement* > faces;
7524 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7527 //=======================================================================
7528 //function : SewFreeBorder
7530 //=======================================================================
7532 SMESH_MeshEditor::Sew_Error
7533 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7534 const SMDS_MeshNode* theBordSecondNode,
7535 const SMDS_MeshNode* theBordLastNode,
7536 const SMDS_MeshNode* theSideFirstNode,
7537 const SMDS_MeshNode* theSideSecondNode,
7538 const SMDS_MeshNode* theSideThirdNode,
7539 const bool theSideIsFreeBorder,
7540 const bool toCreatePolygons,
7541 const bool toCreatePolyedrs)
7543 myLastCreatedElems.Clear();
7544 myLastCreatedNodes.Clear();
7546 MESSAGE("::SewFreeBorder()");
7547 Sew_Error aResult = SEW_OK;
7549 // ====================================
7550 // find side nodes and elements
7551 // ====================================
7553 list< const SMDS_MeshNode* > nSide[ 2 ];
7554 list< const SMDS_MeshElement* > eSide[ 2 ];
7555 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7556 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7560 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7561 nSide[0], eSide[0])) {
7562 MESSAGE(" Free Border 1 not found " );
7563 aResult = SEW_BORDER1_NOT_FOUND;
7565 if (theSideIsFreeBorder) {
7568 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7569 nSide[1], eSide[1])) {
7570 MESSAGE(" Free Border 2 not found " );
7571 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7574 if ( aResult != SEW_OK )
7577 if (!theSideIsFreeBorder) {
7581 // -------------------------------------------------------------------------
7583 // 1. If nodes to merge are not coincident, move nodes of the free border
7584 // from the coord sys defined by the direction from the first to last
7585 // nodes of the border to the correspondent sys of the side 2
7586 // 2. On the side 2, find the links most co-directed with the correspondent
7587 // links of the free border
7588 // -------------------------------------------------------------------------
7590 // 1. Since sewing may brake if there are volumes to split on the side 2,
7591 // we wont move nodes but just compute new coordinates for them
7592 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7593 TNodeXYZMap nBordXYZ;
7594 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7595 list< const SMDS_MeshNode* >::iterator nBordIt;
7597 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7598 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7599 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7600 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7601 double tol2 = 1.e-8;
7602 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7603 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7604 // Need node movement.
7606 // find X and Z axes to create trsf
7607 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7609 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7611 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7614 gp_Ax3 toBordAx( Pb1, Zb, X );
7615 gp_Ax3 fromSideAx( Ps1, Zs, X );
7616 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7618 gp_Trsf toBordSys, fromSide2Sys;
7619 toBordSys.SetTransformation( toBordAx );
7620 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7621 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7624 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7625 const SMDS_MeshNode* n = *nBordIt;
7626 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7627 toBordSys.Transforms( xyz );
7628 fromSide2Sys.Transforms( xyz );
7629 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7633 // just insert nodes XYZ in the nBordXYZ map
7634 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7635 const SMDS_MeshNode* n = *nBordIt;
7636 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7640 // 2. On the side 2, find the links most co-directed with the correspondent
7641 // links of the free border
7643 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7644 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7645 sideNodes.push_back( theSideFirstNode );
7647 bool hasVolumes = false;
7648 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7649 set<long> foundSideLinkIDs, checkedLinkIDs;
7650 SMDS_VolumeTool volume;
7651 //const SMDS_MeshNode* faceNodes[ 4 ];
7653 const SMDS_MeshNode* sideNode;
7654 const SMDS_MeshElement* sideElem;
7655 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7656 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7657 nBordIt = bordNodes.begin();
7659 // border node position and border link direction to compare with
7660 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7661 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7662 // choose next side node by link direction or by closeness to
7663 // the current border node:
7664 bool searchByDir = ( *nBordIt != theBordLastNode );
7666 // find the next node on the Side 2
7668 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7670 checkedLinkIDs.clear();
7671 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7673 // loop on inverse elements of current node (prevSideNode) on the Side 2
7674 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7675 while ( invElemIt->more() )
7677 const SMDS_MeshElement* elem = invElemIt->next();
7678 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7679 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7680 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7681 bool isVolume = volume.Set( elem );
7682 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7683 if ( isVolume ) // --volume
7685 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7686 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7687 if(elem->IsQuadratic()) {
7688 const SMDS_QuadraticFaceOfNodes* F =
7689 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7690 // use special nodes iterator
7691 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7692 while( anIter->more() ) {
7693 nodes[ iNode ] = anIter->next();
7694 if ( nodes[ iNode++ ] == prevSideNode )
7695 iPrevNode = iNode - 1;
7699 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7700 while ( nIt->more() ) {
7701 nodes[ iNode ] = cast2Node( nIt->next() );
7702 if ( nodes[ iNode++ ] == prevSideNode )
7703 iPrevNode = iNode - 1;
7706 // there are 2 links to check
7711 // loop on links, to be precise, on the second node of links
7712 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7713 const SMDS_MeshNode* n = nodes[ iNode ];
7715 if ( !volume.IsLinked( n, prevSideNode ))
7719 if ( iNode ) // a node before prevSideNode
7720 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7721 else // a node after prevSideNode
7722 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7724 // check if this link was already used
7725 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7726 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7727 if (!isJustChecked &&
7728 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7730 // test a link geometrically
7731 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7732 bool linkIsBetter = false;
7733 double dot = 0.0, dist = 0.0;
7734 if ( searchByDir ) { // choose most co-directed link
7735 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7736 linkIsBetter = ( dot > maxDot );
7738 else { // choose link with the node closest to bordPos
7739 dist = ( nextXYZ - bordPos ).SquareModulus();
7740 linkIsBetter = ( dist < minDist );
7742 if ( linkIsBetter ) {
7751 } // loop on inverse elements of prevSideNode
7754 MESSAGE(" Cant find path by links of the Side 2 ");
7755 return SEW_BAD_SIDE_NODES;
7757 sideNodes.push_back( sideNode );
7758 sideElems.push_back( sideElem );
7759 foundSideLinkIDs.insert ( linkID );
7760 prevSideNode = sideNode;
7762 if ( *nBordIt == theBordLastNode )
7763 searchByDir = false;
7765 // find the next border link to compare with
7766 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7767 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7768 // move to next border node if sideNode is before forward border node (bordPos)
7769 while ( *nBordIt != theBordLastNode && !searchByDir ) {
7770 prevBordNode = *nBordIt;
7772 bordPos = nBordXYZ[ *nBordIt ];
7773 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7774 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7778 while ( sideNode != theSideSecondNode );
7780 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7781 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7782 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7784 } // end nodes search on the side 2
7786 // ============================
7787 // sew the border to the side 2
7788 // ============================
7790 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7791 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7793 TListOfListOfNodes nodeGroupsToMerge;
7794 if ( nbNodes[0] == nbNodes[1] ||
7795 ( theSideIsFreeBorder && !theSideThirdNode)) {
7797 // all nodes are to be merged
7799 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7800 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7801 nIt[0]++, nIt[1]++ )
7803 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7804 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7805 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7810 // insert new nodes into the border and the side to get equal nb of segments
7812 // get normalized parameters of nodes on the borders
7813 //double param[ 2 ][ maxNbNodes ];
7815 param[0] = new double [ maxNbNodes ];
7816 param[1] = new double [ maxNbNodes ];
7818 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7819 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7820 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7821 const SMDS_MeshNode* nPrev = *nIt;
7822 double bordLength = 0;
7823 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7824 const SMDS_MeshNode* nCur = *nIt;
7825 gp_XYZ segment (nCur->X() - nPrev->X(),
7826 nCur->Y() - nPrev->Y(),
7827 nCur->Z() - nPrev->Z());
7828 double segmentLen = segment.Modulus();
7829 bordLength += segmentLen;
7830 param[ iBord ][ iNode ] = bordLength;
7833 // normalize within [0,1]
7834 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7835 param[ iBord ][ iNode ] /= bordLength;
7839 // loop on border segments
7840 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7841 int i[ 2 ] = { 0, 0 };
7842 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7843 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7845 TElemOfNodeListMap insertMap;
7846 TElemOfNodeListMap::iterator insertMapIt;
7848 // key: elem to insert nodes into
7849 // value: 2 nodes to insert between + nodes to be inserted
7851 bool next[ 2 ] = { false, false };
7853 // find min adjacent segment length after sewing
7854 double nextParam = 10., prevParam = 0;
7855 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7856 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7857 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7858 if ( i[ iBord ] > 0 )
7859 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7861 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7862 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7863 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7865 // choose to insert or to merge nodes
7866 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7867 if ( Abs( du ) <= minSegLen * 0.2 ) {
7870 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7871 const SMDS_MeshNode* n0 = *nIt[0];
7872 const SMDS_MeshNode* n1 = *nIt[1];
7873 nodeGroupsToMerge.back().push_back( n1 );
7874 nodeGroupsToMerge.back().push_back( n0 );
7875 // position of node of the border changes due to merge
7876 param[ 0 ][ i[0] ] += du;
7877 // move n1 for the sake of elem shape evaluation during insertion.
7878 // n1 will be removed by MergeNodes() anyway
7879 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
7880 next[0] = next[1] = true;
7885 int intoBord = ( du < 0 ) ? 0 : 1;
7886 const SMDS_MeshElement* elem = *eIt[ intoBord ];
7887 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
7888 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
7889 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
7890 if ( intoBord == 1 ) {
7891 // move node of the border to be on a link of elem of the side
7892 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
7893 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
7894 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
7895 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
7896 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
7898 insertMapIt = insertMap.find( elem );
7899 bool notFound = ( insertMapIt == insertMap.end() );
7900 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
7902 // insert into another link of the same element:
7903 // 1. perform insertion into the other link of the elem
7904 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7905 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
7906 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
7907 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
7908 // 2. perform insertion into the link of adjacent faces
7910 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
7912 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
7916 if (toCreatePolyedrs) {
7917 // perform insertion into the links of adjacent volumes
7918 UpdateVolumes(n12, n22, nodeList);
7920 // 3. find an element appeared on n1 and n2 after the insertion
7921 insertMap.erase( elem );
7922 elem = findAdjacentFace( n1, n2, 0 );
7924 if ( notFound || otherLink ) {
7925 // add element and nodes of the side into the insertMap
7926 insertMapIt = insertMap.insert
7927 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
7928 (*insertMapIt).second.push_back( n1 );
7929 (*insertMapIt).second.push_back( n2 );
7931 // add node to be inserted into elem
7932 (*insertMapIt).second.push_back( nIns );
7933 next[ 1 - intoBord ] = true;
7936 // go to the next segment
7937 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7938 if ( next[ iBord ] ) {
7939 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
7941 nPrev[ iBord ] = *nIt[ iBord ];
7942 nIt[ iBord ]++; i[ iBord ]++;
7946 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
7948 // perform insertion of nodes into elements
7950 for (insertMapIt = insertMap.begin();
7951 insertMapIt != insertMap.end();
7954 const SMDS_MeshElement* elem = (*insertMapIt).first;
7955 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
7956 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
7957 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
7959 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
7961 if ( !theSideIsFreeBorder ) {
7962 // look for and insert nodes into the faces adjacent to elem
7964 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
7966 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
7971 if (toCreatePolyedrs) {
7972 // perform insertion into the links of adjacent volumes
7973 UpdateVolumes(n1, n2, nodeList);
7979 } // end: insert new nodes
7981 MergeNodes ( nodeGroupsToMerge );
7986 //=======================================================================
7987 //function : InsertNodesIntoLink
7988 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
7989 // and theBetweenNode2 and split theElement
7990 //=======================================================================
7992 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
7993 const SMDS_MeshNode* theBetweenNode1,
7994 const SMDS_MeshNode* theBetweenNode2,
7995 list<const SMDS_MeshNode*>& theNodesToInsert,
7996 const bool toCreatePoly)
7998 if ( theFace->GetType() != SMDSAbs_Face ) return;
8000 // find indices of 2 link nodes and of the rest nodes
8001 int iNode = 0, il1, il2, i3, i4;
8002 il1 = il2 = i3 = i4 = -1;
8003 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8004 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8006 if(theFace->IsQuadratic()) {
8007 const SMDS_QuadraticFaceOfNodes* F =
8008 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8009 // use special nodes iterator
8010 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8011 while( anIter->more() ) {
8012 const SMDS_MeshNode* n = anIter->next();
8013 if ( n == theBetweenNode1 )
8015 else if ( n == theBetweenNode2 )
8021 nodes[ iNode++ ] = n;
8025 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8026 while ( nodeIt->more() ) {
8027 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8028 if ( n == theBetweenNode1 )
8030 else if ( n == theBetweenNode2 )
8036 nodes[ iNode++ ] = n;
8039 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8042 // arrange link nodes to go one after another regarding the face orientation
8043 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8044 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8049 aNodesToInsert.reverse();
8051 // check that not link nodes of a quadrangles are in good order
8052 int nbFaceNodes = theFace->NbNodes();
8053 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8059 if (toCreatePoly || theFace->IsPoly()) {
8062 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8064 // add nodes of face up to first node of link
8067 if(theFace->IsQuadratic()) {
8068 const SMDS_QuadraticFaceOfNodes* F =
8069 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8070 // use special nodes iterator
8071 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8072 while( anIter->more() && !isFLN ) {
8073 const SMDS_MeshNode* n = anIter->next();
8074 poly_nodes[iNode++] = n;
8075 if (n == nodes[il1]) {
8079 // add nodes to insert
8080 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8081 for (; nIt != aNodesToInsert.end(); nIt++) {
8082 poly_nodes[iNode++] = *nIt;
8084 // add nodes of face starting from last node of link
8085 while ( anIter->more() ) {
8086 poly_nodes[iNode++] = anIter->next();
8090 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8091 while ( nodeIt->more() && !isFLN ) {
8092 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8093 poly_nodes[iNode++] = n;
8094 if (n == nodes[il1]) {
8098 // add nodes to insert
8099 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8100 for (; nIt != aNodesToInsert.end(); nIt++) {
8101 poly_nodes[iNode++] = *nIt;
8103 // add nodes of face starting from last node of link
8104 while ( nodeIt->more() ) {
8105 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8106 poly_nodes[iNode++] = n;
8110 // edit or replace the face
8111 SMESHDS_Mesh *aMesh = GetMeshDS();
8113 if (theFace->IsPoly()) {
8114 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8117 int aShapeId = FindShape( theFace );
8119 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8120 myLastCreatedElems.Append(newElem);
8121 if ( aShapeId && newElem )
8122 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8124 aMesh->RemoveElement(theFace);
8129 if( !theFace->IsQuadratic() ) {
8131 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8132 int nbLinkNodes = 2 + aNodesToInsert.size();
8133 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8134 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8135 linkNodes[ 0 ] = nodes[ il1 ];
8136 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8137 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8138 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8139 linkNodes[ iNode++ ] = *nIt;
8141 // decide how to split a quadrangle: compare possible variants
8142 // and choose which of splits to be a quadrangle
8143 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8144 if ( nbFaceNodes == 3 ) {
8145 iBestQuad = nbSplits;
8148 else if ( nbFaceNodes == 4 ) {
8149 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8150 double aBestRate = DBL_MAX;
8151 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8153 double aBadRate = 0;
8154 // evaluate elements quality
8155 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8156 if ( iSplit == iQuad ) {
8157 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8161 aBadRate += getBadRate( &quad, aCrit );
8164 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8166 nodes[ iSplit < iQuad ? i4 : i3 ]);
8167 aBadRate += getBadRate( &tria, aCrit );
8171 if ( aBadRate < aBestRate ) {
8173 aBestRate = aBadRate;
8178 // create new elements
8179 SMESHDS_Mesh *aMesh = GetMeshDS();
8180 int aShapeId = FindShape( theFace );
8183 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8184 SMDS_MeshElement* newElem = 0;
8185 if ( iSplit == iBestQuad )
8186 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8191 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8193 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8194 myLastCreatedElems.Append(newElem);
8195 if ( aShapeId && newElem )
8196 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8199 // change nodes of theFace
8200 const SMDS_MeshNode* newNodes[ 4 ];
8201 newNodes[ 0 ] = linkNodes[ i1 ];
8202 newNodes[ 1 ] = linkNodes[ i2 ];
8203 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8204 newNodes[ 3 ] = nodes[ i4 ];
8205 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8206 } // end if(!theFace->IsQuadratic())
8207 else { // theFace is quadratic
8208 // we have to split theFace on simple triangles and one simple quadrangle
8210 int nbshift = tmp*2;
8211 // shift nodes in nodes[] by nbshift
8213 for(i=0; i<nbshift; i++) {
8214 const SMDS_MeshNode* n = nodes[0];
8215 for(j=0; j<nbFaceNodes-1; j++) {
8216 nodes[j] = nodes[j+1];
8218 nodes[nbFaceNodes-1] = n;
8220 il1 = il1 - nbshift;
8221 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8222 // n0 n1 n2 n0 n1 n2
8223 // +-----+-----+ +-----+-----+
8232 // create new elements
8233 SMESHDS_Mesh *aMesh = GetMeshDS();
8234 int aShapeId = FindShape( theFace );
8237 if(nbFaceNodes==6) { // quadratic triangle
8238 SMDS_MeshElement* newElem =
8239 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8240 myLastCreatedElems.Append(newElem);
8241 if ( aShapeId && newElem )
8242 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8243 if(theFace->IsMediumNode(nodes[il1])) {
8244 // create quadrangle
8245 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8246 myLastCreatedElems.Append(newElem);
8247 if ( aShapeId && newElem )
8248 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8254 // create quadrangle
8255 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8256 myLastCreatedElems.Append(newElem);
8257 if ( aShapeId && newElem )
8258 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8264 else { // nbFaceNodes==8 - quadratic quadrangle
8265 SMDS_MeshElement* newElem =
8266 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8267 myLastCreatedElems.Append(newElem);
8268 if ( aShapeId && newElem )
8269 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8270 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8271 myLastCreatedElems.Append(newElem);
8272 if ( aShapeId && newElem )
8273 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8274 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8275 myLastCreatedElems.Append(newElem);
8276 if ( aShapeId && newElem )
8277 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8278 if(theFace->IsMediumNode(nodes[il1])) {
8279 // create quadrangle
8280 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8281 myLastCreatedElems.Append(newElem);
8282 if ( aShapeId && newElem )
8283 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8289 // create quadrangle
8290 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8291 myLastCreatedElems.Append(newElem);
8292 if ( aShapeId && newElem )
8293 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8299 // create needed triangles using n1,n2,n3 and inserted nodes
8300 int nbn = 2 + aNodesToInsert.size();
8301 //const SMDS_MeshNode* aNodes[nbn];
8302 vector<const SMDS_MeshNode*> aNodes(nbn);
8303 aNodes[0] = nodes[n1];
8304 aNodes[nbn-1] = nodes[n2];
8305 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8306 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8307 aNodes[iNode++] = *nIt;
8309 for(i=1; i<nbn; i++) {
8310 SMDS_MeshElement* newElem =
8311 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8312 myLastCreatedElems.Append(newElem);
8313 if ( aShapeId && newElem )
8314 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8316 // remove old quadratic face
8317 aMesh->RemoveElement(theFace);
8321 //=======================================================================
8322 //function : UpdateVolumes
8324 //=======================================================================
8325 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8326 const SMDS_MeshNode* theBetweenNode2,
8327 list<const SMDS_MeshNode*>& theNodesToInsert)
8329 myLastCreatedElems.Clear();
8330 myLastCreatedNodes.Clear();
8332 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8333 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8334 const SMDS_MeshElement* elem = invElemIt->next();
8336 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8337 SMDS_VolumeTool aVolume (elem);
8338 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8341 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8342 int iface, nbFaces = aVolume.NbFaces();
8343 vector<const SMDS_MeshNode *> poly_nodes;
8344 vector<int> quantities (nbFaces);
8346 for (iface = 0; iface < nbFaces; iface++) {
8347 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8348 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8349 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8351 for (int inode = 0; inode < nbFaceNodes; inode++) {
8352 poly_nodes.push_back(faceNodes[inode]);
8354 if (nbInserted == 0) {
8355 if (faceNodes[inode] == theBetweenNode1) {
8356 if (faceNodes[inode + 1] == theBetweenNode2) {
8357 nbInserted = theNodesToInsert.size();
8359 // add nodes to insert
8360 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8361 for (; nIt != theNodesToInsert.end(); nIt++) {
8362 poly_nodes.push_back(*nIt);
8366 else if (faceNodes[inode] == theBetweenNode2) {
8367 if (faceNodes[inode + 1] == theBetweenNode1) {
8368 nbInserted = theNodesToInsert.size();
8370 // add nodes to insert in reversed order
8371 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8373 for (; nIt != theNodesToInsert.begin(); nIt--) {
8374 poly_nodes.push_back(*nIt);
8376 poly_nodes.push_back(*nIt);
8383 quantities[iface] = nbFaceNodes + nbInserted;
8386 // Replace or update the volume
8387 SMESHDS_Mesh *aMesh = GetMeshDS();
8389 if (elem->IsPoly()) {
8390 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8394 int aShapeId = FindShape( elem );
8396 SMDS_MeshElement* newElem =
8397 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8398 myLastCreatedElems.Append(newElem);
8399 if (aShapeId && newElem)
8400 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8402 aMesh->RemoveElement(elem);
8407 //=======================================================================
8409 * \brief Convert elements contained in a submesh to quadratic
8410 * \retval int - nb of checked elements
8412 //=======================================================================
8414 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8415 SMESH_MesherHelper& theHelper,
8416 const bool theForce3d)
8419 if( !theSm ) return nbElem;
8421 const bool notFromGroups = false;
8422 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8423 while(ElemItr->more())
8426 const SMDS_MeshElement* elem = ElemItr->next();
8427 if( !elem || elem->IsQuadratic() ) continue;
8429 int id = elem->GetID();
8430 int nbNodes = elem->NbNodes();
8431 vector<const SMDS_MeshNode *> aNds (nbNodes);
8433 for(int i = 0; i < nbNodes; i++)
8435 aNds[i] = elem->GetNode(i);
8437 SMDSAbs_ElementType aType = elem->GetType();
8439 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8441 const SMDS_MeshElement* NewElem = 0;
8447 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8455 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8458 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8465 case SMDSAbs_Volume :
8470 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8473 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8476 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8479 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8480 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8490 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8492 theSm->AddElement( NewElem );
8497 //=======================================================================
8498 //function : ConvertToQuadratic
8500 //=======================================================================
8501 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8503 SMESHDS_Mesh* meshDS = GetMeshDS();
8505 SMESH_MesherHelper aHelper(*myMesh);
8506 aHelper.SetIsQuadratic( true );
8507 const bool notFromGroups = false;
8509 int nbCheckedElems = 0;
8510 if ( myMesh->HasShapeToMesh() )
8512 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8514 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8515 while ( smIt->more() ) {
8516 SMESH_subMesh* sm = smIt->next();
8517 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8518 aHelper.SetSubShape( sm->GetSubShape() );
8519 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8524 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8525 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8527 SMESHDS_SubMesh *smDS = 0;
8528 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8529 while(aEdgeItr->more())
8531 const SMDS_MeshEdge* edge = aEdgeItr->next();
8532 if(edge && !edge->IsQuadratic())
8534 int id = edge->GetID();
8535 const SMDS_MeshNode* n1 = edge->GetNode(0);
8536 const SMDS_MeshNode* n2 = edge->GetNode(1);
8538 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8540 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8541 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8544 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8545 while(aFaceItr->more())
8547 const SMDS_MeshFace* face = aFaceItr->next();
8548 if(!face || face->IsQuadratic() ) continue;
8550 int id = face->GetID();
8551 int nbNodes = face->NbNodes();
8552 vector<const SMDS_MeshNode *> aNds (nbNodes);
8554 for(int i = 0; i < nbNodes; i++)
8556 aNds[i] = face->GetNode(i);
8559 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8561 SMDS_MeshFace * NewFace = 0;
8565 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8568 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8573 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8575 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8576 while(aVolumeItr->more())
8578 const SMDS_MeshVolume* volume = aVolumeItr->next();
8579 if(!volume || volume->IsQuadratic() ) continue;
8581 int id = volume->GetID();
8582 int nbNodes = volume->NbNodes();
8583 vector<const SMDS_MeshNode *> aNds (nbNodes);
8585 for(int i = 0; i < nbNodes; i++)
8587 aNds[i] = volume->GetNode(i);
8590 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8592 SMDS_MeshVolume * NewVolume = 0;
8596 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8597 aNds[3], id, theForce3d );
8600 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8601 aNds[3], aNds[4], id, theForce3d);
8604 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8605 aNds[3], aNds[4], aNds[5], id, theForce3d);
8608 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8609 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8614 ReplaceElemInGroups(volume, NewVolume, meshDS);
8617 if ( !theForce3d ) {
8618 aHelper.SetSubShape(0); // apply to the whole mesh
8619 aHelper.FixQuadraticElements();
8623 //=======================================================================
8625 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8626 * \retval int - nb of checked elements
8628 //=======================================================================
8630 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8631 SMDS_ElemIteratorPtr theItr,
8632 const int theShapeID)
8635 SMESHDS_Mesh* meshDS = GetMeshDS();
8636 const bool notFromGroups = false;
8638 while( theItr->more() )
8640 const SMDS_MeshElement* elem = theItr->next();
8642 if( elem && elem->IsQuadratic())
8644 int id = elem->GetID();
8645 int nbNodes = elem->NbNodes();
8646 vector<const SMDS_MeshNode *> aNds, mediumNodes;
8647 aNds.reserve( nbNodes );
8648 mediumNodes.reserve( nbNodes );
8650 for(int i = 0; i < nbNodes; i++)
8652 const SMDS_MeshNode* n = elem->GetNode(i);
8654 if( elem->IsMediumNode( n ) )
8655 mediumNodes.push_back( n );
8657 aNds.push_back( n );
8659 if( aNds.empty() ) continue;
8660 SMDSAbs_ElementType aType = elem->GetType();
8662 //remove old quadratic element
8663 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8665 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8666 ReplaceElemInGroups(elem, NewElem, meshDS);
8667 if( theSm && NewElem )
8668 theSm->AddElement( NewElem );
8670 // remove medium nodes
8671 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8672 for ( ; nIt != mediumNodes.end(); ++nIt ) {
8673 const SMDS_MeshNode* n = *nIt;
8674 if ( n->NbInverseElements() == 0 ) {
8675 if ( n->GetPosition()->GetShapeId() != theShapeID )
8676 meshDS->RemoveFreeNode( n, meshDS->MeshElements
8677 ( n->GetPosition()->GetShapeId() ));
8679 meshDS->RemoveFreeNode( n, theSm );
8687 //=======================================================================
8688 //function : ConvertFromQuadratic
8690 //=======================================================================
8691 bool SMESH_MeshEditor::ConvertFromQuadratic()
8693 int nbCheckedElems = 0;
8694 if ( myMesh->HasShapeToMesh() )
8696 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8698 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8699 while ( smIt->more() ) {
8700 SMESH_subMesh* sm = smIt->next();
8701 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8702 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8708 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8709 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8711 SMESHDS_SubMesh *aSM = 0;
8712 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8718 //=======================================================================
8719 //function : SewSideElements
8721 //=======================================================================
8723 SMESH_MeshEditor::Sew_Error
8724 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8725 TIDSortedElemSet& theSide2,
8726 const SMDS_MeshNode* theFirstNode1,
8727 const SMDS_MeshNode* theFirstNode2,
8728 const SMDS_MeshNode* theSecondNode1,
8729 const SMDS_MeshNode* theSecondNode2)
8731 myLastCreatedElems.Clear();
8732 myLastCreatedNodes.Clear();
8734 MESSAGE ("::::SewSideElements()");
8735 if ( theSide1.size() != theSide2.size() )
8736 return SEW_DIFF_NB_OF_ELEMENTS;
8738 Sew_Error aResult = SEW_OK;
8740 // 1. Build set of faces representing each side
8741 // 2. Find which nodes of the side 1 to merge with ones on the side 2
8742 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8744 // =======================================================================
8745 // 1. Build set of faces representing each side:
8746 // =======================================================================
8747 // a. build set of nodes belonging to faces
8748 // b. complete set of faces: find missing fices whose nodes are in set of nodes
8749 // c. create temporary faces representing side of volumes if correspondent
8750 // face does not exist
8752 SMESHDS_Mesh* aMesh = GetMeshDS();
8753 SMDS_Mesh aTmpFacesMesh;
8754 set<const SMDS_MeshElement*> faceSet1, faceSet2;
8755 set<const SMDS_MeshElement*> volSet1, volSet2;
8756 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
8757 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8758 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
8759 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8760 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8761 int iSide, iFace, iNode;
8763 for ( iSide = 0; iSide < 2; iSide++ ) {
8764 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
8765 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8766 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8767 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
8768 set<const SMDS_MeshElement*>::iterator vIt;
8769 TIDSortedElemSet::iterator eIt;
8770 set<const SMDS_MeshNode*>::iterator nIt;
8772 // check that given nodes belong to given elements
8773 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8774 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8775 int firstIndex = -1, secondIndex = -1;
8776 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8777 const SMDS_MeshElement* elem = *eIt;
8778 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8779 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8780 if ( firstIndex > -1 && secondIndex > -1 ) break;
8782 if ( firstIndex < 0 || secondIndex < 0 ) {
8783 // we can simply return until temporary faces created
8784 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8787 // -----------------------------------------------------------
8788 // 1a. Collect nodes of existing faces
8789 // and build set of face nodes in order to detect missing
8790 // faces corresponing to sides of volumes
8791 // -----------------------------------------------------------
8793 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8795 // loop on the given element of a side
8796 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8797 //const SMDS_MeshElement* elem = *eIt;
8798 const SMDS_MeshElement* elem = *eIt;
8799 if ( elem->GetType() == SMDSAbs_Face ) {
8800 faceSet->insert( elem );
8801 set <const SMDS_MeshNode*> faceNodeSet;
8802 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8803 while ( nodeIt->more() ) {
8804 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8805 nodeSet->insert( n );
8806 faceNodeSet.insert( n );
8808 setOfFaceNodeSet.insert( faceNodeSet );
8810 else if ( elem->GetType() == SMDSAbs_Volume )
8811 volSet->insert( elem );
8813 // ------------------------------------------------------------------------------
8814 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8815 // ------------------------------------------------------------------------------
8817 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8818 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8819 while ( fIt->more() ) { // loop on faces sharing a node
8820 const SMDS_MeshElement* f = fIt->next();
8821 if ( faceSet->find( f ) == faceSet->end() ) {
8822 // check if all nodes are in nodeSet and
8823 // complete setOfFaceNodeSet if they are
8824 set <const SMDS_MeshNode*> faceNodeSet;
8825 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8826 bool allInSet = true;
8827 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8828 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8829 if ( nodeSet->find( n ) == nodeSet->end() )
8832 faceNodeSet.insert( n );
8835 faceSet->insert( f );
8836 setOfFaceNodeSet.insert( faceNodeSet );
8842 // -------------------------------------------------------------------------
8843 // 1c. Create temporary faces representing sides of volumes if correspondent
8844 // face does not exist
8845 // -------------------------------------------------------------------------
8847 if ( !volSet->empty() ) {
8848 //int nodeSetSize = nodeSet->size();
8850 // loop on given volumes
8851 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8852 SMDS_VolumeTool vol (*vIt);
8853 // loop on volume faces: find free faces
8854 // --------------------------------------
8855 list<const SMDS_MeshElement* > freeFaceList;
8856 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8857 if ( !vol.IsFreeFace( iFace ))
8859 // check if there is already a face with same nodes in a face set
8860 const SMDS_MeshElement* aFreeFace = 0;
8861 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8862 int nbNodes = vol.NbFaceNodes( iFace );
8863 set <const SMDS_MeshNode*> faceNodeSet;
8864 vol.GetFaceNodes( iFace, faceNodeSet );
8865 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8867 // no such a face is given but it still can exist, check it
8868 if ( nbNodes == 3 ) {
8869 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8871 else if ( nbNodes == 4 ) {
8872 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8875 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8876 aFreeFace = aMesh->FindFace(poly_nodes);
8880 // create a temporary face
8881 if ( nbNodes == 3 ) {
8882 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
8884 else if ( nbNodes == 4 ) {
8885 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8888 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8889 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
8893 freeFaceList.push_back( aFreeFace );
8895 } // loop on faces of a volume
8897 // choose one of several free faces
8898 // --------------------------------------
8899 if ( freeFaceList.size() > 1 ) {
8900 // choose a face having max nb of nodes shared by other elems of a side
8901 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
8902 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
8903 while ( fIt != freeFaceList.end() ) { // loop on free faces
8904 int nbSharedNodes = 0;
8905 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8906 while ( nodeIt->more() ) { // loop on free face nodes
8907 const SMDS_MeshNode* n =
8908 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8909 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
8910 while ( invElemIt->more() ) {
8911 const SMDS_MeshElement* e = invElemIt->next();
8912 if ( faceSet->find( e ) != faceSet->end() )
8914 if ( elemSet->find( e ) != elemSet->end() )
8918 if ( nbSharedNodes >= maxNbNodes ) {
8919 maxNbNodes = nbSharedNodes;
8923 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
8925 if ( freeFaceList.size() > 1 )
8927 // could not choose one face, use another way
8928 // choose a face most close to the bary center of the opposite side
8929 gp_XYZ aBC( 0., 0., 0. );
8930 set <const SMDS_MeshNode*> addedNodes;
8931 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
8932 eIt = elemSet2->begin();
8933 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
8934 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
8935 while ( nodeIt->more() ) { // loop on free face nodes
8936 const SMDS_MeshNode* n =
8937 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8938 if ( addedNodes.insert( n ).second )
8939 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
8942 aBC /= addedNodes.size();
8943 double minDist = DBL_MAX;
8944 fIt = freeFaceList.begin();
8945 while ( fIt != freeFaceList.end() ) { // loop on free faces
8947 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
8948 while ( nodeIt->more() ) { // loop on free face nodes
8949 const SMDS_MeshNode* n =
8950 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8951 gp_XYZ p( n->X(),n->Y(),n->Z() );
8952 dist += ( aBC - p ).SquareModulus();
8954 if ( dist < minDist ) {
8956 freeFaceList.erase( freeFaceList.begin(), fIt++ );
8959 fIt = freeFaceList.erase( fIt++ );
8962 } // choose one of several free faces of a volume
8964 if ( freeFaceList.size() == 1 ) {
8965 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
8966 faceSet->insert( aFreeFace );
8967 // complete a node set with nodes of a found free face
8968 // for ( iNode = 0; iNode < ; iNode++ )
8969 // nodeSet->insert( fNodes[ iNode ] );
8972 } // loop on volumes of a side
8974 // // complete a set of faces if new nodes in a nodeSet appeared
8975 // // ----------------------------------------------------------
8976 // if ( nodeSetSize != nodeSet->size() ) {
8977 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8978 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8979 // while ( fIt->more() ) { // loop on faces sharing a node
8980 // const SMDS_MeshElement* f = fIt->next();
8981 // if ( faceSet->find( f ) == faceSet->end() ) {
8982 // // check if all nodes are in nodeSet and
8983 // // complete setOfFaceNodeSet if they are
8984 // set <const SMDS_MeshNode*> faceNodeSet;
8985 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8986 // bool allInSet = true;
8987 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8988 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8989 // if ( nodeSet->find( n ) == nodeSet->end() )
8990 // allInSet = false;
8992 // faceNodeSet.insert( n );
8994 // if ( allInSet ) {
8995 // faceSet->insert( f );
8996 // setOfFaceNodeSet.insert( faceNodeSet );
9002 } // Create temporary faces, if there are volumes given
9005 if ( faceSet1.size() != faceSet2.size() ) {
9006 // delete temporary faces: they are in reverseElements of actual nodes
9007 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9008 while ( tmpFaceIt->more() )
9009 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9010 MESSAGE("Diff nb of faces");
9011 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9014 // ============================================================
9015 // 2. Find nodes to merge:
9016 // bind a node to remove to a node to put instead
9017 // ============================================================
9019 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9020 if ( theFirstNode1 != theFirstNode2 )
9021 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9022 if ( theSecondNode1 != theSecondNode2 )
9023 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9025 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9026 set< long > linkIdSet; // links to process
9027 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9029 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9030 list< NLink > linkList[2];
9031 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9032 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9033 // loop on links in linkList; find faces by links and append links
9034 // of the found faces to linkList
9035 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9036 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9037 NLink link[] = { *linkIt[0], *linkIt[1] };
9038 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9039 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9042 // by links, find faces in the face sets,
9043 // and find indices of link nodes in the found faces;
9044 // in a face set, there is only one or no face sharing a link
9045 // ---------------------------------------------------------------
9047 const SMDS_MeshElement* face[] = { 0, 0 };
9048 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9049 vector<const SMDS_MeshNode*> fnodes1(9);
9050 vector<const SMDS_MeshNode*> fnodes2(9);
9051 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9052 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9053 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9054 int iLinkNode[2][2];
9055 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9056 const SMDS_MeshNode* n1 = link[iSide].first;
9057 const SMDS_MeshNode* n2 = link[iSide].second;
9058 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9059 set< const SMDS_MeshElement* > fMap;
9060 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9061 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9062 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9063 while ( fIt->more() ) { // loop on faces sharing a node
9064 const SMDS_MeshElement* f = fIt->next();
9065 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9066 ! fMap.insert( f ).second ) // f encounters twice
9068 if ( face[ iSide ] ) {
9069 MESSAGE( "2 faces per link " );
9070 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9074 faceSet->erase( f );
9075 // get face nodes and find ones of a link
9080 fnodes1.resize(f->NbNodes()+1);
9081 notLinkNodes1.resize(f->NbNodes()-2);
9084 fnodes2.resize(f->NbNodes()+1);
9085 notLinkNodes2.resize(f->NbNodes()-2);
9088 if(!f->IsQuadratic()) {
9089 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9090 while ( nIt->more() ) {
9091 const SMDS_MeshNode* n =
9092 static_cast<const SMDS_MeshNode*>( nIt->next() );
9094 iLinkNode[ iSide ][ 0 ] = iNode;
9096 else if ( n == n2 ) {
9097 iLinkNode[ iSide ][ 1 ] = iNode;
9099 //else if ( notLinkNodes[ iSide ][ 0 ] )
9100 // notLinkNodes[ iSide ][ 1 ] = n;
9102 // notLinkNodes[ iSide ][ 0 ] = n;
9106 notLinkNodes1[nbl] = n;
9107 //notLinkNodes1.push_back(n);
9109 notLinkNodes2[nbl] = n;
9110 //notLinkNodes2.push_back(n);
9112 //faceNodes[ iSide ][ iNode++ ] = n;
9114 fnodes1[iNode++] = n;
9117 fnodes2[iNode++] = n;
9121 else { // f->IsQuadratic()
9122 const SMDS_QuadraticFaceOfNodes* F =
9123 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9124 // use special nodes iterator
9125 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9126 while ( anIter->more() ) {
9127 const SMDS_MeshNode* n =
9128 static_cast<const SMDS_MeshNode*>( anIter->next() );
9130 iLinkNode[ iSide ][ 0 ] = iNode;
9132 else if ( n == n2 ) {
9133 iLinkNode[ iSide ][ 1 ] = iNode;
9138 notLinkNodes1[nbl] = n;
9141 notLinkNodes2[nbl] = n;
9145 fnodes1[iNode++] = n;
9148 fnodes2[iNode++] = n;
9152 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9154 fnodes1[iNode] = fnodes1[0];
9157 fnodes2[iNode] = fnodes1[0];
9164 // check similarity of elements of the sides
9165 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9166 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9167 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9168 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9171 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9173 break; // do not return because it s necessary to remove tmp faces
9176 // set nodes to merge
9177 // -------------------
9179 if ( face[0] && face[1] ) {
9180 int nbNodes = face[0]->NbNodes();
9181 if ( nbNodes != face[1]->NbNodes() ) {
9182 MESSAGE("Diff nb of face nodes");
9183 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9184 break; // do not return because it s necessary to remove tmp faces
9186 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9187 if ( nbNodes == 3 ) {
9188 //nReplaceMap.insert( TNodeNodeMap::value_type
9189 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9190 nReplaceMap.insert( TNodeNodeMap::value_type
9191 ( notLinkNodes1[0], notLinkNodes2[0] ));
9194 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9195 // analyse link orientation in faces
9196 int i1 = iLinkNode[ iSide ][ 0 ];
9197 int i2 = iLinkNode[ iSide ][ 1 ];
9198 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9199 // if notLinkNodes are the first and the last ones, then
9200 // their order does not correspond to the link orientation
9201 if (( i1 == 1 && i2 == 2 ) ||
9202 ( i1 == 2 && i2 == 1 ))
9203 reverse[ iSide ] = !reverse[ iSide ];
9205 if ( reverse[0] == reverse[1] ) {
9206 //nReplaceMap.insert( TNodeNodeMap::value_type
9207 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9208 //nReplaceMap.insert( TNodeNodeMap::value_type
9209 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9210 for(int nn=0; nn<nbNodes-2; nn++) {
9211 nReplaceMap.insert( TNodeNodeMap::value_type
9212 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9216 //nReplaceMap.insert( TNodeNodeMap::value_type
9217 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9218 //nReplaceMap.insert( TNodeNodeMap::value_type
9219 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9220 for(int nn=0; nn<nbNodes-2; nn++) {
9221 nReplaceMap.insert( TNodeNodeMap::value_type
9222 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9227 // add other links of the faces to linkList
9228 // -----------------------------------------
9230 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9231 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9232 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9233 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9234 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9235 if ( !iter_isnew.second ) { // already in a set: no need to process
9236 linkIdSet.erase( iter_isnew.first );
9238 else // new in set == encountered for the first time: add
9240 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9241 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9242 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9243 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9244 linkList[0].push_back ( NLink( n1, n2 ));
9245 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9249 } // loop on link lists
9251 if ( aResult == SEW_OK &&
9252 ( linkIt[0] != linkList[0].end() ||
9253 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9254 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9255 " " << (faceSetPtr[1]->empty()));
9256 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9259 // ====================================================================
9260 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9261 // ====================================================================
9263 // delete temporary faces: they are in reverseElements of actual nodes
9264 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9265 while ( tmpFaceIt->more() )
9266 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9268 if ( aResult != SEW_OK)
9271 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9272 // loop on nodes replacement map
9273 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9274 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9275 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9276 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9277 nodeIDsToRemove.push_back( nToRemove->GetID() );
9278 // loop on elements sharing nToRemove
9279 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9280 while ( invElemIt->more() ) {
9281 const SMDS_MeshElement* e = invElemIt->next();
9282 // get a new suite of nodes: make replacement
9283 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9284 vector< const SMDS_MeshNode*> nodes( nbNodes );
9285 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9286 while ( nIt->more() ) {
9287 const SMDS_MeshNode* n =
9288 static_cast<const SMDS_MeshNode*>( nIt->next() );
9289 nnIt = nReplaceMap.find( n );
9290 if ( nnIt != nReplaceMap.end() ) {
9296 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9297 // elemIDsToRemove.push_back( e->GetID() );
9300 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9304 Remove( nodeIDsToRemove, true );
9309 //================================================================================
9311 * \brief Find corresponding nodes in two sets of faces
9312 * \param theSide1 - first face set
9313 * \param theSide2 - second first face
9314 * \param theFirstNode1 - a boundary node of set 1
9315 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9316 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9317 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9318 * \param nReplaceMap - output map of corresponding nodes
9319 * \retval bool - is a success or not
9321 //================================================================================
9324 //#define DEBUG_MATCHING_NODES
9327 SMESH_MeshEditor::Sew_Error
9328 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9329 set<const SMDS_MeshElement*>& theSide2,
9330 const SMDS_MeshNode* theFirstNode1,
9331 const SMDS_MeshNode* theFirstNode2,
9332 const SMDS_MeshNode* theSecondNode1,
9333 const SMDS_MeshNode* theSecondNode2,
9334 TNodeNodeMap & nReplaceMap)
9336 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9338 nReplaceMap.clear();
9339 if ( theFirstNode1 != theFirstNode2 )
9340 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9341 if ( theSecondNode1 != theSecondNode2 )
9342 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9344 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9345 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9347 list< NLink > linkList[2];
9348 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9349 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9351 // loop on links in linkList; find faces by links and append links
9352 // of the found faces to linkList
9353 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9354 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9355 NLink link[] = { *linkIt[0], *linkIt[1] };
9356 if ( linkSet.find( link[0] ) == linkSet.end() )
9359 // by links, find faces in the face sets,
9360 // and find indices of link nodes in the found faces;
9361 // in a face set, there is only one or no face sharing a link
9362 // ---------------------------------------------------------------
9364 const SMDS_MeshElement* face[] = { 0, 0 };
9365 list<const SMDS_MeshNode*> notLinkNodes[2];
9366 //bool reverse[] = { false, false }; // order of notLinkNodes
9368 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9370 const SMDS_MeshNode* n1 = link[iSide].first;
9371 const SMDS_MeshNode* n2 = link[iSide].second;
9372 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9373 set< const SMDS_MeshElement* > facesOfNode1;
9374 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9376 // during a loop of the first node, we find all faces around n1,
9377 // during a loop of the second node, we find one face sharing both n1 and n2
9378 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9379 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9380 while ( fIt->more() ) { // loop on faces sharing a node
9381 const SMDS_MeshElement* f = fIt->next();
9382 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9383 ! facesOfNode1.insert( f ).second ) // f encounters twice
9385 if ( face[ iSide ] ) {
9386 MESSAGE( "2 faces per link " );
9387 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9390 faceSet->erase( f );
9392 // get not link nodes
9393 int nbN = f->NbNodes();
9394 if ( f->IsQuadratic() )
9396 nbNodes[ iSide ] = nbN;
9397 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9398 int i1 = f->GetNodeIndex( n1 );
9399 int i2 = f->GetNodeIndex( n2 );
9400 int iEnd = nbN, iBeg = -1, iDelta = 1;
9401 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9403 std::swap( iEnd, iBeg ); iDelta = -1;
9408 if ( i == iEnd ) i = iBeg + iDelta;
9409 if ( i == i1 ) break;
9410 nodes.push_back ( f->GetNode( i ) );
9416 // check similarity of elements of the sides
9417 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9418 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9419 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9420 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9423 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9427 // set nodes to merge
9428 // -------------------
9430 if ( face[0] && face[1] ) {
9431 if ( nbNodes[0] != nbNodes[1] ) {
9432 MESSAGE("Diff nb of face nodes");
9433 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9435 #ifdef DEBUG_MATCHING_NODES
9436 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9437 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9438 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9440 int nbN = nbNodes[0];
9442 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9443 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9444 for ( int i = 0 ; i < nbN - 2; ++i ) {
9445 #ifdef DEBUG_MATCHING_NODES
9446 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9448 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9452 // add other links of the face 1 to linkList
9453 // -----------------------------------------
9455 const SMDS_MeshElement* f0 = face[0];
9456 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9457 for ( int i = 0; i < nbN; i++ )
9459 const SMDS_MeshNode* n2 = f0->GetNode( i );
9460 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9461 linkSet.insert( SMESH_TLink( n1, n2 ));
9462 if ( !iter_isnew.second ) { // already in a set: no need to process
9463 linkSet.erase( iter_isnew.first );
9465 else // new in set == encountered for the first time: add
9467 #ifdef DEBUG_MATCHING_NODES
9468 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9469 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9471 linkList[0].push_back ( NLink( n1, n2 ));
9472 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9477 } // loop on link lists
9482 //================================================================================
9484 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9485 \param theElems - the list of elements (edges or faces) to be replicated
9486 The nodes for duplication could be found from these elements
9487 \param theNodesNot - list of nodes to NOT replicate
9488 \param theAffectedElems - the list of elements (cells and edges) to which the
9489 replicated nodes should be associated to.
9490 \return TRUE if operation has been completed successfully, FALSE otherwise
9492 //================================================================================
9494 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9495 const TIDSortedElemSet& theNodesNot,
9496 const TIDSortedElemSet& theAffectedElems )
9498 myLastCreatedElems.Clear();
9499 myLastCreatedNodes.Clear();
9501 if ( theElems.size() == 0 )
9504 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9509 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9510 // duplicate elements and nodes
9511 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9512 // replce nodes by duplications
9513 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9517 //================================================================================
9519 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9520 \param theMeshDS - mesh instance
9521 \param theElems - the elements replicated or modified (nodes should be changed)
9522 \param theNodesNot - nodes to NOT replicate
9523 \param theNodeNodeMap - relation of old node to new created node
9524 \param theIsDoubleElem - flag os to replicate element or modify
9525 \return TRUE if operation has been completed successfully, FALSE otherwise
9527 //================================================================================
9529 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9530 const TIDSortedElemSet& theElems,
9531 const TIDSortedElemSet& theNodesNot,
9532 std::map< const SMDS_MeshNode*,
9533 const SMDS_MeshNode* >& theNodeNodeMap,
9534 const bool theIsDoubleElem )
9536 // iterate on through element and duplicate them (by nodes duplication)
9538 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9539 for ( ; elemItr != theElems.end(); ++elemItr )
9541 const SMDS_MeshElement* anElem = *elemItr;
9545 bool isDuplicate = false;
9546 // duplicate nodes to duplicate element
9547 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9548 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9550 while ( anIter->more() )
9553 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9554 SMDS_MeshNode* aNewNode = aCurrNode;
9555 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9556 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9557 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9560 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9561 theNodeNodeMap[ aCurrNode ] = aNewNode;
9562 myLastCreatedNodes.Append( aNewNode );
9564 isDuplicate |= (aCurrNode != aNewNode);
9565 newNodes[ ind++ ] = aNewNode;
9570 if ( theIsDoubleElem )
9571 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9573 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9580 //================================================================================
9582 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9583 \param theNodes - identifiers of nodes to be doubled
9584 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9585 nodes. If list of element identifiers is empty then nodes are doubled but
9586 they not assigned to elements
9587 \return TRUE if operation has been completed successfully, FALSE otherwise
9589 //================================================================================
9591 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9592 const std::list< int >& theListOfModifiedElems )
9594 myLastCreatedElems.Clear();
9595 myLastCreatedNodes.Clear();
9597 if ( theListOfNodes.size() == 0 )
9600 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9604 // iterate through nodes and duplicate them
9606 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9608 std::list< int >::const_iterator aNodeIter;
9609 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9611 int aCurr = *aNodeIter;
9612 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9618 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9621 anOldNodeToNewNode[ aNode ] = aNewNode;
9622 myLastCreatedNodes.Append( aNewNode );
9626 // Create map of new nodes for modified elements
9628 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9630 std::list< int >::const_iterator anElemIter;
9631 for ( anElemIter = theListOfModifiedElems.begin();
9632 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9634 int aCurr = *anElemIter;
9635 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9639 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9641 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9643 while ( anIter->more() )
9645 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9646 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9648 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9649 aNodeArr[ ind++ ] = aNewNode;
9652 aNodeArr[ ind++ ] = aCurrNode;
9654 anElemToNodes[ anElem ] = aNodeArr;
9657 // Change nodes of elements
9659 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9660 anElemToNodesIter = anElemToNodes.begin();
9661 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9663 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9664 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9666 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9674 //================================================================================
9676 \brief Check if element located inside shape
9677 \return TRUE if IN or ON shape, FALSE otherwise
9679 //================================================================================
9681 template<class Classifier>
9682 bool isInside(const SMDS_MeshElement* theElem,
9683 Classifier& theClassifier,
9684 const double theTol)
9686 gp_XYZ centerXYZ (0, 0, 0);
9687 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9688 while (aNodeItr->more())
9689 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9691 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9692 theClassifier.Perform(aPnt, theTol);
9693 TopAbs_State aState = theClassifier.State();
9694 return (aState == TopAbs_IN || aState == TopAbs_ON );
9697 //================================================================================
9699 * \brief Classifier of the 3D point on the TopoDS_Face
9700 * with interaface suitable for isInside()
9702 //================================================================================
9704 struct _FaceClassifier
9706 Extrema_ExtPS _extremum;
9707 BRepAdaptor_Surface _surface;
9708 TopAbs_State _state;
9710 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9712 _extremum.Initialize( _surface,
9713 _surface.FirstUParameter(), _surface.LastUParameter(),
9714 _surface.FirstVParameter(), _surface.LastVParameter(),
9715 _surface.Tolerance(), _surface.Tolerance() );
9717 void Perform(const gp_Pnt& aPnt, double theTol)
9719 _state = TopAbs_OUT;
9720 _extremum.Perform(aPnt);
9721 if ( _extremum.IsDone() )
9722 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9723 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9725 TopAbs_State State() const
9732 //================================================================================
9734 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9735 \param theElems - group of of elements (edges or faces) to be replicated
9736 \param theNodesNot - group of nodes not to replicate
9737 \param theShape - shape to detect affected elements (element which geometric center
9738 located on or inside shape).
9739 The replicated nodes should be associated to affected elements.
9740 \return TRUE if operation has been completed successfully, FALSE otherwise
9742 //================================================================================
9744 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9745 const TIDSortedElemSet& theNodesNot,
9746 const TopoDS_Shape& theShape )
9748 if ( theShape.IsNull() )
9751 const double aTol = Precision::Confusion();
9752 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9753 auto_ptr<_FaceClassifier> aFaceClassifier;
9754 if ( theShape.ShapeType() == TopAbs_SOLID )
9756 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9757 bsc3d->PerformInfinitePoint(aTol);
9759 else if (theShape.ShapeType() == TopAbs_FACE )
9761 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9764 // iterates on indicated elements and get elements by back references from their nodes
9765 TIDSortedElemSet anAffected;
9766 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9767 for ( ; elemItr != theElems.end(); ++elemItr )
9769 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9773 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9774 while ( nodeItr->more() )
9776 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9777 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9779 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9780 while ( backElemItr->more() )
9782 const SMDS_MeshElement* curElem = backElemItr->next();
9783 if ( curElem && theElems.find(curElem) == theElems.end() &&
9785 isInside( curElem, *bsc3d, aTol ) :
9786 isInside( curElem, *aFaceClassifier, aTol )))
9787 anAffected.insert( curElem );
9791 return DoubleNodes( theElems, theNodesNot, anAffected );
9794 //================================================================================
9796 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9797 * The created 2D mesh elements based on nodes of free faces of boundary volumes
9798 * \return TRUE if operation has been completed successfully, FALSE otherwise
9800 //================================================================================
9802 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9804 // iterates on volume elements and detect all free faces on them
9805 SMESHDS_Mesh* aMesh = GetMeshDS();
9809 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9812 const SMDS_MeshVolume* volume = vIt->next();
9813 SMDS_VolumeTool vTool( volume );
9814 vTool.SetExternalNormal();
9815 const bool isPoly = volume->IsPoly();
9816 const bool isQuad = volume->IsQuadratic();
9817 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9819 if (!vTool.IsFreeFace(iface))
9821 vector<const SMDS_MeshNode *> nodes;
9822 int nbFaceNodes = vTool.NbFaceNodes(iface);
9823 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9825 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9826 nodes.push_back(faceNodes[inode]);
9828 for ( inode = 1; inode < nbFaceNodes; inode += 2)
9829 nodes.push_back(faceNodes[inode]);
9831 // add new face based on volume nodes
9832 if (aMesh->FindFace( nodes ) )
9833 continue; // face already exsist
9834 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );