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 bool _outerFacesFound;
5938 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
5940 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
5941 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
5942 ~SMESH_ElementSearcherImpl()
5944 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5945 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5947 virtual int FindElementsByPoint(const gp_Pnt& point,
5948 SMDSAbs_ElementType type,
5949 vector< const SMDS_MeshElement* >& foundElements);
5950 virtual TopAbs_State GetPointState(const gp_Pnt& point);
5952 double getTolerance();
5953 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
5954 const double tolerance, double & param);
5955 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
5956 bool isOuterBoundary(const SMDS_MeshElement* face) const
5958 return _outerFaces.empty() || _outerFaces.count(face);
5960 struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
5962 const SMDS_MeshElement* _face;
5964 bool _coincides; //!< the line lays in face plane
5965 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
5966 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
5968 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
5971 TIDSortedElemSet _faces;
5972 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
5973 : _link( n1, n2 ), _faces( &face, &face + 1) {}
5977 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
5979 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
5980 << ", _coincides="<<i._coincides << ")";
5983 //=======================================================================
5985 * \brief define tolerance for search
5987 //=======================================================================
5989 double SMESH_ElementSearcherImpl::getTolerance()
5991 if ( _tolerance < 0 )
5993 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
5996 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
5998 double boxSize = _nodeSearcher->getTree()->maxSize();
5999 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6001 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6003 double boxSize = _ebbTree->maxSize();
6004 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6006 if ( _tolerance == 0 )
6008 // define tolerance by size of a most complex element
6009 int complexType = SMDSAbs_Volume;
6010 while ( complexType > SMDSAbs_All &&
6011 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6013 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6016 if ( complexType == int( SMDSAbs_Node ))
6018 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6020 if ( meshInfo.NbNodes() > 2 )
6021 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6025 const SMDS_MeshElement* elem =
6026 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6027 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6028 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6029 while ( nodeIt->more() )
6031 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6032 elemSize = max( dist, elemSize );
6035 _tolerance = 1e-6 * elemSize;
6041 //================================================================================
6043 * \brief Find intersection of the line and an edge of face and return parameter on line
6045 //================================================================================
6047 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6048 const SMDS_MeshElement* face,
6055 GeomAPI_ExtremaCurveCurve anExtCC;
6056 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6058 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6059 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6061 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6062 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6063 anExtCC.Init( lineCurve, edge);
6064 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6066 Quantity_Parameter pl, pe;
6067 anExtCC.LowerDistanceParameters( pl, pe );
6069 if ( ++nbInts == 2 )
6073 if ( nbInts > 0 ) param /= nbInts;
6076 //================================================================================
6078 * \brief Find all faces belonging to the outer boundary of mesh
6080 //================================================================================
6082 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6084 if ( _outerFacesFound ) return;
6086 // Collect all outer faces by passing from one outer face to another via their links
6087 // and BTW find out if there are internal faces at all.
6089 // checked links and links where outer boundary meets internal one
6090 set< SMESH_TLink > visitedLinks, seamLinks;
6092 // links to treat with already visited faces sharing them
6093 list < TFaceLink > startLinks;
6095 // load startLinks with the first outerFace
6096 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6097 _outerFaces.insert( outerFace );
6099 TIDSortedElemSet emptySet;
6100 while ( !startLinks.empty() )
6102 const SMESH_TLink& link = startLinks.front()._link;
6103 TIDSortedElemSet& faces = startLinks.front()._faces;
6105 outerFace = *faces.begin();
6106 // find other faces sharing the link
6107 const SMDS_MeshElement* f;
6108 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6111 // select another outer face among the found
6112 const SMDS_MeshElement* outerFace2 = 0;
6113 if ( faces.size() == 2 )
6115 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6117 else if ( faces.size() > 2 )
6119 seamLinks.insert( link );
6121 // link direction within the outerFace
6122 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6123 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6124 int i1 = outerFace->GetNodeIndex( link.node1() );
6125 int i2 = outerFace->GetNodeIndex( link.node2() );
6126 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6127 if ( rev ) n1n2.Reverse();
6129 gp_XYZ ofNorm, fNorm;
6130 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6132 // direction from the link inside outerFace
6133 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6134 // sort all other faces by angle with the dirInOF
6135 map< double, const SMDS_MeshElement* > angle2Face;
6136 set< const SMDS_MeshElement* >::const_iterator face = faces.begin();
6137 for ( ; face != faces.end(); ++face )
6139 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6141 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6142 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6143 if ( angle < 0 ) angle += 2*PI;
6144 angle2Face.insert( make_pair( angle, *face ));
6146 if ( !angle2Face.empty() )
6147 outerFace2 = angle2Face.begin()->second;
6150 // store the found outer face and add its links to continue seaching from
6153 _outerFaces.insert( outerFace );
6154 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6155 for ( int i = 0; i < nbNodes; ++i )
6157 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6158 if ( visitedLinks.insert( link2 ).second )
6159 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6162 startLinks.pop_front();
6164 _outerFacesFound = true;
6166 if ( !seamLinks.empty() )
6168 // There are internal boundaries touching the outher one,
6169 // find all faces of internal boundaries in order to find
6170 // faces of boundaries of holes, if any.
6175 _outerFaces.clear();
6179 //=======================================================================
6181 * \brief Find elements of given type where the given point is IN or ON.
6182 * Returns nb of found elements and elements them-selves.
6184 * 'ALL' type means elements of any type excluding nodes and 0D elements
6186 //=======================================================================
6188 int SMESH_ElementSearcherImpl::
6189 FindElementsByPoint(const gp_Pnt& point,
6190 SMDSAbs_ElementType type,
6191 vector< const SMDS_MeshElement* >& foundElements)
6193 foundElements.clear();
6195 double tolerance = getTolerance();
6197 // =================================================================================
6198 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6200 if ( !_nodeSearcher )
6201 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6203 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6204 if ( !closeNode ) return foundElements.size();
6206 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6207 return foundElements.size(); // to far from any node
6209 if ( type == SMDSAbs_Node )
6211 foundElements.push_back( closeNode );
6215 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6216 while ( elemIt->more() )
6217 foundElements.push_back( elemIt->next() );
6220 // =================================================================================
6221 else // elements more complex than 0D
6223 if ( !_ebbTree || _elementType != type )
6225 if ( _ebbTree ) delete _ebbTree;
6226 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6228 TIDSortedElemSet suspectElems;
6229 _ebbTree->getElementsNearPoint( point, suspectElems );
6230 TIDSortedElemSet::iterator elem = suspectElems.begin();
6231 for ( ; elem != suspectElems.end(); ++elem )
6232 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6233 foundElements.push_back( *elem );
6235 return foundElements.size();
6238 //================================================================================
6240 * \brief Classify the given point in the closed 2D mesh
6242 //================================================================================
6244 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6246 double tolerance = getTolerance();
6247 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6249 if ( _ebbTree ) delete _ebbTree;
6250 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6252 // Algo: analyse transition of a line starting at the point through mesh boundary;
6253 // try three lines parallel to axis of the coordinate system and perform rough
6254 // analysis. If solution is not clear perform thorough analysis.
6256 const int nbAxes = 3;
6257 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6258 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6259 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6260 multimap< int, int > nbInt2Axis; // to find the simplest case
6261 for ( int axis = 0; axis < nbAxes; ++axis )
6263 gp_Ax1 lineAxis( point, axisDir[axis]);
6264 gp_Lin line ( lineAxis );
6266 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6267 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6269 // Intersect faces with the line
6271 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6272 TIDSortedElemSet::iterator face = suspectFaces.begin();
6273 for ( ; face != suspectFaces.end(); ++face )
6277 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6278 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6280 // perform intersection
6281 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6282 if ( !intersection.IsDone() )
6284 if ( intersection.IsInQuadric() )
6286 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6288 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6290 gp_Pnt intersectionPoint = intersection.Point(1);
6291 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6292 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6295 // Analyse intersections roughly
6297 int nbInter = u2inters.size();
6301 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6302 if ( nbInter == 1 ) // not closed mesh
6303 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6305 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6308 if ( (f<0) == (l<0) )
6311 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6312 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6313 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6316 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6318 if ( _outerFacesFound ) break; // pass to thorough analysis
6320 } // three attempts - loop on CS axes
6322 // Analyse intersections thoroughly.
6323 // We make two loops maximum, on the first one we only exclude touching intersections,
6324 // on the second, if situation is still unclear, we gather and use information on
6325 // position of faces (internal or outer). If faces position is already gathered,
6326 // we make the second loop right away.
6328 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6330 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6331 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6333 int axis = nb_axis->second;
6334 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6336 gp_Ax1 lineAxis( point, axisDir[axis]);
6337 gp_Lin line ( lineAxis );
6339 // add tangent intersections to u2inters
6341 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6342 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6343 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6344 u2inters.insert(make_pair( param, *tgtInt ));
6345 tangentInters[ axis ].clear();
6347 // Count intersections before and after the point excluding touching ones.
6348 // If hasPositionInfo we count intersections of outer boundary only
6350 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6351 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6352 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6353 bool ok = ! u_int1->second._coincides;
6354 while ( ok && u_int1 != u2inters.end() )
6356 double u = u_int1->first;
6357 bool touchingInt = false;
6358 if ( ++u_int2 != u2inters.end() )
6360 // skip intersections at the same point (if the line passes through edge or node)
6362 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6368 // skip tangent intersections
6370 const SMDS_MeshElement* prevFace = u_int1->second._face;
6371 while ( ok && u_int2->second._coincides )
6373 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6379 ok = ( u_int2 != u2inters.end() );
6384 // skip intersections at the same point after tangent intersections
6387 double u2 = u_int2->first;
6389 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6395 // decide if we skipped a touching intersection
6396 if ( nbSamePnt + nbTgt > 0 )
6398 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6399 map< double, TInters >::iterator u_int = u_int1;
6400 for ( ; u_int != u_int2; ++u_int )
6402 if ( u_int->second._coincides ) continue;
6403 double dot = u_int->second._faceNorm * line.Direction();
6404 if ( dot > maxDot ) maxDot = dot;
6405 if ( dot < minDot ) minDot = dot;
6407 touchingInt = ( minDot*maxDot < 0 );
6412 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6423 u_int1 = u_int2; // to next intersection
6425 } // loop on intersections with one line
6429 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6432 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6435 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6436 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6438 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6441 if ( (f<0) == (l<0) )
6444 if ( hasPositionInfo )
6445 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6447 } // loop on intersections of the tree lines - thorough analysis
6449 if ( !hasPositionInfo )
6451 // gather info on faces position - is face in the outer boundary or not
6452 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6453 findOuterBoundary( u2inters.begin()->second._face );
6456 } // two attempts - with and w/o faces position info in the mesh
6458 return TopAbs_UNKNOWN;
6461 //=======================================================================
6463 * \brief Return SMESH_ElementSearcher
6465 //=======================================================================
6467 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6469 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6472 //=======================================================================
6474 * \brief Return true if the point is IN or ON of the element
6476 //=======================================================================
6478 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6480 if ( element->GetType() == SMDSAbs_Volume)
6482 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6485 // get ordered nodes
6487 vector< gp_XYZ > xyz;
6489 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6490 if ( element->IsQuadratic() )
6491 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6492 nodeIt = f->interlacedNodesElemIterator();
6493 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6494 nodeIt = e->interlacedNodesElemIterator();
6496 while ( nodeIt->more() )
6497 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6499 int i, nbNodes = element->NbNodes();
6501 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6503 // compute face normal
6504 gp_Vec faceNorm(0,0,0);
6505 xyz.push_back( xyz.front() );
6506 for ( i = 0; i < nbNodes; ++i )
6508 gp_Vec edge1( xyz[i+1], xyz[i]);
6509 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6510 faceNorm += edge1 ^ edge2;
6512 double normSize = faceNorm.Magnitude();
6513 if ( normSize <= tol )
6515 // degenerated face: point is out if it is out of all face edges
6516 for ( i = 0; i < nbNodes; ++i )
6518 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6519 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6520 SMDS_MeshEdge edge( &n1, &n2 );
6521 if ( !isOut( &edge, point, tol ))
6526 faceNorm /= normSize;
6528 // check if the point lays on face plane
6529 gp_Vec n2p( xyz[0], point );
6530 if ( fabs( n2p * faceNorm ) > tol )
6531 return true; // not on face plane
6533 // check if point is out of face boundary:
6534 // define it by closest transition of a ray point->infinity through face boundary
6535 // on the face plane.
6536 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6537 // to find intersections of the ray with the boundary.
6539 gp_Vec plnNorm = ray ^ faceNorm;
6540 normSize = plnNorm.Magnitude();
6541 if ( normSize <= tol ) return false; // point coincides with the first node
6542 plnNorm /= normSize;
6543 // for each node of the face, compute its signed distance to the plane
6544 vector<double> dist( nbNodes + 1);
6545 for ( i = 0; i < nbNodes; ++i )
6547 gp_Vec n2p( xyz[i], point );
6548 dist[i] = n2p * plnNorm;
6550 dist.back() = dist.front();
6551 // find the closest intersection
6553 double rClosest, distClosest = 1e100;;
6555 for ( i = 0; i < nbNodes; ++i )
6558 if ( fabs( dist[i]) < tol )
6560 else if ( fabs( dist[i+1]) < tol )
6562 else if ( dist[i] * dist[i+1] < 0 )
6563 r = dist[i] / ( dist[i] - dist[i+1] );
6565 continue; // no intersection
6566 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6567 gp_Vec p2int ( point, pInt);
6568 if ( p2int * ray > -tol ) // right half-space
6570 double intDist = p2int.SquareMagnitude();
6571 if ( intDist < distClosest )
6576 distClosest = intDist;
6581 return true; // no intesections - out
6583 // analyse transition
6584 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6585 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6586 gp_Vec p2int ( point, pClosest );
6587 bool out = (edgeNorm * p2int) < -tol;
6588 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6591 // ray pass through a face node; analyze transition through an adjacent edge
6592 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6593 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6594 gp_Vec edgeAdjacent( p1, p2 );
6595 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6596 bool out2 = (edgeNorm2 * p2int) < -tol;
6598 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6599 return covexCorner ? (out || out2) : (out && out2);
6601 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6603 // point is out of edge if it is NOT ON any straight part of edge
6604 // (we consider quadratic edge as being composed of two straight parts)
6605 for ( i = 1; i < nbNodes; ++i )
6607 gp_Vec edge( xyz[i-1], xyz[i]);
6608 gp_Vec n1p ( xyz[i-1], point);
6609 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6612 gp_Vec n2p( xyz[i], point );
6613 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6615 return false; // point is ON this part
6619 // Node or 0D element -------------------------------------------------------------------------
6621 gp_Vec n2p ( xyz[0], point );
6622 return n2p.Magnitude() <= tol;
6627 //=======================================================================
6628 //function : SimplifyFace
6630 //=======================================================================
6631 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6632 vector<const SMDS_MeshNode *>& poly_nodes,
6633 vector<int>& quantities) const
6635 int nbNodes = faceNodes.size();
6640 set<const SMDS_MeshNode*> nodeSet;
6642 // get simple seq of nodes
6643 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6644 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6645 int iSimple = 0, nbUnique = 0;
6647 simpleNodes[iSimple++] = faceNodes[0];
6649 for (int iCur = 1; iCur < nbNodes; iCur++) {
6650 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6651 simpleNodes[iSimple++] = faceNodes[iCur];
6652 if (nodeSet.insert( faceNodes[iCur] ).second)
6656 int nbSimple = iSimple;
6657 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6667 bool foundLoop = (nbSimple > nbUnique);
6670 set<const SMDS_MeshNode*> loopSet;
6671 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6672 const SMDS_MeshNode* n = simpleNodes[iSimple];
6673 if (!loopSet.insert( n ).second) {
6677 int iC = 0, curLast = iSimple;
6678 for (; iC < curLast; iC++) {
6679 if (simpleNodes[iC] == n) break;
6681 int loopLen = curLast - iC;
6683 // create sub-element
6685 quantities.push_back(loopLen);
6686 for (; iC < curLast; iC++) {
6687 poly_nodes.push_back(simpleNodes[iC]);
6690 // shift the rest nodes (place from the first loop position)
6691 for (iC = curLast + 1; iC < nbSimple; iC++) {
6692 simpleNodes[iC - loopLen] = simpleNodes[iC];
6694 nbSimple -= loopLen;
6697 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6698 } // while (foundLoop)
6702 quantities.push_back(iSimple);
6703 for (int i = 0; i < iSimple; i++)
6704 poly_nodes.push_back(simpleNodes[i]);
6710 //=======================================================================
6711 //function : MergeNodes
6712 //purpose : In each group, the cdr of nodes are substituted by the first one
6714 //=======================================================================
6716 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6718 myLastCreatedElems.Clear();
6719 myLastCreatedNodes.Clear();
6721 SMESHDS_Mesh* aMesh = GetMeshDS();
6723 TNodeNodeMap nodeNodeMap; // node to replace - new node
6724 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6725 list< int > rmElemIds, rmNodeIds;
6727 // Fill nodeNodeMap and elems
6729 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6730 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6731 list<const SMDS_MeshNode*>& nodes = *grIt;
6732 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6733 const SMDS_MeshNode* nToKeep = *nIt;
6734 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6735 const SMDS_MeshNode* nToRemove = *nIt;
6736 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6737 if ( nToRemove != nToKeep ) {
6738 rmNodeIds.push_back( nToRemove->GetID() );
6739 AddToSameGroups( nToKeep, nToRemove, aMesh );
6742 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6743 while ( invElemIt->more() ) {
6744 const SMDS_MeshElement* elem = invElemIt->next();
6749 // Change element nodes or remove an element
6751 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6752 for ( ; eIt != elems.end(); eIt++ ) {
6753 const SMDS_MeshElement* elem = *eIt;
6754 int nbNodes = elem->NbNodes();
6755 int aShapeId = FindShape( elem );
6757 set<const SMDS_MeshNode*> nodeSet;
6758 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6759 int iUnique = 0, iCur = 0, nbRepl = 0;
6760 vector<int> iRepl( nbNodes );
6762 // get new seq of nodes
6763 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6764 while ( itN->more() ) {
6765 const SMDS_MeshNode* n =
6766 static_cast<const SMDS_MeshNode*>( itN->next() );
6768 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6769 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6771 // BUG 0020185: begin
6773 bool stopRecur = false;
6774 set<const SMDS_MeshNode*> nodesRecur;
6775 nodesRecur.insert(n);
6776 while (!stopRecur) {
6777 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6778 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6779 n = (*nnIt_i).second;
6780 if (!nodesRecur.insert(n).second) {
6781 // error: recursive dependancy
6790 iRepl[ nbRepl++ ] = iCur;
6792 curNodes[ iCur ] = n;
6793 bool isUnique = nodeSet.insert( n ).second;
6795 uniqueNodes[ iUnique++ ] = n;
6799 // Analyse element topology after replacement
6802 int nbUniqueNodes = nodeSet.size();
6803 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6804 // Polygons and Polyhedral volumes
6805 if (elem->IsPoly()) {
6807 if (elem->GetType() == SMDSAbs_Face) {
6809 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6811 for (; inode < nbNodes; inode++) {
6812 face_nodes[inode] = curNodes[inode];
6815 vector<const SMDS_MeshNode *> polygons_nodes;
6816 vector<int> quantities;
6817 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6821 for (int iface = 0; iface < nbNew - 1; iface++) {
6822 int nbNodes = quantities[iface];
6823 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6824 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6825 poly_nodes[ii] = polygons_nodes[inode];
6827 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6828 myLastCreatedElems.Append(newElem);
6830 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6832 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6835 rmElemIds.push_back(elem->GetID());
6839 else if (elem->GetType() == SMDSAbs_Volume) {
6840 // Polyhedral volume
6841 if (nbUniqueNodes < 4) {
6842 rmElemIds.push_back(elem->GetID());
6845 // each face has to be analized in order to check volume validity
6846 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6847 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6849 int nbFaces = aPolyedre->NbFaces();
6851 vector<const SMDS_MeshNode *> poly_nodes;
6852 vector<int> quantities;
6854 for (int iface = 1; iface <= nbFaces; iface++) {
6855 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6856 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6858 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6859 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6860 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6861 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6862 faceNode = (*nnIt).second;
6864 faceNodes[inode - 1] = faceNode;
6867 SimplifyFace(faceNodes, poly_nodes, quantities);
6870 if (quantities.size() > 3) {
6871 // to be done: remove coincident faces
6874 if (quantities.size() > 3)
6875 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6877 rmElemIds.push_back(elem->GetID());
6881 rmElemIds.push_back(elem->GetID());
6892 switch ( nbNodes ) {
6893 case 2: ///////////////////////////////////// EDGE
6894 isOk = false; break;
6895 case 3: ///////////////////////////////////// TRIANGLE
6896 isOk = false; break;
6898 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6900 else { //////////////////////////////////// QUADRANGLE
6901 if ( nbUniqueNodes < 3 )
6903 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6904 isOk = false; // opposite nodes stick
6907 case 6: ///////////////////////////////////// PENTAHEDRON
6908 if ( nbUniqueNodes == 4 ) {
6909 // ---------------------------------> tetrahedron
6911 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6912 // all top nodes stick: reverse a bottom
6913 uniqueNodes[ 0 ] = curNodes [ 1 ];
6914 uniqueNodes[ 1 ] = curNodes [ 0 ];
6916 else if (nbRepl == 3 &&
6917 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6918 // all bottom nodes stick: set a top before
6919 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6920 uniqueNodes[ 0 ] = curNodes [ 3 ];
6921 uniqueNodes[ 1 ] = curNodes [ 4 ];
6922 uniqueNodes[ 2 ] = curNodes [ 5 ];
6924 else if (nbRepl == 4 &&
6925 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6926 // a lateral face turns into a line: reverse a bottom
6927 uniqueNodes[ 0 ] = curNodes [ 1 ];
6928 uniqueNodes[ 1 ] = curNodes [ 0 ];
6933 else if ( nbUniqueNodes == 5 ) {
6934 // PENTAHEDRON --------------------> 2 tetrahedrons
6935 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6936 // a bottom node sticks with a linked top one
6938 SMDS_MeshElement* newElem =
6939 aMesh->AddVolume(curNodes[ 3 ],
6942 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6943 myLastCreatedElems.Append(newElem);
6945 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6946 // 2. : reverse a bottom
6947 uniqueNodes[ 0 ] = curNodes [ 1 ];
6948 uniqueNodes[ 1 ] = curNodes [ 0 ];
6958 if(elem->IsQuadratic()) { // Quadratic quadrangle
6971 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6972 uniqueNodes[0] = curNodes[0];
6973 uniqueNodes[1] = curNodes[2];
6974 uniqueNodes[2] = curNodes[3];
6975 uniqueNodes[3] = curNodes[5];
6976 uniqueNodes[4] = curNodes[6];
6977 uniqueNodes[5] = curNodes[7];
6980 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6981 uniqueNodes[0] = curNodes[0];
6982 uniqueNodes[1] = curNodes[1];
6983 uniqueNodes[2] = curNodes[2];
6984 uniqueNodes[3] = curNodes[4];
6985 uniqueNodes[4] = curNodes[5];
6986 uniqueNodes[5] = curNodes[6];
6989 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6990 uniqueNodes[0] = curNodes[1];
6991 uniqueNodes[1] = curNodes[2];
6992 uniqueNodes[2] = curNodes[3];
6993 uniqueNodes[3] = curNodes[5];
6994 uniqueNodes[4] = curNodes[6];
6995 uniqueNodes[5] = curNodes[0];
6998 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
6999 uniqueNodes[0] = curNodes[0];
7000 uniqueNodes[1] = curNodes[1];
7001 uniqueNodes[2] = curNodes[3];
7002 uniqueNodes[3] = curNodes[4];
7003 uniqueNodes[4] = curNodes[6];
7004 uniqueNodes[5] = curNodes[7];
7007 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7008 uniqueNodes[0] = curNodes[0];
7009 uniqueNodes[1] = curNodes[2];
7010 uniqueNodes[2] = curNodes[3];
7011 uniqueNodes[3] = curNodes[1];
7012 uniqueNodes[4] = curNodes[6];
7013 uniqueNodes[5] = curNodes[7];
7016 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7017 uniqueNodes[0] = curNodes[0];
7018 uniqueNodes[1] = curNodes[1];
7019 uniqueNodes[2] = curNodes[2];
7020 uniqueNodes[3] = curNodes[4];
7021 uniqueNodes[4] = curNodes[5];
7022 uniqueNodes[5] = curNodes[7];
7025 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7026 uniqueNodes[0] = curNodes[0];
7027 uniqueNodes[1] = curNodes[1];
7028 uniqueNodes[2] = curNodes[3];
7029 uniqueNodes[3] = curNodes[4];
7030 uniqueNodes[4] = curNodes[2];
7031 uniqueNodes[5] = curNodes[7];
7034 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7035 uniqueNodes[0] = curNodes[0];
7036 uniqueNodes[1] = curNodes[1];
7037 uniqueNodes[2] = curNodes[2];
7038 uniqueNodes[3] = curNodes[4];
7039 uniqueNodes[4] = curNodes[5];
7040 uniqueNodes[5] = curNodes[3];
7046 //////////////////////////////////// HEXAHEDRON
7048 SMDS_VolumeTool hexa (elem);
7049 hexa.SetExternalNormal();
7050 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7051 //////////////////////// ---> tetrahedron
7052 for ( int iFace = 0; iFace < 6; iFace++ ) {
7053 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7054 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7055 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7056 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7057 // one face turns into a point ...
7058 int iOppFace = hexa.GetOppFaceIndex( iFace );
7059 ind = hexa.GetFaceNodesIndices( iOppFace );
7061 iUnique = 2; // reverse a tetrahedron bottom
7062 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7063 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7065 else if ( iUnique >= 0 )
7066 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7068 if ( nbStick == 1 ) {
7069 // ... and the opposite one - into a triangle.
7071 ind = hexa.GetFaceNodesIndices( iFace );
7072 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7079 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7080 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7081 for ( int iFace = 0; iFace < 6; iFace++ ) {
7082 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7083 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7084 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7085 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7086 // one face turns into a point ...
7087 int iOppFace = hexa.GetOppFaceIndex( iFace );
7088 ind = hexa.GetFaceNodesIndices( iOppFace );
7090 iUnique = 2; // reverse a tetrahedron 1 bottom
7091 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7092 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7094 else if ( iUnique >= 0 )
7095 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7097 if ( nbStick == 0 ) {
7098 // ... and the opposite one is a quadrangle
7100 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7101 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7104 SMDS_MeshElement* newElem =
7105 aMesh->AddVolume(curNodes[ind[ 0 ]],
7108 curNodes[indTop[ 0 ]]);
7109 myLastCreatedElems.Append(newElem);
7111 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7118 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7119 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7120 // find indices of quad and tri faces
7121 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7122 for ( iFace = 0; iFace < 6; iFace++ ) {
7123 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7125 for ( iCur = 0; iCur < 4; iCur++ )
7126 nodeSet.insert( curNodes[ind[ iCur ]] );
7127 nbUniqueNodes = nodeSet.size();
7128 if ( nbUniqueNodes == 3 )
7129 iTriFace[ nbTri++ ] = iFace;
7130 else if ( nbUniqueNodes == 4 )
7131 iQuadFace[ nbQuad++ ] = iFace;
7133 if (nbQuad == 2 && nbTri == 4 &&
7134 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7135 // 2 opposite quadrangles stuck with a diagonal;
7136 // sample groups of merged indices: (0-4)(2-6)
7137 // --------------------------------------------> 2 tetrahedrons
7138 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7139 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7140 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7141 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7142 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7143 // stuck with 0-2 diagonal
7151 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7152 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7153 // stuck with 1-3 diagonal
7165 uniqueNodes[ 0 ] = curNodes [ i0 ];
7166 uniqueNodes[ 1 ] = curNodes [ i1d ];
7167 uniqueNodes[ 2 ] = curNodes [ i3d ];
7168 uniqueNodes[ 3 ] = curNodes [ i0t ];
7171 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7175 myLastCreatedElems.Append(newElem);
7177 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7180 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7181 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7182 // --------------------------------------------> prism
7183 // find 2 opposite triangles
7185 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7186 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7187 // find indices of kept and replaced nodes
7188 // and fill unique nodes of 2 opposite triangles
7189 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7190 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7191 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7192 // fill unique nodes
7195 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7196 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7197 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7199 // iCur of a linked node of the opposite face (make normals co-directed):
7200 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7201 // check that correspondent corners of triangles are linked
7202 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7205 uniqueNodes[ iUnique ] = n;
7206 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7215 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7221 } // switch ( nbNodes )
7223 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7226 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7227 // Change nodes of polyedre
7228 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7229 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7231 int nbFaces = aPolyedre->NbFaces();
7233 vector<const SMDS_MeshNode *> poly_nodes;
7234 vector<int> quantities (nbFaces);
7236 for (int iface = 1; iface <= nbFaces; iface++) {
7237 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7238 quantities[iface - 1] = nbFaceNodes;
7240 for (inode = 1; inode <= nbFaceNodes; inode++) {
7241 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7243 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7244 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7245 curNode = (*nnIt).second;
7247 poly_nodes.push_back(curNode);
7250 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7254 // Change regular element or polygon
7255 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7259 // Remove invalid regular element or invalid polygon
7260 rmElemIds.push_back( elem->GetID() );
7263 } // loop on elements
7265 // Remove equal nodes and bad elements
7267 Remove( rmNodeIds, true );
7268 Remove( rmElemIds, false );
7273 // ========================================================
7274 // class : SortableElement
7275 // purpose : allow sorting elements basing on their nodes
7276 // ========================================================
7277 class SortableElement : public set <const SMDS_MeshElement*>
7281 SortableElement( const SMDS_MeshElement* theElem )
7284 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7285 while ( nodeIt->more() )
7286 this->insert( nodeIt->next() );
7289 const SMDS_MeshElement* Get() const
7292 void Set(const SMDS_MeshElement* e) const
7297 mutable const SMDS_MeshElement* myElem;
7300 //=======================================================================
7301 //function : FindEqualElements
7302 //purpose : Return list of group of elements built on the same nodes.
7303 // Search among theElements or in the whole mesh if theElements is empty
7304 //=======================================================================
7305 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7306 TListOfListOfElementsID & theGroupsOfElementsID)
7308 myLastCreatedElems.Clear();
7309 myLastCreatedNodes.Clear();
7311 typedef set<const SMDS_MeshElement*> TElemsSet;
7312 typedef map< SortableElement, int > TMapOfNodeSet;
7313 typedef list<int> TGroupOfElems;
7316 if ( theElements.empty() )
7317 { // get all elements in the mesh
7318 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7319 while ( eIt->more() )
7320 elems.insert( elems.end(), eIt->next());
7323 elems = theElements;
7325 vector< TGroupOfElems > arrayOfGroups;
7326 TGroupOfElems groupOfElems;
7327 TMapOfNodeSet mapOfNodeSet;
7329 TElemsSet::iterator elemIt = elems.begin();
7330 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7331 const SMDS_MeshElement* curElem = *elemIt;
7332 SortableElement SE(curElem);
7335 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7336 if( !(pp.second) ) {
7337 TMapOfNodeSet::iterator& itSE = pp.first;
7338 ind = (*itSE).second;
7339 arrayOfGroups[ind].push_back(curElem->GetID());
7342 groupOfElems.clear();
7343 groupOfElems.push_back(curElem->GetID());
7344 arrayOfGroups.push_back(groupOfElems);
7349 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7350 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7351 groupOfElems = *groupIt;
7352 if ( groupOfElems.size() > 1 ) {
7353 groupOfElems.sort();
7354 theGroupsOfElementsID.push_back(groupOfElems);
7359 //=======================================================================
7360 //function : MergeElements
7361 //purpose : In each given group, substitute all elements by the first one.
7362 //=======================================================================
7364 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7366 myLastCreatedElems.Clear();
7367 myLastCreatedNodes.Clear();
7369 typedef list<int> TListOfIDs;
7370 TListOfIDs rmElemIds; // IDs of elems to remove
7372 SMESHDS_Mesh* aMesh = GetMeshDS();
7374 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7375 while ( groupsIt != theGroupsOfElementsID.end() ) {
7376 TListOfIDs& aGroupOfElemID = *groupsIt;
7377 aGroupOfElemID.sort();
7378 int elemIDToKeep = aGroupOfElemID.front();
7379 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7380 aGroupOfElemID.pop_front();
7381 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7382 while ( idIt != aGroupOfElemID.end() ) {
7383 int elemIDToRemove = *idIt;
7384 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7385 // add the kept element in groups of removed one (PAL15188)
7386 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7387 rmElemIds.push_back( elemIDToRemove );
7393 Remove( rmElemIds, false );
7396 //=======================================================================
7397 //function : MergeEqualElements
7398 //purpose : Remove all but one of elements built on the same nodes.
7399 //=======================================================================
7401 void SMESH_MeshEditor::MergeEqualElements()
7403 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7404 to merge equal elements in the whole mesh */
7405 TListOfListOfElementsID aGroupsOfElementsID;
7406 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7407 MergeElements(aGroupsOfElementsID);
7410 //=======================================================================
7411 //function : FindFaceInSet
7412 //purpose : Return a face having linked nodes n1 and n2 and which is
7413 // - not in avoidSet,
7414 // - in elemSet provided that !elemSet.empty()
7415 // i1 and i2 optionally returns indices of n1 and n2
7416 //=======================================================================
7418 const SMDS_MeshElement*
7419 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7420 const SMDS_MeshNode* n2,
7421 const TIDSortedElemSet& elemSet,
7422 const TIDSortedElemSet& avoidSet,
7428 const SMDS_MeshElement* face = 0;
7430 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7431 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7433 const SMDS_MeshElement* elem = invElemIt->next();
7434 if (avoidSet.count( elem ))
7436 if ( !elemSet.empty() && !elemSet.count( elem ))
7439 i1 = elem->GetNodeIndex( n1 );
7440 // find a n2 linked to n1
7441 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7442 for ( int di = -1; di < 2 && !face; di += 2 )
7444 i2 = (i1+di+nbN) % nbN;
7445 if ( elem->GetNode( i2 ) == n2 )
7448 if ( !face && elem->IsQuadratic())
7450 // analysis for quadratic elements using all nodes
7451 const SMDS_QuadraticFaceOfNodes* F =
7452 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7453 // use special nodes iterator
7454 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7455 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7456 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7458 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7459 if ( n1 == prevN && n2 == n )
7463 else if ( n2 == prevN && n1 == n )
7465 face = elem; swap( i1, i2 );
7471 if ( n1ind ) *n1ind = i1;
7472 if ( n2ind ) *n2ind = i2;
7476 //=======================================================================
7477 //function : findAdjacentFace
7479 //=======================================================================
7481 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7482 const SMDS_MeshNode* n2,
7483 const SMDS_MeshElement* elem)
7485 TIDSortedElemSet elemSet, avoidSet;
7487 avoidSet.insert ( elem );
7488 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7491 //=======================================================================
7492 //function : FindFreeBorder
7494 //=======================================================================
7496 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7498 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7499 const SMDS_MeshNode* theSecondNode,
7500 const SMDS_MeshNode* theLastNode,
7501 list< const SMDS_MeshNode* > & theNodes,
7502 list< const SMDS_MeshElement* >& theFaces)
7504 if ( !theFirstNode || !theSecondNode )
7506 // find border face between theFirstNode and theSecondNode
7507 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7511 theFaces.push_back( curElem );
7512 theNodes.push_back( theFirstNode );
7513 theNodes.push_back( theSecondNode );
7515 //vector<const SMDS_MeshNode*> nodes;
7516 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7517 TIDSortedElemSet foundElems;
7518 bool needTheLast = ( theLastNode != 0 );
7520 while ( nStart != theLastNode ) {
7521 if ( nStart == theFirstNode )
7522 return !needTheLast;
7524 // find all free border faces sharing form nStart
7526 list< const SMDS_MeshElement* > curElemList;
7527 list< const SMDS_MeshNode* > nStartList;
7528 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7529 while ( invElemIt->more() ) {
7530 const SMDS_MeshElement* e = invElemIt->next();
7531 if ( e == curElem || foundElems.insert( e ).second ) {
7533 int iNode = 0, nbNodes = e->NbNodes();
7534 //const SMDS_MeshNode* nodes[nbNodes+1];
7535 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7537 if(e->IsQuadratic()) {
7538 const SMDS_QuadraticFaceOfNodes* F =
7539 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7540 // use special nodes iterator
7541 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7542 while( anIter->more() ) {
7543 nodes[ iNode++ ] = anIter->next();
7547 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7548 while ( nIt->more() )
7549 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7551 nodes[ iNode ] = nodes[ 0 ];
7553 for ( iNode = 0; iNode < nbNodes; iNode++ )
7554 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7555 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7556 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7558 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7559 curElemList.push_back( e );
7563 // analyse the found
7565 int nbNewBorders = curElemList.size();
7566 if ( nbNewBorders == 0 ) {
7567 // no free border furthermore
7568 return !needTheLast;
7570 else if ( nbNewBorders == 1 ) {
7571 // one more element found
7573 nStart = nStartList.front();
7574 curElem = curElemList.front();
7575 theFaces.push_back( curElem );
7576 theNodes.push_back( nStart );
7579 // several continuations found
7580 list< const SMDS_MeshElement* >::iterator curElemIt;
7581 list< const SMDS_MeshNode* >::iterator nStartIt;
7582 // check if one of them reached the last node
7583 if ( needTheLast ) {
7584 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7585 curElemIt!= curElemList.end();
7586 curElemIt++, nStartIt++ )
7587 if ( *nStartIt == theLastNode ) {
7588 theFaces.push_back( *curElemIt );
7589 theNodes.push_back( *nStartIt );
7593 // find the best free border by the continuations
7594 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7595 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7596 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7597 curElemIt!= curElemList.end();
7598 curElemIt++, nStartIt++ )
7600 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7601 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7602 // find one more free border
7603 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7607 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7608 // choice: clear a worse one
7609 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7610 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7611 contNodes[ iWorse ].clear();
7612 contFaces[ iWorse ].clear();
7615 if ( contNodes[0].empty() && contNodes[1].empty() )
7618 // append the best free border
7619 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7620 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7621 theNodes.pop_back(); // remove nIgnore
7622 theNodes.pop_back(); // remove nStart
7623 theFaces.pop_back(); // remove curElem
7624 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7625 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7626 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7627 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7630 } // several continuations found
7631 } // while ( nStart != theLastNode )
7636 //=======================================================================
7637 //function : CheckFreeBorderNodes
7638 //purpose : Return true if the tree nodes are on a free border
7639 //=======================================================================
7641 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7642 const SMDS_MeshNode* theNode2,
7643 const SMDS_MeshNode* theNode3)
7645 list< const SMDS_MeshNode* > nodes;
7646 list< const SMDS_MeshElement* > faces;
7647 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7650 //=======================================================================
7651 //function : SewFreeBorder
7653 //=======================================================================
7655 SMESH_MeshEditor::Sew_Error
7656 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7657 const SMDS_MeshNode* theBordSecondNode,
7658 const SMDS_MeshNode* theBordLastNode,
7659 const SMDS_MeshNode* theSideFirstNode,
7660 const SMDS_MeshNode* theSideSecondNode,
7661 const SMDS_MeshNode* theSideThirdNode,
7662 const bool theSideIsFreeBorder,
7663 const bool toCreatePolygons,
7664 const bool toCreatePolyedrs)
7666 myLastCreatedElems.Clear();
7667 myLastCreatedNodes.Clear();
7669 MESSAGE("::SewFreeBorder()");
7670 Sew_Error aResult = SEW_OK;
7672 // ====================================
7673 // find side nodes and elements
7674 // ====================================
7676 list< const SMDS_MeshNode* > nSide[ 2 ];
7677 list< const SMDS_MeshElement* > eSide[ 2 ];
7678 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7679 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7683 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7684 nSide[0], eSide[0])) {
7685 MESSAGE(" Free Border 1 not found " );
7686 aResult = SEW_BORDER1_NOT_FOUND;
7688 if (theSideIsFreeBorder) {
7691 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7692 nSide[1], eSide[1])) {
7693 MESSAGE(" Free Border 2 not found " );
7694 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7697 if ( aResult != SEW_OK )
7700 if (!theSideIsFreeBorder) {
7704 // -------------------------------------------------------------------------
7706 // 1. If nodes to merge are not coincident, move nodes of the free border
7707 // from the coord sys defined by the direction from the first to last
7708 // nodes of the border to the correspondent sys of the side 2
7709 // 2. On the side 2, find the links most co-directed with the correspondent
7710 // links of the free border
7711 // -------------------------------------------------------------------------
7713 // 1. Since sewing may brake if there are volumes to split on the side 2,
7714 // we wont move nodes but just compute new coordinates for them
7715 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7716 TNodeXYZMap nBordXYZ;
7717 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7718 list< const SMDS_MeshNode* >::iterator nBordIt;
7720 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7721 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7722 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7723 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7724 double tol2 = 1.e-8;
7725 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7726 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7727 // Need node movement.
7729 // find X and Z axes to create trsf
7730 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7732 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7734 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7737 gp_Ax3 toBordAx( Pb1, Zb, X );
7738 gp_Ax3 fromSideAx( Ps1, Zs, X );
7739 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7741 gp_Trsf toBordSys, fromSide2Sys;
7742 toBordSys.SetTransformation( toBordAx );
7743 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7744 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7747 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7748 const SMDS_MeshNode* n = *nBordIt;
7749 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7750 toBordSys.Transforms( xyz );
7751 fromSide2Sys.Transforms( xyz );
7752 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7756 // just insert nodes XYZ in the nBordXYZ map
7757 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7758 const SMDS_MeshNode* n = *nBordIt;
7759 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7763 // 2. On the side 2, find the links most co-directed with the correspondent
7764 // links of the free border
7766 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7767 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7768 sideNodes.push_back( theSideFirstNode );
7770 bool hasVolumes = false;
7771 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7772 set<long> foundSideLinkIDs, checkedLinkIDs;
7773 SMDS_VolumeTool volume;
7774 //const SMDS_MeshNode* faceNodes[ 4 ];
7776 const SMDS_MeshNode* sideNode;
7777 const SMDS_MeshElement* sideElem;
7778 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7779 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7780 nBordIt = bordNodes.begin();
7782 // border node position and border link direction to compare with
7783 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7784 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7785 // choose next side node by link direction or by closeness to
7786 // the current border node:
7787 bool searchByDir = ( *nBordIt != theBordLastNode );
7789 // find the next node on the Side 2
7791 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7793 checkedLinkIDs.clear();
7794 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7796 // loop on inverse elements of current node (prevSideNode) on the Side 2
7797 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7798 while ( invElemIt->more() )
7800 const SMDS_MeshElement* elem = invElemIt->next();
7801 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7802 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7803 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7804 bool isVolume = volume.Set( elem );
7805 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7806 if ( isVolume ) // --volume
7808 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7809 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7810 if(elem->IsQuadratic()) {
7811 const SMDS_QuadraticFaceOfNodes* F =
7812 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7813 // use special nodes iterator
7814 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7815 while( anIter->more() ) {
7816 nodes[ iNode ] = anIter->next();
7817 if ( nodes[ iNode++ ] == prevSideNode )
7818 iPrevNode = iNode - 1;
7822 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7823 while ( nIt->more() ) {
7824 nodes[ iNode ] = cast2Node( nIt->next() );
7825 if ( nodes[ iNode++ ] == prevSideNode )
7826 iPrevNode = iNode - 1;
7829 // there are 2 links to check
7834 // loop on links, to be precise, on the second node of links
7835 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7836 const SMDS_MeshNode* n = nodes[ iNode ];
7838 if ( !volume.IsLinked( n, prevSideNode ))
7842 if ( iNode ) // a node before prevSideNode
7843 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7844 else // a node after prevSideNode
7845 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7847 // check if this link was already used
7848 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7849 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7850 if (!isJustChecked &&
7851 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7853 // test a link geometrically
7854 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7855 bool linkIsBetter = false;
7856 double dot = 0.0, dist = 0.0;
7857 if ( searchByDir ) { // choose most co-directed link
7858 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7859 linkIsBetter = ( dot > maxDot );
7861 else { // choose link with the node closest to bordPos
7862 dist = ( nextXYZ - bordPos ).SquareModulus();
7863 linkIsBetter = ( dist < minDist );
7865 if ( linkIsBetter ) {
7874 } // loop on inverse elements of prevSideNode
7877 MESSAGE(" Cant find path by links of the Side 2 ");
7878 return SEW_BAD_SIDE_NODES;
7880 sideNodes.push_back( sideNode );
7881 sideElems.push_back( sideElem );
7882 foundSideLinkIDs.insert ( linkID );
7883 prevSideNode = sideNode;
7885 if ( *nBordIt == theBordLastNode )
7886 searchByDir = false;
7888 // find the next border link to compare with
7889 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7890 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7891 // move to next border node if sideNode is before forward border node (bordPos)
7892 while ( *nBordIt != theBordLastNode && !searchByDir ) {
7893 prevBordNode = *nBordIt;
7895 bordPos = nBordXYZ[ *nBordIt ];
7896 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7897 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7901 while ( sideNode != theSideSecondNode );
7903 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7904 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7905 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7907 } // end nodes search on the side 2
7909 // ============================
7910 // sew the border to the side 2
7911 // ============================
7913 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7914 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7916 TListOfListOfNodes nodeGroupsToMerge;
7917 if ( nbNodes[0] == nbNodes[1] ||
7918 ( theSideIsFreeBorder && !theSideThirdNode)) {
7920 // all nodes are to be merged
7922 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7923 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7924 nIt[0]++, nIt[1]++ )
7926 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7927 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7928 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7933 // insert new nodes into the border and the side to get equal nb of segments
7935 // get normalized parameters of nodes on the borders
7936 //double param[ 2 ][ maxNbNodes ];
7938 param[0] = new double [ maxNbNodes ];
7939 param[1] = new double [ maxNbNodes ];
7941 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7942 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7943 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7944 const SMDS_MeshNode* nPrev = *nIt;
7945 double bordLength = 0;
7946 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7947 const SMDS_MeshNode* nCur = *nIt;
7948 gp_XYZ segment (nCur->X() - nPrev->X(),
7949 nCur->Y() - nPrev->Y(),
7950 nCur->Z() - nPrev->Z());
7951 double segmentLen = segment.Modulus();
7952 bordLength += segmentLen;
7953 param[ iBord ][ iNode ] = bordLength;
7956 // normalize within [0,1]
7957 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7958 param[ iBord ][ iNode ] /= bordLength;
7962 // loop on border segments
7963 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7964 int i[ 2 ] = { 0, 0 };
7965 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7966 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7968 TElemOfNodeListMap insertMap;
7969 TElemOfNodeListMap::iterator insertMapIt;
7971 // key: elem to insert nodes into
7972 // value: 2 nodes to insert between + nodes to be inserted
7974 bool next[ 2 ] = { false, false };
7976 // find min adjacent segment length after sewing
7977 double nextParam = 10., prevParam = 0;
7978 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7979 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7980 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7981 if ( i[ iBord ] > 0 )
7982 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7984 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7985 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7986 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7988 // choose to insert or to merge nodes
7989 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7990 if ( Abs( du ) <= minSegLen * 0.2 ) {
7993 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7994 const SMDS_MeshNode* n0 = *nIt[0];
7995 const SMDS_MeshNode* n1 = *nIt[1];
7996 nodeGroupsToMerge.back().push_back( n1 );
7997 nodeGroupsToMerge.back().push_back( n0 );
7998 // position of node of the border changes due to merge
7999 param[ 0 ][ i[0] ] += du;
8000 // move n1 for the sake of elem shape evaluation during insertion.
8001 // n1 will be removed by MergeNodes() anyway
8002 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8003 next[0] = next[1] = true;
8008 int intoBord = ( du < 0 ) ? 0 : 1;
8009 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8010 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8011 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8012 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8013 if ( intoBord == 1 ) {
8014 // move node of the border to be on a link of elem of the side
8015 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8016 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8017 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8018 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8019 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8021 insertMapIt = insertMap.find( elem );
8022 bool notFound = ( insertMapIt == insertMap.end() );
8023 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8025 // insert into another link of the same element:
8026 // 1. perform insertion into the other link of the elem
8027 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8028 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8029 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8030 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8031 // 2. perform insertion into the link of adjacent faces
8033 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8035 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8039 if (toCreatePolyedrs) {
8040 // perform insertion into the links of adjacent volumes
8041 UpdateVolumes(n12, n22, nodeList);
8043 // 3. find an element appeared on n1 and n2 after the insertion
8044 insertMap.erase( elem );
8045 elem = findAdjacentFace( n1, n2, 0 );
8047 if ( notFound || otherLink ) {
8048 // add element and nodes of the side into the insertMap
8049 insertMapIt = insertMap.insert
8050 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8051 (*insertMapIt).second.push_back( n1 );
8052 (*insertMapIt).second.push_back( n2 );
8054 // add node to be inserted into elem
8055 (*insertMapIt).second.push_back( nIns );
8056 next[ 1 - intoBord ] = true;
8059 // go to the next segment
8060 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8061 if ( next[ iBord ] ) {
8062 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8064 nPrev[ iBord ] = *nIt[ iBord ];
8065 nIt[ iBord ]++; i[ iBord ]++;
8069 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8071 // perform insertion of nodes into elements
8073 for (insertMapIt = insertMap.begin();
8074 insertMapIt != insertMap.end();
8077 const SMDS_MeshElement* elem = (*insertMapIt).first;
8078 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8079 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8080 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8082 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8084 if ( !theSideIsFreeBorder ) {
8085 // look for and insert nodes into the faces adjacent to elem
8087 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8089 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8094 if (toCreatePolyedrs) {
8095 // perform insertion into the links of adjacent volumes
8096 UpdateVolumes(n1, n2, nodeList);
8102 } // end: insert new nodes
8104 MergeNodes ( nodeGroupsToMerge );
8109 //=======================================================================
8110 //function : InsertNodesIntoLink
8111 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8112 // and theBetweenNode2 and split theElement
8113 //=======================================================================
8115 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8116 const SMDS_MeshNode* theBetweenNode1,
8117 const SMDS_MeshNode* theBetweenNode2,
8118 list<const SMDS_MeshNode*>& theNodesToInsert,
8119 const bool toCreatePoly)
8121 if ( theFace->GetType() != SMDSAbs_Face ) return;
8123 // find indices of 2 link nodes and of the rest nodes
8124 int iNode = 0, il1, il2, i3, i4;
8125 il1 = il2 = i3 = i4 = -1;
8126 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8127 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8129 if(theFace->IsQuadratic()) {
8130 const SMDS_QuadraticFaceOfNodes* F =
8131 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8132 // use special nodes iterator
8133 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8134 while( anIter->more() ) {
8135 const SMDS_MeshNode* n = anIter->next();
8136 if ( n == theBetweenNode1 )
8138 else if ( n == theBetweenNode2 )
8144 nodes[ iNode++ ] = n;
8148 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8149 while ( nodeIt->more() ) {
8150 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8151 if ( n == theBetweenNode1 )
8153 else if ( n == theBetweenNode2 )
8159 nodes[ iNode++ ] = n;
8162 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8165 // arrange link nodes to go one after another regarding the face orientation
8166 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8167 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8172 aNodesToInsert.reverse();
8174 // check that not link nodes of a quadrangles are in good order
8175 int nbFaceNodes = theFace->NbNodes();
8176 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8182 if (toCreatePoly || theFace->IsPoly()) {
8185 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8187 // add nodes of face up to first node of link
8190 if(theFace->IsQuadratic()) {
8191 const SMDS_QuadraticFaceOfNodes* F =
8192 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8193 // use special nodes iterator
8194 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8195 while( anIter->more() && !isFLN ) {
8196 const SMDS_MeshNode* n = anIter->next();
8197 poly_nodes[iNode++] = n;
8198 if (n == nodes[il1]) {
8202 // add nodes to insert
8203 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8204 for (; nIt != aNodesToInsert.end(); nIt++) {
8205 poly_nodes[iNode++] = *nIt;
8207 // add nodes of face starting from last node of link
8208 while ( anIter->more() ) {
8209 poly_nodes[iNode++] = anIter->next();
8213 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8214 while ( nodeIt->more() && !isFLN ) {
8215 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8216 poly_nodes[iNode++] = n;
8217 if (n == nodes[il1]) {
8221 // add nodes to insert
8222 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8223 for (; nIt != aNodesToInsert.end(); nIt++) {
8224 poly_nodes[iNode++] = *nIt;
8226 // add nodes of face starting from last node of link
8227 while ( nodeIt->more() ) {
8228 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8229 poly_nodes[iNode++] = n;
8233 // edit or replace the face
8234 SMESHDS_Mesh *aMesh = GetMeshDS();
8236 if (theFace->IsPoly()) {
8237 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8240 int aShapeId = FindShape( theFace );
8242 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8243 myLastCreatedElems.Append(newElem);
8244 if ( aShapeId && newElem )
8245 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8247 aMesh->RemoveElement(theFace);
8252 if( !theFace->IsQuadratic() ) {
8254 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8255 int nbLinkNodes = 2 + aNodesToInsert.size();
8256 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8257 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8258 linkNodes[ 0 ] = nodes[ il1 ];
8259 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8260 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8261 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8262 linkNodes[ iNode++ ] = *nIt;
8264 // decide how to split a quadrangle: compare possible variants
8265 // and choose which of splits to be a quadrangle
8266 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8267 if ( nbFaceNodes == 3 ) {
8268 iBestQuad = nbSplits;
8271 else if ( nbFaceNodes == 4 ) {
8272 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8273 double aBestRate = DBL_MAX;
8274 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8276 double aBadRate = 0;
8277 // evaluate elements quality
8278 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8279 if ( iSplit == iQuad ) {
8280 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8284 aBadRate += getBadRate( &quad, aCrit );
8287 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8289 nodes[ iSplit < iQuad ? i4 : i3 ]);
8290 aBadRate += getBadRate( &tria, aCrit );
8294 if ( aBadRate < aBestRate ) {
8296 aBestRate = aBadRate;
8301 // create new elements
8302 SMESHDS_Mesh *aMesh = GetMeshDS();
8303 int aShapeId = FindShape( theFace );
8306 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8307 SMDS_MeshElement* newElem = 0;
8308 if ( iSplit == iBestQuad )
8309 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8314 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8316 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8317 myLastCreatedElems.Append(newElem);
8318 if ( aShapeId && newElem )
8319 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8322 // change nodes of theFace
8323 const SMDS_MeshNode* newNodes[ 4 ];
8324 newNodes[ 0 ] = linkNodes[ i1 ];
8325 newNodes[ 1 ] = linkNodes[ i2 ];
8326 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8327 newNodes[ 3 ] = nodes[ i4 ];
8328 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8329 } // end if(!theFace->IsQuadratic())
8330 else { // theFace is quadratic
8331 // we have to split theFace on simple triangles and one simple quadrangle
8333 int nbshift = tmp*2;
8334 // shift nodes in nodes[] by nbshift
8336 for(i=0; i<nbshift; i++) {
8337 const SMDS_MeshNode* n = nodes[0];
8338 for(j=0; j<nbFaceNodes-1; j++) {
8339 nodes[j] = nodes[j+1];
8341 nodes[nbFaceNodes-1] = n;
8343 il1 = il1 - nbshift;
8344 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8345 // n0 n1 n2 n0 n1 n2
8346 // +-----+-----+ +-----+-----+
8355 // create new elements
8356 SMESHDS_Mesh *aMesh = GetMeshDS();
8357 int aShapeId = FindShape( theFace );
8360 if(nbFaceNodes==6) { // quadratic triangle
8361 SMDS_MeshElement* newElem =
8362 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8363 myLastCreatedElems.Append(newElem);
8364 if ( aShapeId && newElem )
8365 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8366 if(theFace->IsMediumNode(nodes[il1])) {
8367 // create quadrangle
8368 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8369 myLastCreatedElems.Append(newElem);
8370 if ( aShapeId && newElem )
8371 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8377 // create quadrangle
8378 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8379 myLastCreatedElems.Append(newElem);
8380 if ( aShapeId && newElem )
8381 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8387 else { // nbFaceNodes==8 - quadratic quadrangle
8388 SMDS_MeshElement* newElem =
8389 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8390 myLastCreatedElems.Append(newElem);
8391 if ( aShapeId && newElem )
8392 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8393 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8394 myLastCreatedElems.Append(newElem);
8395 if ( aShapeId && newElem )
8396 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8397 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8398 myLastCreatedElems.Append(newElem);
8399 if ( aShapeId && newElem )
8400 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8401 if(theFace->IsMediumNode(nodes[il1])) {
8402 // create quadrangle
8403 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8404 myLastCreatedElems.Append(newElem);
8405 if ( aShapeId && newElem )
8406 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8412 // create quadrangle
8413 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8414 myLastCreatedElems.Append(newElem);
8415 if ( aShapeId && newElem )
8416 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8422 // create needed triangles using n1,n2,n3 and inserted nodes
8423 int nbn = 2 + aNodesToInsert.size();
8424 //const SMDS_MeshNode* aNodes[nbn];
8425 vector<const SMDS_MeshNode*> aNodes(nbn);
8426 aNodes[0] = nodes[n1];
8427 aNodes[nbn-1] = nodes[n2];
8428 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8429 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8430 aNodes[iNode++] = *nIt;
8432 for(i=1; i<nbn; i++) {
8433 SMDS_MeshElement* newElem =
8434 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8435 myLastCreatedElems.Append(newElem);
8436 if ( aShapeId && newElem )
8437 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8439 // remove old quadratic face
8440 aMesh->RemoveElement(theFace);
8444 //=======================================================================
8445 //function : UpdateVolumes
8447 //=======================================================================
8448 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8449 const SMDS_MeshNode* theBetweenNode2,
8450 list<const SMDS_MeshNode*>& theNodesToInsert)
8452 myLastCreatedElems.Clear();
8453 myLastCreatedNodes.Clear();
8455 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8456 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8457 const SMDS_MeshElement* elem = invElemIt->next();
8459 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8460 SMDS_VolumeTool aVolume (elem);
8461 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8464 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8465 int iface, nbFaces = aVolume.NbFaces();
8466 vector<const SMDS_MeshNode *> poly_nodes;
8467 vector<int> quantities (nbFaces);
8469 for (iface = 0; iface < nbFaces; iface++) {
8470 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8471 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8472 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8474 for (int inode = 0; inode < nbFaceNodes; inode++) {
8475 poly_nodes.push_back(faceNodes[inode]);
8477 if (nbInserted == 0) {
8478 if (faceNodes[inode] == theBetweenNode1) {
8479 if (faceNodes[inode + 1] == theBetweenNode2) {
8480 nbInserted = theNodesToInsert.size();
8482 // add nodes to insert
8483 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8484 for (; nIt != theNodesToInsert.end(); nIt++) {
8485 poly_nodes.push_back(*nIt);
8489 else if (faceNodes[inode] == theBetweenNode2) {
8490 if (faceNodes[inode + 1] == theBetweenNode1) {
8491 nbInserted = theNodesToInsert.size();
8493 // add nodes to insert in reversed order
8494 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8496 for (; nIt != theNodesToInsert.begin(); nIt--) {
8497 poly_nodes.push_back(*nIt);
8499 poly_nodes.push_back(*nIt);
8506 quantities[iface] = nbFaceNodes + nbInserted;
8509 // Replace or update the volume
8510 SMESHDS_Mesh *aMesh = GetMeshDS();
8512 if (elem->IsPoly()) {
8513 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8517 int aShapeId = FindShape( elem );
8519 SMDS_MeshElement* newElem =
8520 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8521 myLastCreatedElems.Append(newElem);
8522 if (aShapeId && newElem)
8523 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8525 aMesh->RemoveElement(elem);
8530 //=======================================================================
8532 * \brief Convert elements contained in a submesh to quadratic
8533 * \retval int - nb of checked elements
8535 //=======================================================================
8537 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8538 SMESH_MesherHelper& theHelper,
8539 const bool theForce3d)
8542 if( !theSm ) return nbElem;
8544 const bool notFromGroups = false;
8545 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8546 while(ElemItr->more())
8549 const SMDS_MeshElement* elem = ElemItr->next();
8550 if( !elem || elem->IsQuadratic() ) continue;
8552 int id = elem->GetID();
8553 int nbNodes = elem->NbNodes();
8554 vector<const SMDS_MeshNode *> aNds (nbNodes);
8556 for(int i = 0; i < nbNodes; i++)
8558 aNds[i] = elem->GetNode(i);
8560 SMDSAbs_ElementType aType = elem->GetType();
8562 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8564 const SMDS_MeshElement* NewElem = 0;
8570 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8578 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8581 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8588 case SMDSAbs_Volume :
8593 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8596 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8599 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8602 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8603 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8613 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8615 theSm->AddElement( NewElem );
8620 //=======================================================================
8621 //function : ConvertToQuadratic
8623 //=======================================================================
8624 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8626 SMESHDS_Mesh* meshDS = GetMeshDS();
8628 SMESH_MesherHelper aHelper(*myMesh);
8629 aHelper.SetIsQuadratic( true );
8630 const bool notFromGroups = false;
8632 int nbCheckedElems = 0;
8633 if ( myMesh->HasShapeToMesh() )
8635 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8637 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8638 while ( smIt->more() ) {
8639 SMESH_subMesh* sm = smIt->next();
8640 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8641 aHelper.SetSubShape( sm->GetSubShape() );
8642 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8647 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8648 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8650 SMESHDS_SubMesh *smDS = 0;
8651 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8652 while(aEdgeItr->more())
8654 const SMDS_MeshEdge* edge = aEdgeItr->next();
8655 if(edge && !edge->IsQuadratic())
8657 int id = edge->GetID();
8658 const SMDS_MeshNode* n1 = edge->GetNode(0);
8659 const SMDS_MeshNode* n2 = edge->GetNode(1);
8661 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8663 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8664 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8667 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8668 while(aFaceItr->more())
8670 const SMDS_MeshFace* face = aFaceItr->next();
8671 if(!face || face->IsQuadratic() ) continue;
8673 int id = face->GetID();
8674 int nbNodes = face->NbNodes();
8675 vector<const SMDS_MeshNode *> aNds (nbNodes);
8677 for(int i = 0; i < nbNodes; i++)
8679 aNds[i] = face->GetNode(i);
8682 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8684 SMDS_MeshFace * NewFace = 0;
8688 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8691 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8696 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8698 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8699 while(aVolumeItr->more())
8701 const SMDS_MeshVolume* volume = aVolumeItr->next();
8702 if(!volume || volume->IsQuadratic() ) continue;
8704 int id = volume->GetID();
8705 int nbNodes = volume->NbNodes();
8706 vector<const SMDS_MeshNode *> aNds (nbNodes);
8708 for(int i = 0; i < nbNodes; i++)
8710 aNds[i] = volume->GetNode(i);
8713 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8715 SMDS_MeshVolume * NewVolume = 0;
8719 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8720 aNds[3], id, theForce3d );
8723 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8724 aNds[3], aNds[4], id, theForce3d);
8727 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8728 aNds[3], aNds[4], aNds[5], id, theForce3d);
8731 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8732 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8737 ReplaceElemInGroups(volume, NewVolume, meshDS);
8740 if ( !theForce3d ) {
8741 aHelper.SetSubShape(0); // apply to the whole mesh
8742 aHelper.FixQuadraticElements();
8746 //=======================================================================
8748 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8749 * \retval int - nb of checked elements
8751 //=======================================================================
8753 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8754 SMDS_ElemIteratorPtr theItr,
8755 const int theShapeID)
8758 SMESHDS_Mesh* meshDS = GetMeshDS();
8759 const bool notFromGroups = false;
8761 while( theItr->more() )
8763 const SMDS_MeshElement* elem = theItr->next();
8765 if( elem && elem->IsQuadratic())
8767 int id = elem->GetID();
8768 int nbNodes = elem->NbNodes();
8769 vector<const SMDS_MeshNode *> aNds, mediumNodes;
8770 aNds.reserve( nbNodes );
8771 mediumNodes.reserve( nbNodes );
8773 for(int i = 0; i < nbNodes; i++)
8775 const SMDS_MeshNode* n = elem->GetNode(i);
8777 if( elem->IsMediumNode( n ) )
8778 mediumNodes.push_back( n );
8780 aNds.push_back( n );
8782 if( aNds.empty() ) continue;
8783 SMDSAbs_ElementType aType = elem->GetType();
8785 //remove old quadratic element
8786 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8788 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8789 ReplaceElemInGroups(elem, NewElem, meshDS);
8790 if( theSm && NewElem )
8791 theSm->AddElement( NewElem );
8793 // remove medium nodes
8794 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8795 for ( ; nIt != mediumNodes.end(); ++nIt ) {
8796 const SMDS_MeshNode* n = *nIt;
8797 if ( n->NbInverseElements() == 0 ) {
8798 if ( n->GetPosition()->GetShapeId() != theShapeID )
8799 meshDS->RemoveFreeNode( n, meshDS->MeshElements
8800 ( n->GetPosition()->GetShapeId() ));
8802 meshDS->RemoveFreeNode( n, theSm );
8810 //=======================================================================
8811 //function : ConvertFromQuadratic
8813 //=======================================================================
8814 bool SMESH_MeshEditor::ConvertFromQuadratic()
8816 int nbCheckedElems = 0;
8817 if ( myMesh->HasShapeToMesh() )
8819 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8821 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8822 while ( smIt->more() ) {
8823 SMESH_subMesh* sm = smIt->next();
8824 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8825 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8831 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8832 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8834 SMESHDS_SubMesh *aSM = 0;
8835 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8841 //=======================================================================
8842 //function : SewSideElements
8844 //=======================================================================
8846 SMESH_MeshEditor::Sew_Error
8847 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8848 TIDSortedElemSet& theSide2,
8849 const SMDS_MeshNode* theFirstNode1,
8850 const SMDS_MeshNode* theFirstNode2,
8851 const SMDS_MeshNode* theSecondNode1,
8852 const SMDS_MeshNode* theSecondNode2)
8854 myLastCreatedElems.Clear();
8855 myLastCreatedNodes.Clear();
8857 MESSAGE ("::::SewSideElements()");
8858 if ( theSide1.size() != theSide2.size() )
8859 return SEW_DIFF_NB_OF_ELEMENTS;
8861 Sew_Error aResult = SEW_OK;
8863 // 1. Build set of faces representing each side
8864 // 2. Find which nodes of the side 1 to merge with ones on the side 2
8865 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8867 // =======================================================================
8868 // 1. Build set of faces representing each side:
8869 // =======================================================================
8870 // a. build set of nodes belonging to faces
8871 // b. complete set of faces: find missing fices whose nodes are in set of nodes
8872 // c. create temporary faces representing side of volumes if correspondent
8873 // face does not exist
8875 SMESHDS_Mesh* aMesh = GetMeshDS();
8876 SMDS_Mesh aTmpFacesMesh;
8877 set<const SMDS_MeshElement*> faceSet1, faceSet2;
8878 set<const SMDS_MeshElement*> volSet1, volSet2;
8879 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
8880 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8881 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
8882 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8883 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8884 int iSide, iFace, iNode;
8886 for ( iSide = 0; iSide < 2; iSide++ ) {
8887 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
8888 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8889 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8890 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
8891 set<const SMDS_MeshElement*>::iterator vIt;
8892 TIDSortedElemSet::iterator eIt;
8893 set<const SMDS_MeshNode*>::iterator nIt;
8895 // check that given nodes belong to given elements
8896 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8897 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8898 int firstIndex = -1, secondIndex = -1;
8899 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8900 const SMDS_MeshElement* elem = *eIt;
8901 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8902 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8903 if ( firstIndex > -1 && secondIndex > -1 ) break;
8905 if ( firstIndex < 0 || secondIndex < 0 ) {
8906 // we can simply return until temporary faces created
8907 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8910 // -----------------------------------------------------------
8911 // 1a. Collect nodes of existing faces
8912 // and build set of face nodes in order to detect missing
8913 // faces corresponing to sides of volumes
8914 // -----------------------------------------------------------
8916 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8918 // loop on the given element of a side
8919 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8920 //const SMDS_MeshElement* elem = *eIt;
8921 const SMDS_MeshElement* elem = *eIt;
8922 if ( elem->GetType() == SMDSAbs_Face ) {
8923 faceSet->insert( elem );
8924 set <const SMDS_MeshNode*> faceNodeSet;
8925 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8926 while ( nodeIt->more() ) {
8927 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8928 nodeSet->insert( n );
8929 faceNodeSet.insert( n );
8931 setOfFaceNodeSet.insert( faceNodeSet );
8933 else if ( elem->GetType() == SMDSAbs_Volume )
8934 volSet->insert( elem );
8936 // ------------------------------------------------------------------------------
8937 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8938 // ------------------------------------------------------------------------------
8940 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8941 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8942 while ( fIt->more() ) { // loop on faces sharing a node
8943 const SMDS_MeshElement* f = fIt->next();
8944 if ( faceSet->find( f ) == faceSet->end() ) {
8945 // check if all nodes are in nodeSet and
8946 // complete setOfFaceNodeSet if they are
8947 set <const SMDS_MeshNode*> faceNodeSet;
8948 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8949 bool allInSet = true;
8950 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8951 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8952 if ( nodeSet->find( n ) == nodeSet->end() )
8955 faceNodeSet.insert( n );
8958 faceSet->insert( f );
8959 setOfFaceNodeSet.insert( faceNodeSet );
8965 // -------------------------------------------------------------------------
8966 // 1c. Create temporary faces representing sides of volumes if correspondent
8967 // face does not exist
8968 // -------------------------------------------------------------------------
8970 if ( !volSet->empty() ) {
8971 //int nodeSetSize = nodeSet->size();
8973 // loop on given volumes
8974 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8975 SMDS_VolumeTool vol (*vIt);
8976 // loop on volume faces: find free faces
8977 // --------------------------------------
8978 list<const SMDS_MeshElement* > freeFaceList;
8979 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8980 if ( !vol.IsFreeFace( iFace ))
8982 // check if there is already a face with same nodes in a face set
8983 const SMDS_MeshElement* aFreeFace = 0;
8984 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8985 int nbNodes = vol.NbFaceNodes( iFace );
8986 set <const SMDS_MeshNode*> faceNodeSet;
8987 vol.GetFaceNodes( iFace, faceNodeSet );
8988 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8990 // no such a face is given but it still can exist, check it
8991 if ( nbNodes == 3 ) {
8992 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8994 else if ( nbNodes == 4 ) {
8995 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
8998 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
8999 aFreeFace = aMesh->FindFace(poly_nodes);
9003 // create a temporary face
9004 if ( nbNodes == 3 ) {
9005 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9007 else if ( nbNodes == 4 ) {
9008 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9011 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9012 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9016 freeFaceList.push_back( aFreeFace );
9018 } // loop on faces of a volume
9020 // choose one of several free faces
9021 // --------------------------------------
9022 if ( freeFaceList.size() > 1 ) {
9023 // choose a face having max nb of nodes shared by other elems of a side
9024 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9025 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9026 while ( fIt != freeFaceList.end() ) { // loop on free faces
9027 int nbSharedNodes = 0;
9028 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9029 while ( nodeIt->more() ) { // loop on free face nodes
9030 const SMDS_MeshNode* n =
9031 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9032 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9033 while ( invElemIt->more() ) {
9034 const SMDS_MeshElement* e = invElemIt->next();
9035 if ( faceSet->find( e ) != faceSet->end() )
9037 if ( elemSet->find( e ) != elemSet->end() )
9041 if ( nbSharedNodes >= maxNbNodes ) {
9042 maxNbNodes = nbSharedNodes;
9046 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9048 if ( freeFaceList.size() > 1 )
9050 // could not choose one face, use another way
9051 // choose a face most close to the bary center of the opposite side
9052 gp_XYZ aBC( 0., 0., 0. );
9053 set <const SMDS_MeshNode*> addedNodes;
9054 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9055 eIt = elemSet2->begin();
9056 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9057 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9058 while ( nodeIt->more() ) { // loop on free face nodes
9059 const SMDS_MeshNode* n =
9060 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9061 if ( addedNodes.insert( n ).second )
9062 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9065 aBC /= addedNodes.size();
9066 double minDist = DBL_MAX;
9067 fIt = freeFaceList.begin();
9068 while ( fIt != freeFaceList.end() ) { // loop on free faces
9070 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9071 while ( nodeIt->more() ) { // loop on free face nodes
9072 const SMDS_MeshNode* n =
9073 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9074 gp_XYZ p( n->X(),n->Y(),n->Z() );
9075 dist += ( aBC - p ).SquareModulus();
9077 if ( dist < minDist ) {
9079 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9082 fIt = freeFaceList.erase( fIt++ );
9085 } // choose one of several free faces of a volume
9087 if ( freeFaceList.size() == 1 ) {
9088 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9089 faceSet->insert( aFreeFace );
9090 // complete a node set with nodes of a found free face
9091 // for ( iNode = 0; iNode < ; iNode++ )
9092 // nodeSet->insert( fNodes[ iNode ] );
9095 } // loop on volumes of a side
9097 // // complete a set of faces if new nodes in a nodeSet appeared
9098 // // ----------------------------------------------------------
9099 // if ( nodeSetSize != nodeSet->size() ) {
9100 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9101 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9102 // while ( fIt->more() ) { // loop on faces sharing a node
9103 // const SMDS_MeshElement* f = fIt->next();
9104 // if ( faceSet->find( f ) == faceSet->end() ) {
9105 // // check if all nodes are in nodeSet and
9106 // // complete setOfFaceNodeSet if they are
9107 // set <const SMDS_MeshNode*> faceNodeSet;
9108 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9109 // bool allInSet = true;
9110 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9111 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9112 // if ( nodeSet->find( n ) == nodeSet->end() )
9113 // allInSet = false;
9115 // faceNodeSet.insert( n );
9117 // if ( allInSet ) {
9118 // faceSet->insert( f );
9119 // setOfFaceNodeSet.insert( faceNodeSet );
9125 } // Create temporary faces, if there are volumes given
9128 if ( faceSet1.size() != faceSet2.size() ) {
9129 // delete temporary faces: they are in reverseElements of actual nodes
9130 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9131 while ( tmpFaceIt->more() )
9132 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9133 MESSAGE("Diff nb of faces");
9134 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9137 // ============================================================
9138 // 2. Find nodes to merge:
9139 // bind a node to remove to a node to put instead
9140 // ============================================================
9142 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9143 if ( theFirstNode1 != theFirstNode2 )
9144 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9145 if ( theSecondNode1 != theSecondNode2 )
9146 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9148 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9149 set< long > linkIdSet; // links to process
9150 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9152 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9153 list< NLink > linkList[2];
9154 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9155 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9156 // loop on links in linkList; find faces by links and append links
9157 // of the found faces to linkList
9158 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9159 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9160 NLink link[] = { *linkIt[0], *linkIt[1] };
9161 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9162 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9165 // by links, find faces in the face sets,
9166 // and find indices of link nodes in the found faces;
9167 // in a face set, there is only one or no face sharing a link
9168 // ---------------------------------------------------------------
9170 const SMDS_MeshElement* face[] = { 0, 0 };
9171 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9172 vector<const SMDS_MeshNode*> fnodes1(9);
9173 vector<const SMDS_MeshNode*> fnodes2(9);
9174 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9175 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9176 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9177 int iLinkNode[2][2];
9178 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9179 const SMDS_MeshNode* n1 = link[iSide].first;
9180 const SMDS_MeshNode* n2 = link[iSide].second;
9181 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9182 set< const SMDS_MeshElement* > fMap;
9183 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9184 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9185 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9186 while ( fIt->more() ) { // loop on faces sharing a node
9187 const SMDS_MeshElement* f = fIt->next();
9188 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9189 ! fMap.insert( f ).second ) // f encounters twice
9191 if ( face[ iSide ] ) {
9192 MESSAGE( "2 faces per link " );
9193 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9197 faceSet->erase( f );
9198 // get face nodes and find ones of a link
9203 fnodes1.resize(f->NbNodes()+1);
9204 notLinkNodes1.resize(f->NbNodes()-2);
9207 fnodes2.resize(f->NbNodes()+1);
9208 notLinkNodes2.resize(f->NbNodes()-2);
9211 if(!f->IsQuadratic()) {
9212 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9213 while ( nIt->more() ) {
9214 const SMDS_MeshNode* n =
9215 static_cast<const SMDS_MeshNode*>( nIt->next() );
9217 iLinkNode[ iSide ][ 0 ] = iNode;
9219 else if ( n == n2 ) {
9220 iLinkNode[ iSide ][ 1 ] = iNode;
9222 //else if ( notLinkNodes[ iSide ][ 0 ] )
9223 // notLinkNodes[ iSide ][ 1 ] = n;
9225 // notLinkNodes[ iSide ][ 0 ] = n;
9229 notLinkNodes1[nbl] = n;
9230 //notLinkNodes1.push_back(n);
9232 notLinkNodes2[nbl] = n;
9233 //notLinkNodes2.push_back(n);
9235 //faceNodes[ iSide ][ iNode++ ] = n;
9237 fnodes1[iNode++] = n;
9240 fnodes2[iNode++] = n;
9244 else { // f->IsQuadratic()
9245 const SMDS_QuadraticFaceOfNodes* F =
9246 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9247 // use special nodes iterator
9248 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9249 while ( anIter->more() ) {
9250 const SMDS_MeshNode* n =
9251 static_cast<const SMDS_MeshNode*>( anIter->next() );
9253 iLinkNode[ iSide ][ 0 ] = iNode;
9255 else if ( n == n2 ) {
9256 iLinkNode[ iSide ][ 1 ] = iNode;
9261 notLinkNodes1[nbl] = n;
9264 notLinkNodes2[nbl] = n;
9268 fnodes1[iNode++] = n;
9271 fnodes2[iNode++] = n;
9275 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9277 fnodes1[iNode] = fnodes1[0];
9280 fnodes2[iNode] = fnodes1[0];
9287 // check similarity of elements of the sides
9288 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9289 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9290 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9291 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9294 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9296 break; // do not return because it s necessary to remove tmp faces
9299 // set nodes to merge
9300 // -------------------
9302 if ( face[0] && face[1] ) {
9303 int nbNodes = face[0]->NbNodes();
9304 if ( nbNodes != face[1]->NbNodes() ) {
9305 MESSAGE("Diff nb of face nodes");
9306 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9307 break; // do not return because it s necessary to remove tmp faces
9309 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9310 if ( nbNodes == 3 ) {
9311 //nReplaceMap.insert( TNodeNodeMap::value_type
9312 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9313 nReplaceMap.insert( TNodeNodeMap::value_type
9314 ( notLinkNodes1[0], notLinkNodes2[0] ));
9317 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9318 // analyse link orientation in faces
9319 int i1 = iLinkNode[ iSide ][ 0 ];
9320 int i2 = iLinkNode[ iSide ][ 1 ];
9321 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9322 // if notLinkNodes are the first and the last ones, then
9323 // their order does not correspond to the link orientation
9324 if (( i1 == 1 && i2 == 2 ) ||
9325 ( i1 == 2 && i2 == 1 ))
9326 reverse[ iSide ] = !reverse[ iSide ];
9328 if ( reverse[0] == reverse[1] ) {
9329 //nReplaceMap.insert( TNodeNodeMap::value_type
9330 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9331 //nReplaceMap.insert( TNodeNodeMap::value_type
9332 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9333 for(int nn=0; nn<nbNodes-2; nn++) {
9334 nReplaceMap.insert( TNodeNodeMap::value_type
9335 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9339 //nReplaceMap.insert( TNodeNodeMap::value_type
9340 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9341 //nReplaceMap.insert( TNodeNodeMap::value_type
9342 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9343 for(int nn=0; nn<nbNodes-2; nn++) {
9344 nReplaceMap.insert( TNodeNodeMap::value_type
9345 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9350 // add other links of the faces to linkList
9351 // -----------------------------------------
9353 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9354 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9355 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9356 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9357 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9358 if ( !iter_isnew.second ) { // already in a set: no need to process
9359 linkIdSet.erase( iter_isnew.first );
9361 else // new in set == encountered for the first time: add
9363 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9364 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9365 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9366 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9367 linkList[0].push_back ( NLink( n1, n2 ));
9368 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9372 } // loop on link lists
9374 if ( aResult == SEW_OK &&
9375 ( linkIt[0] != linkList[0].end() ||
9376 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9377 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9378 " " << (faceSetPtr[1]->empty()));
9379 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9382 // ====================================================================
9383 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9384 // ====================================================================
9386 // delete temporary faces: they are in reverseElements of actual nodes
9387 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9388 while ( tmpFaceIt->more() )
9389 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9391 if ( aResult != SEW_OK)
9394 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9395 // loop on nodes replacement map
9396 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9397 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9398 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9399 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9400 nodeIDsToRemove.push_back( nToRemove->GetID() );
9401 // loop on elements sharing nToRemove
9402 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9403 while ( invElemIt->more() ) {
9404 const SMDS_MeshElement* e = invElemIt->next();
9405 // get a new suite of nodes: make replacement
9406 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9407 vector< const SMDS_MeshNode*> nodes( nbNodes );
9408 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9409 while ( nIt->more() ) {
9410 const SMDS_MeshNode* n =
9411 static_cast<const SMDS_MeshNode*>( nIt->next() );
9412 nnIt = nReplaceMap.find( n );
9413 if ( nnIt != nReplaceMap.end() ) {
9419 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9420 // elemIDsToRemove.push_back( e->GetID() );
9423 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9427 Remove( nodeIDsToRemove, true );
9432 //================================================================================
9434 * \brief Find corresponding nodes in two sets of faces
9435 * \param theSide1 - first face set
9436 * \param theSide2 - second first face
9437 * \param theFirstNode1 - a boundary node of set 1
9438 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9439 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9440 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9441 * \param nReplaceMap - output map of corresponding nodes
9442 * \retval bool - is a success or not
9444 //================================================================================
9447 //#define DEBUG_MATCHING_NODES
9450 SMESH_MeshEditor::Sew_Error
9451 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9452 set<const SMDS_MeshElement*>& theSide2,
9453 const SMDS_MeshNode* theFirstNode1,
9454 const SMDS_MeshNode* theFirstNode2,
9455 const SMDS_MeshNode* theSecondNode1,
9456 const SMDS_MeshNode* theSecondNode2,
9457 TNodeNodeMap & nReplaceMap)
9459 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9461 nReplaceMap.clear();
9462 if ( theFirstNode1 != theFirstNode2 )
9463 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9464 if ( theSecondNode1 != theSecondNode2 )
9465 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9467 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9468 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9470 list< NLink > linkList[2];
9471 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9472 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9474 // loop on links in linkList; find faces by links and append links
9475 // of the found faces to linkList
9476 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9477 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9478 NLink link[] = { *linkIt[0], *linkIt[1] };
9479 if ( linkSet.find( link[0] ) == linkSet.end() )
9482 // by links, find faces in the face sets,
9483 // and find indices of link nodes in the found faces;
9484 // in a face set, there is only one or no face sharing a link
9485 // ---------------------------------------------------------------
9487 const SMDS_MeshElement* face[] = { 0, 0 };
9488 list<const SMDS_MeshNode*> notLinkNodes[2];
9489 //bool reverse[] = { false, false }; // order of notLinkNodes
9491 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9493 const SMDS_MeshNode* n1 = link[iSide].first;
9494 const SMDS_MeshNode* n2 = link[iSide].second;
9495 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9496 set< const SMDS_MeshElement* > facesOfNode1;
9497 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9499 // during a loop of the first node, we find all faces around n1,
9500 // during a loop of the second node, we find one face sharing both n1 and n2
9501 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9502 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9503 while ( fIt->more() ) { // loop on faces sharing a node
9504 const SMDS_MeshElement* f = fIt->next();
9505 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9506 ! facesOfNode1.insert( f ).second ) // f encounters twice
9508 if ( face[ iSide ] ) {
9509 MESSAGE( "2 faces per link " );
9510 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9513 faceSet->erase( f );
9515 // get not link nodes
9516 int nbN = f->NbNodes();
9517 if ( f->IsQuadratic() )
9519 nbNodes[ iSide ] = nbN;
9520 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9521 int i1 = f->GetNodeIndex( n1 );
9522 int i2 = f->GetNodeIndex( n2 );
9523 int iEnd = nbN, iBeg = -1, iDelta = 1;
9524 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9526 std::swap( iEnd, iBeg ); iDelta = -1;
9531 if ( i == iEnd ) i = iBeg + iDelta;
9532 if ( i == i1 ) break;
9533 nodes.push_back ( f->GetNode( i ) );
9539 // check similarity of elements of the sides
9540 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9541 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9542 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9543 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9546 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9550 // set nodes to merge
9551 // -------------------
9553 if ( face[0] && face[1] ) {
9554 if ( nbNodes[0] != nbNodes[1] ) {
9555 MESSAGE("Diff nb of face nodes");
9556 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9558 #ifdef DEBUG_MATCHING_NODES
9559 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9560 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9561 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9563 int nbN = nbNodes[0];
9565 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9566 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9567 for ( int i = 0 ; i < nbN - 2; ++i ) {
9568 #ifdef DEBUG_MATCHING_NODES
9569 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9571 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9575 // add other links of the face 1 to linkList
9576 // -----------------------------------------
9578 const SMDS_MeshElement* f0 = face[0];
9579 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9580 for ( int i = 0; i < nbN; i++ )
9582 const SMDS_MeshNode* n2 = f0->GetNode( i );
9583 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9584 linkSet.insert( SMESH_TLink( n1, n2 ));
9585 if ( !iter_isnew.second ) { // already in a set: no need to process
9586 linkSet.erase( iter_isnew.first );
9588 else // new in set == encountered for the first time: add
9590 #ifdef DEBUG_MATCHING_NODES
9591 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9592 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9594 linkList[0].push_back ( NLink( n1, n2 ));
9595 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9600 } // loop on link lists
9605 //================================================================================
9607 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9608 \param theElems - the list of elements (edges or faces) to be replicated
9609 The nodes for duplication could be found from these elements
9610 \param theNodesNot - list of nodes to NOT replicate
9611 \param theAffectedElems - the list of elements (cells and edges) to which the
9612 replicated nodes should be associated to.
9613 \return TRUE if operation has been completed successfully, FALSE otherwise
9615 //================================================================================
9617 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9618 const TIDSortedElemSet& theNodesNot,
9619 const TIDSortedElemSet& theAffectedElems )
9621 myLastCreatedElems.Clear();
9622 myLastCreatedNodes.Clear();
9624 if ( theElems.size() == 0 )
9627 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9632 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9633 // duplicate elements and nodes
9634 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9635 // replce nodes by duplications
9636 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9640 //================================================================================
9642 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9643 \param theMeshDS - mesh instance
9644 \param theElems - the elements replicated or modified (nodes should be changed)
9645 \param theNodesNot - nodes to NOT replicate
9646 \param theNodeNodeMap - relation of old node to new created node
9647 \param theIsDoubleElem - flag os to replicate element or modify
9648 \return TRUE if operation has been completed successfully, FALSE otherwise
9650 //================================================================================
9652 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9653 const TIDSortedElemSet& theElems,
9654 const TIDSortedElemSet& theNodesNot,
9655 std::map< const SMDS_MeshNode*,
9656 const SMDS_MeshNode* >& theNodeNodeMap,
9657 const bool theIsDoubleElem )
9659 // iterate on through element and duplicate them (by nodes duplication)
9661 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9662 for ( ; elemItr != theElems.end(); ++elemItr )
9664 const SMDS_MeshElement* anElem = *elemItr;
9668 bool isDuplicate = false;
9669 // duplicate nodes to duplicate element
9670 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9671 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9673 while ( anIter->more() )
9676 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9677 SMDS_MeshNode* aNewNode = aCurrNode;
9678 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9679 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9680 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9683 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9684 theNodeNodeMap[ aCurrNode ] = aNewNode;
9685 myLastCreatedNodes.Append( aNewNode );
9687 isDuplicate |= (aCurrNode != aNewNode);
9688 newNodes[ ind++ ] = aNewNode;
9693 if ( theIsDoubleElem )
9694 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9696 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9703 //================================================================================
9705 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9706 \param theNodes - identifiers of nodes to be doubled
9707 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9708 nodes. If list of element identifiers is empty then nodes are doubled but
9709 they not assigned to elements
9710 \return TRUE if operation has been completed successfully, FALSE otherwise
9712 //================================================================================
9714 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9715 const std::list< int >& theListOfModifiedElems )
9717 myLastCreatedElems.Clear();
9718 myLastCreatedNodes.Clear();
9720 if ( theListOfNodes.size() == 0 )
9723 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9727 // iterate through nodes and duplicate them
9729 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9731 std::list< int >::const_iterator aNodeIter;
9732 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9734 int aCurr = *aNodeIter;
9735 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9741 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9744 anOldNodeToNewNode[ aNode ] = aNewNode;
9745 myLastCreatedNodes.Append( aNewNode );
9749 // Create map of new nodes for modified elements
9751 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9753 std::list< int >::const_iterator anElemIter;
9754 for ( anElemIter = theListOfModifiedElems.begin();
9755 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9757 int aCurr = *anElemIter;
9758 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9762 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9764 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9766 while ( anIter->more() )
9768 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9769 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9771 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9772 aNodeArr[ ind++ ] = aNewNode;
9775 aNodeArr[ ind++ ] = aCurrNode;
9777 anElemToNodes[ anElem ] = aNodeArr;
9780 // Change nodes of elements
9782 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9783 anElemToNodesIter = anElemToNodes.begin();
9784 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9786 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9787 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9789 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9797 //================================================================================
9799 \brief Check if element located inside shape
9800 \return TRUE if IN or ON shape, FALSE otherwise
9802 //================================================================================
9804 template<class Classifier>
9805 bool isInside(const SMDS_MeshElement* theElem,
9806 Classifier& theClassifier,
9807 const double theTol)
9809 gp_XYZ centerXYZ (0, 0, 0);
9810 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9811 while (aNodeItr->more())
9812 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9814 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9815 theClassifier.Perform(aPnt, theTol);
9816 TopAbs_State aState = theClassifier.State();
9817 return (aState == TopAbs_IN || aState == TopAbs_ON );
9820 //================================================================================
9822 * \brief Classifier of the 3D point on the TopoDS_Face
9823 * with interaface suitable for isInside()
9825 //================================================================================
9827 struct _FaceClassifier
9829 Extrema_ExtPS _extremum;
9830 BRepAdaptor_Surface _surface;
9831 TopAbs_State _state;
9833 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9835 _extremum.Initialize( _surface,
9836 _surface.FirstUParameter(), _surface.LastUParameter(),
9837 _surface.FirstVParameter(), _surface.LastVParameter(),
9838 _surface.Tolerance(), _surface.Tolerance() );
9840 void Perform(const gp_Pnt& aPnt, double theTol)
9842 _state = TopAbs_OUT;
9843 _extremum.Perform(aPnt);
9844 if ( _extremum.IsDone() )
9845 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9846 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9848 TopAbs_State State() const
9855 //================================================================================
9857 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9858 \param theElems - group of of elements (edges or faces) to be replicated
9859 \param theNodesNot - group of nodes not to replicate
9860 \param theShape - shape to detect affected elements (element which geometric center
9861 located on or inside shape).
9862 The replicated nodes should be associated to affected elements.
9863 \return TRUE if operation has been completed successfully, FALSE otherwise
9865 //================================================================================
9867 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9868 const TIDSortedElemSet& theNodesNot,
9869 const TopoDS_Shape& theShape )
9871 if ( theShape.IsNull() )
9874 const double aTol = Precision::Confusion();
9875 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9876 auto_ptr<_FaceClassifier> aFaceClassifier;
9877 if ( theShape.ShapeType() == TopAbs_SOLID )
9879 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9880 bsc3d->PerformInfinitePoint(aTol);
9882 else if (theShape.ShapeType() == TopAbs_FACE )
9884 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9887 // iterates on indicated elements and get elements by back references from their nodes
9888 TIDSortedElemSet anAffected;
9889 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9890 for ( ; elemItr != theElems.end(); ++elemItr )
9892 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9896 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9897 while ( nodeItr->more() )
9899 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9900 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9902 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9903 while ( backElemItr->more() )
9905 const SMDS_MeshElement* curElem = backElemItr->next();
9906 if ( curElem && theElems.find(curElem) == theElems.end() &&
9908 isInside( curElem, *bsc3d, aTol ) :
9909 isInside( curElem, *aFaceClassifier, aTol )))
9910 anAffected.insert( curElem );
9914 return DoubleNodes( theElems, theNodesNot, anAffected );
9917 //================================================================================
9919 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9920 * The created 2D mesh elements based on nodes of free faces of boundary volumes
9921 * \return TRUE if operation has been completed successfully, FALSE otherwise
9923 //================================================================================
9925 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9927 // iterates on volume elements and detect all free faces on them
9928 SMESHDS_Mesh* aMesh = GetMeshDS();
9932 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9935 const SMDS_MeshVolume* volume = vIt->next();
9936 SMDS_VolumeTool vTool( volume );
9937 vTool.SetExternalNormal();
9938 const bool isPoly = volume->IsPoly();
9939 const bool isQuad = volume->IsQuadratic();
9940 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9942 if (!vTool.IsFreeFace(iface))
9944 vector<const SMDS_MeshNode *> nodes;
9945 int nbFaceNodes = vTool.NbFaceNodes(iface);
9946 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9948 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9949 nodes.push_back(faceNodes[inode]);
9951 for ( inode = 1; inode < nbFaceNodes; inode += 2)
9952 nodes.push_back(faceNodes[inode]);
9954 // add new face based on volume nodes
9955 if (aMesh->FindFace( nodes ) )
9956 continue; // face already exsist
9957 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );