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();
127 case SMDSAbs_0DElement:
129 if ( ID ) e = mesh->Add0DElementWithID(node[0], ID);
130 else e = mesh->Add0DElement (node[0] );
134 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
135 else e = mesh->AddEdge (node[0], node[1] );
136 else if ( nbnode == 3 )
137 if ( ID ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
138 else e = mesh->AddEdge (node[0], node[1], node[2] );
143 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
144 else e = mesh->AddFace (node[0], node[1], node[2] );
145 else if (nbnode == 4)
146 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
148 else if (nbnode == 6)
149 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
150 node[4], node[5], ID);
151 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
153 else if (nbnode == 8)
154 if ( ID ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7], ID);
156 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7] );
159 if ( ID ) e = mesh->AddPolygonalFaceWithID(node, ID);
160 else e = mesh->AddPolygonalFace (node );
166 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
167 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
168 else if (nbnode == 5)
169 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
171 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
173 else if (nbnode == 6)
174 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
175 node[4], node[5], ID);
176 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
178 else if (nbnode == 8)
179 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
180 node[4], node[5], node[6], node[7], ID);
181 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
182 node[4], node[5], node[6], node[7] );
183 else if (nbnode == 10)
184 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7],
186 node[8], node[9], ID);
187 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7],
190 else if (nbnode == 13)
191 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
192 node[4], node[5], node[6], node[7],
193 node[8], node[9], node[10],node[11],
195 else e = mesh->AddVolume (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],
199 else if (nbnode == 15)
200 if ( ID ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
203 node[12],node[13],node[14],ID);
204 else e = mesh->AddVolume (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] );
208 else if (nbnode == 20)
209 if ( ID ) e = mesh->AddVolumeWithID(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],ID);
214 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
215 node[4], node[5], node[6], node[7],
216 node[8], node[9], node[10],node[11],
217 node[12],node[13],node[14],node[15],
218 node[16],node[17],node[18],node[19] );
224 //=======================================================================
228 //=======================================================================
230 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
231 const SMDSAbs_ElementType type,
235 vector<const SMDS_MeshNode*> nodes;
236 nodes.reserve( nodeIDs.size() );
237 vector<int>::const_iterator id = nodeIDs.begin();
238 while ( id != nodeIDs.end() ) {
239 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
240 nodes.push_back( node );
244 return AddElement( nodes, type, isPoly, ID );
247 //=======================================================================
249 //purpose : Remove a node or an element.
250 // Modify a compute state of sub-meshes which become empty
251 //=======================================================================
253 bool SMESH_MeshEditor::Remove (const list< int >& theIDs,
256 myLastCreatedElems.Clear();
257 myLastCreatedNodes.Clear();
259 SMESHDS_Mesh* aMesh = GetMeshDS();
260 set< SMESH_subMesh *> smmap;
262 list<int>::const_iterator it = theIDs.begin();
263 for ( ; it != theIDs.end(); it++ ) {
264 const SMDS_MeshElement * elem;
266 elem = aMesh->FindNode( *it );
268 elem = aMesh->FindElement( *it );
272 // Notify VERTEX sub-meshes about modification
274 const SMDS_MeshNode* node = cast2Node( elem );
275 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
276 if ( int aShapeID = node->GetPosition()->GetShapeId() )
277 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
280 // Find sub-meshes to notify about modification
281 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
282 // while ( nodeIt->more() ) {
283 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
284 // const SMDS_PositionPtr& aPosition = node->GetPosition();
285 // if ( aPosition.get() ) {
286 // if ( int aShapeID = aPosition->GetShapeId() ) {
287 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
288 // smmap.insert( sm );
295 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
297 aMesh->RemoveElement( elem );
300 // Notify sub-meshes about modification
301 if ( !smmap.empty() ) {
302 set< SMESH_subMesh *>::iterator smIt;
303 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
304 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
307 // // Check if the whole mesh becomes empty
308 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
309 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
314 //=======================================================================
315 //function : FindShape
316 //purpose : Return an index of the shape theElem is on
317 // or zero if a shape not found
318 //=======================================================================
320 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
322 myLastCreatedElems.Clear();
323 myLastCreatedNodes.Clear();
325 SMESHDS_Mesh * aMesh = GetMeshDS();
326 if ( aMesh->ShapeToMesh().IsNull() )
329 if ( theElem->GetType() == SMDSAbs_Node ) {
330 const SMDS_PositionPtr& aPosition =
331 static_cast<const SMDS_MeshNode*>( theElem )->GetPosition();
332 if ( aPosition.get() )
333 return aPosition->GetShapeId();
338 TopoDS_Shape aShape; // the shape a node is on
339 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
340 while ( nodeIt->more() ) {
341 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
342 const SMDS_PositionPtr& aPosition = node->GetPosition();
343 if ( aPosition.get() ) {
344 int aShapeID = aPosition->GetShapeId();
345 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
347 if ( sm->Contains( theElem ))
349 if ( aShape.IsNull() )
350 aShape = aMesh->IndexToShape( aShapeID );
353 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
358 // None of nodes is on a proper shape,
359 // find the shape among ancestors of aShape on which a node is
360 if ( aShape.IsNull() ) {
361 //MESSAGE ("::FindShape() - NONE node is on shape")
364 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
365 for ( ; ancIt.More(); ancIt.Next() ) {
366 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
367 if ( sm && sm->Contains( theElem ))
368 return aMesh->ShapeToIndex( ancIt.Value() );
371 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
375 //=======================================================================
376 //function : IsMedium
378 //=======================================================================
380 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
381 const SMDSAbs_ElementType typeToCheck)
383 bool isMedium = false;
384 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
385 while (it->more() && !isMedium ) {
386 const SMDS_MeshElement* elem = it->next();
387 isMedium = elem->IsMediumNode(node);
392 //=======================================================================
393 //function : ShiftNodesQuadTria
395 // Shift nodes in the array corresponded to quadratic triangle
396 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
397 //=======================================================================
398 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
400 const SMDS_MeshNode* nd1 = aNodes[0];
401 aNodes[0] = aNodes[1];
402 aNodes[1] = aNodes[2];
404 const SMDS_MeshNode* nd2 = aNodes[3];
405 aNodes[3] = aNodes[4];
406 aNodes[4] = aNodes[5];
410 //=======================================================================
411 //function : GetNodesFromTwoTria
413 // Shift nodes in the array corresponded to quadratic triangle
414 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
415 //=======================================================================
416 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
417 const SMDS_MeshElement * theTria2,
418 const SMDS_MeshNode* N1[],
419 const SMDS_MeshNode* N2[])
421 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
424 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
427 if(it->more()) return false;
428 it = theTria2->nodesIterator();
431 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
434 if(it->more()) return false;
436 int sames[3] = {-1,-1,-1};
448 if(nbsames!=2) return false;
450 ShiftNodesQuadTria(N1);
452 ShiftNodesQuadTria(N1);
455 i = sames[0] + sames[1] + sames[2];
457 ShiftNodesQuadTria(N2);
459 // now we receive following N1 and N2 (using numeration as above image)
460 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
461 // i.e. first nodes from both arrays determ new diagonal
465 //=======================================================================
466 //function : InverseDiag
467 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
468 // but having other common link.
469 // Return False if args are improper
470 //=======================================================================
472 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
473 const SMDS_MeshElement * theTria2 )
475 myLastCreatedElems.Clear();
476 myLastCreatedNodes.Clear();
478 if (!theTria1 || !theTria2)
481 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria1 );
482 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( theTria2 );
485 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
486 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
490 // put nodes in array and find out indices of the same ones
491 const SMDS_MeshNode* aNodes [6];
492 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
494 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
495 while ( it->more() ) {
496 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
498 if ( i > 2 ) // theTria2
499 // find same node of theTria1
500 for ( int j = 0; j < 3; j++ )
501 if ( aNodes[ i ] == aNodes[ j ]) {
510 return false; // theTria1 is not a triangle
511 it = theTria2->nodesIterator();
513 if ( i == 6 && it->more() )
514 return false; // theTria2 is not a triangle
517 // find indices of 1,2 and of A,B in theTria1
518 int iA = 0, iB = 0, i1 = 0, i2 = 0;
519 for ( i = 0; i < 6; i++ ) {
520 if ( sameInd [ i ] == 0 )
527 // nodes 1 and 2 should not be the same
528 if ( aNodes[ i1 ] == aNodes[ i2 ] )
532 aNodes[ iA ] = aNodes[ i2 ];
534 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
536 //MESSAGE( theTria1 << theTria2 );
538 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
539 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
541 //MESSAGE( theTria1 << theTria2 );
545 } // end if(F1 && F2)
547 // check case of quadratic faces
548 const SMDS_QuadraticFaceOfNodes* QF1 =
549 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria1);
550 if(!QF1) return false;
551 const SMDS_QuadraticFaceOfNodes* QF2 =
552 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (theTria2);
553 if(!QF2) return false;
556 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
557 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
565 const SMDS_MeshNode* N1 [6];
566 const SMDS_MeshNode* N2 [6];
567 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
569 // now we receive following N1 and N2 (using numeration as above image)
570 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
571 // i.e. first nodes from both arrays determ new diagonal
573 const SMDS_MeshNode* N1new [6];
574 const SMDS_MeshNode* N2new [6];
587 // replaces nodes in faces
588 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
589 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
594 //=======================================================================
595 //function : findTriangles
596 //purpose : find triangles sharing theNode1-theNode2 link
597 //=======================================================================
599 static bool findTriangles(const SMDS_MeshNode * theNode1,
600 const SMDS_MeshNode * theNode2,
601 const SMDS_MeshElement*& theTria1,
602 const SMDS_MeshElement*& theTria2)
604 if ( !theNode1 || !theNode2 ) return false;
606 theTria1 = theTria2 = 0;
608 set< const SMDS_MeshElement* > emap;
609 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
611 const SMDS_MeshElement* elem = it->next();
612 if ( elem->NbNodes() == 3 )
615 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
617 const SMDS_MeshElement* elem = it->next();
618 if ( emap.find( elem ) != emap.end() )
620 // theTria1 must be element with minimum ID
621 if( theTria1->GetID() < elem->GetID() ) {
634 return ( theTria1 && theTria2 );
637 //=======================================================================
638 //function : InverseDiag
639 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
640 // with ones built on the same 4 nodes but having other common link.
641 // Return false if proper faces not found
642 //=======================================================================
644 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
645 const SMDS_MeshNode * theNode2)
647 myLastCreatedElems.Clear();
648 myLastCreatedNodes.Clear();
650 MESSAGE( "::InverseDiag()" );
652 const SMDS_MeshElement *tr1, *tr2;
653 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
656 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
657 //if (!F1) return false;
658 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
659 //if (!F2) return false;
662 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
663 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
667 // put nodes in array
668 // and find indices of 1,2 and of A in tr1 and of B in tr2
669 int i, iA1 = 0, i1 = 0;
670 const SMDS_MeshNode* aNodes1 [3];
671 SMDS_ElemIteratorPtr it;
672 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
673 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
674 if ( aNodes1[ i ] == theNode1 )
675 iA1 = i; // node A in tr1
676 else if ( aNodes1[ i ] != theNode2 )
680 const SMDS_MeshNode* aNodes2 [3];
681 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
682 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683 if ( aNodes2[ i ] == theNode2 )
684 iB2 = i; // node B in tr2
685 else if ( aNodes2[ i ] != theNode1 )
689 // nodes 1 and 2 should not be the same
690 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
694 aNodes1[ iA1 ] = aNodes2[ i2 ];
696 aNodes2[ iB2 ] = aNodes1[ i1 ];
698 //MESSAGE( tr1 << tr2 );
700 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
701 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
703 //MESSAGE( tr1 << tr2 );
708 // check case of quadratic faces
709 const SMDS_QuadraticFaceOfNodes* QF1 =
710 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
711 if(!QF1) return false;
712 const SMDS_QuadraticFaceOfNodes* QF2 =
713 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
714 if(!QF2) return false;
715 return InverseDiag(tr1,tr2);
718 //=======================================================================
719 //function : getQuadrangleNodes
720 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
721 // fusion of triangles tr1 and tr2 having shared link on
722 // theNode1 and theNode2
723 //=======================================================================
725 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
726 const SMDS_MeshNode * theNode1,
727 const SMDS_MeshNode * theNode2,
728 const SMDS_MeshElement * tr1,
729 const SMDS_MeshElement * tr2 )
731 if( tr1->NbNodes() != tr2->NbNodes() )
733 // find the 4-th node to insert into tr1
734 const SMDS_MeshNode* n4 = 0;
735 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
737 while ( !n4 && i<3 ) {
738 const SMDS_MeshNode * n = cast2Node( it->next() );
740 bool isDiag = ( n == theNode1 || n == theNode2 );
744 // Make an array of nodes to be in a quadrangle
745 int iNode = 0, iFirstDiag = -1;
746 it = tr1->nodesIterator();
749 const SMDS_MeshNode * n = cast2Node( it->next() );
751 bool isDiag = ( n == theNode1 || n == theNode2 );
753 if ( iFirstDiag < 0 )
755 else if ( iNode - iFirstDiag == 1 )
756 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
758 else if ( n == n4 ) {
759 return false; // tr1 and tr2 should not have all the same nodes
761 theQuadNodes[ iNode++ ] = n;
763 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
764 theQuadNodes[ iNode ] = n4;
769 //=======================================================================
770 //function : DeleteDiag
771 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
772 // with a quadrangle built on the same 4 nodes.
773 // Return false if proper faces not found
774 //=======================================================================
776 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
777 const SMDS_MeshNode * theNode2)
779 myLastCreatedElems.Clear();
780 myLastCreatedNodes.Clear();
782 MESSAGE( "::DeleteDiag()" );
784 const SMDS_MeshElement *tr1, *tr2;
785 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
788 const SMDS_FaceOfNodes* F1 = dynamic_cast<const SMDS_FaceOfNodes*>( tr1 );
789 //if (!F1) return false;
790 const SMDS_FaceOfNodes* F2 = dynamic_cast<const SMDS_FaceOfNodes*>( tr2 );
791 //if (!F2) return false;
794 const SMDS_MeshNode* aNodes [ 4 ];
795 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
798 //MESSAGE( endl << tr1 << tr2 );
800 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 4 );
801 myLastCreatedElems.Append(tr1);
802 GetMeshDS()->RemoveElement( tr2 );
804 //MESSAGE( endl << tr1 );
809 // check case of quadratic faces
810 const SMDS_QuadraticFaceOfNodes* QF1 =
811 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr1);
812 if(!QF1) return false;
813 const SMDS_QuadraticFaceOfNodes* QF2 =
814 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (tr2);
815 if(!QF2) return false;
818 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
819 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
827 const SMDS_MeshNode* N1 [6];
828 const SMDS_MeshNode* N2 [6];
829 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
831 // now we receive following N1 and N2 (using numeration as above image)
832 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
833 // i.e. first nodes from both arrays determ new diagonal
835 const SMDS_MeshNode* aNodes[8];
845 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
846 myLastCreatedElems.Append(tr1);
847 GetMeshDS()->RemoveElement( tr2 );
849 // remove middle node (9)
850 GetMeshDS()->RemoveNode( N1[4] );
855 //=======================================================================
856 //function : Reorient
857 //purpose : Reverse theElement orientation
858 //=======================================================================
860 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
862 myLastCreatedElems.Clear();
863 myLastCreatedNodes.Clear();
867 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
868 if ( !it || !it->more() )
871 switch ( theElem->GetType() ) {
875 if(!theElem->IsQuadratic()) {
876 int i = theElem->NbNodes();
877 vector<const SMDS_MeshNode*> aNodes( i );
879 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
880 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
883 // quadratic elements
884 if(theElem->GetType()==SMDSAbs_Edge) {
885 vector<const SMDS_MeshNode*> aNodes(3);
886 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
887 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
888 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
889 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
892 int nbn = theElem->NbNodes();
893 vector<const SMDS_MeshNode*> aNodes(nbn);
894 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
896 for(; i<nbn/2; i++) {
897 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
899 for(i=0; i<nbn/2; i++) {
900 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
902 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
906 case SMDSAbs_Volume: {
907 if (theElem->IsPoly()) {
908 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
909 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
911 MESSAGE("Warning: bad volumic element");
915 int nbFaces = aPolyedre->NbFaces();
916 vector<const SMDS_MeshNode *> poly_nodes;
917 vector<int> quantities (nbFaces);
919 // reverse each face of the polyedre
920 for (int iface = 1; iface <= nbFaces; iface++) {
921 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
922 quantities[iface - 1] = nbFaceNodes;
924 for (inode = nbFaceNodes; inode >= 1; inode--) {
925 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
926 poly_nodes.push_back(curNode);
930 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
934 SMDS_VolumeTool vTool;
935 if ( !vTool.Set( theElem ))
938 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
947 //=======================================================================
948 //function : getBadRate
950 //=======================================================================
952 static double getBadRate (const SMDS_MeshElement* theElem,
953 SMESH::Controls::NumericalFunctorPtr& theCrit)
955 SMESH::Controls::TSequenceOfXYZ P;
956 if ( !theElem || !theCrit->GetPoints( theElem, P ))
958 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
959 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
962 //=======================================================================
963 //function : QuadToTri
964 //purpose : Cut quadrangles into triangles.
965 // theCrit is used to select a diagonal to cut
966 //=======================================================================
968 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
969 SMESH::Controls::NumericalFunctorPtr theCrit)
971 myLastCreatedElems.Clear();
972 myLastCreatedNodes.Clear();
974 MESSAGE( "::QuadToTri()" );
976 if ( !theCrit.get() )
979 SMESHDS_Mesh * aMesh = GetMeshDS();
981 Handle(Geom_Surface) surface;
982 SMESH_MesherHelper helper( *GetMesh() );
984 TIDSortedElemSet::iterator itElem;
985 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
986 const SMDS_MeshElement* elem = *itElem;
987 if ( !elem || elem->GetType() != SMDSAbs_Face )
989 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
992 // retrieve element nodes
993 const SMDS_MeshNode* aNodes [8];
994 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
996 while ( itN->more() )
997 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
999 // compare two sets of possible triangles
1000 double aBadRate1, aBadRate2; // to what extent a set is bad
1001 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1002 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1003 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1005 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1006 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1007 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1009 int aShapeId = FindShape( elem );
1010 const SMDS_MeshElement* newElem = 0;
1012 if( !elem->IsQuadratic() ) {
1014 // split liner quadrangle
1016 if ( aBadRate1 <= aBadRate2 ) {
1017 // tr1 + tr2 is better
1018 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1019 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1022 // tr3 + tr4 is better
1023 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1024 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1029 // split quadratic quadrangle
1031 // get surface elem is on
1032 if ( aShapeId != helper.GetSubShapeID() ) {
1036 shape = aMesh->IndexToShape( aShapeId );
1037 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1038 TopoDS_Face face = TopoDS::Face( shape );
1039 surface = BRep_Tool::Surface( face );
1040 if ( !surface.IsNull() )
1041 helper.SetSubShape( shape );
1045 const SMDS_MeshNode* aNodes [8];
1046 const SMDS_MeshNode* inFaceNode = 0;
1047 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1049 while ( itN->more() ) {
1050 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1051 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1052 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1054 inFaceNode = aNodes[ i-1 ];
1057 // find middle point for (0,1,2,3)
1058 // and create a node in this point;
1060 if ( surface.IsNull() ) {
1062 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1066 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1069 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1071 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1073 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1074 myLastCreatedNodes.Append(newN);
1076 // create a new element
1077 const SMDS_MeshNode* N[6];
1078 if ( aBadRate1 <= aBadRate2 ) {
1085 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1086 aNodes[6], aNodes[7], newN );
1095 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1096 aNodes[7], aNodes[4], newN );
1098 aMesh->ChangeElementNodes( elem, N, 6 );
1102 // care of a new element
1104 myLastCreatedElems.Append(newElem);
1105 AddToSameGroups( newElem, elem, aMesh );
1107 // put a new triangle on the same shape
1109 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1114 //=======================================================================
1115 //function : BestSplit
1116 //purpose : Find better diagonal for cutting.
1117 //=======================================================================
1119 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1120 SMESH::Controls::NumericalFunctorPtr theCrit)
1122 myLastCreatedElems.Clear();
1123 myLastCreatedNodes.Clear();
1128 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1131 if( theQuad->NbNodes()==4 ||
1132 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1134 // retrieve element nodes
1135 const SMDS_MeshNode* aNodes [4];
1136 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1138 //while (itN->more())
1140 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1142 // compare two sets of possible triangles
1143 double aBadRate1, aBadRate2; // to what extent a set is bad
1144 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1145 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1146 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1148 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1149 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1150 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1152 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1153 return 1; // diagonal 1-3
1155 return 2; // diagonal 2-4
1162 // Methods of splitting volumes into tetra
1164 const int theHexTo5[5*4] =
1172 const int theHexTo6[6*4] =
1180 const int thePyraTo2[2*4] =
1186 const int thePentaTo8[8*4] =
1201 const int* _connectivity;
1202 bool _addNode; // additional node is to be created
1203 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1204 : _nbTetra(nbTet), _connectivity(conn), _addNode(addNode) {}
1208 * \brief return TSplitMethod for the given element
1210 TSplitMethod getSplitMethod( const SMDS_MeshElement* vol, const int theMethodFlags)
1212 TSplitMethod method;
1213 if ( vol->GetType() == SMDSAbs_Volume && !vol->IsPoly())
1214 switch ( vol->NbNodes() )
1218 if ( theMethodFlags & SMESH_MeshEditor::HEXA_TO_5 )
1219 method = TSplitMethod( 5, theHexTo5 );
1221 method = TSplitMethod( 6, theHexTo6 );
1225 method = TSplitMethod( 2, thePyraTo2 );
1229 method = TSplitMethod( 8, thePentaTo8, /*addNode=*/true );
1237 //=======================================================================
1238 //function : SplitVolumesIntoTetra
1239 //purpose : Split volumic elements into tetrahedra.
1240 //=======================================================================
1242 // void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1243 // const int theMethodFlags)
1245 // // sdt-like iterator on coordinates of nodes of mesh element
1246 // typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1247 // NXyzIterator xyzEnd;
1249 // SMESH_MesherHelper helper( *GetMesh());
1251 // TIDSortedElemSet::const_iterator elem = theElems.begin();
1252 // for ( ; elem != theElems.end(); ++elem )
1254 // SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1255 // if ( geomType <= SMDSEntity_Quad_Tetra )
1256 // continue; // tetra or face or edge
1258 // if ( (*elem)->IsQuadratic() )
1260 // // add quadratic links to the helper
1261 // SMDS_VolumeTool vol( *elem );
1262 // for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1264 // const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1265 // for ( int iN = 0; iN < vol.NbFaceNodes( iF ); iN += 2)
1266 // helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1268 // helper.SetIsQuadratic( true );
1272 // helper.SetIsQuadratic( false );
1275 // vector<const SMDS_MeshElement* > tetras; // splits of a volume
1277 // if ( geomType == SMDSEntity_Polyhedra )
1279 // // Each face of a polyhedron is split into triangles and
1280 // // each of triangles and a cell barycenter form a tetrahedron.
1282 // SMDS_VolumeTool vol( *elem );
1284 // // make a node at barycenter
1285 // gp_XYZ gc = std::accumulate( NXyzIterator((*elem)->nodesIterator()), xyzEnd,gp_XYZ(0,0,0));
1286 // gc /= vol.NbNodes();
1287 // SMDS_MeshNode* gcNode = GetMeshDS()->AddNode( gc.X(), gc.Y(), gc.Z() );
1289 // for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1291 // const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1292 // int nbFNodes = vol.NbFaceNodes( iF );
1293 // int nbTria = nbFNodes - 2;
1294 // bool extFace = vol.IsFaceExternal( iF );
1295 // SMDS_MeshElement* tet;
1296 // for ( int i = 0; i < nbTria; ++i )
1299 // tet = helper.AddVolume( fNodes[0], fNodes[i+1], fNodes[i+2], gcNode );
1301 // tet = helper.AddVolume( fNodes[0], fNodes[i+2], fNodes[i+1], gcNode );
1302 // tetras.push_back( tet );
1310 // TSplitMethod splitMethod = getSplitMethod( *elem, theMethodFlags );
1311 // if ( splitMethod._nbTetra < 1 ) continue;
1313 // vector<const SMDS_MeshNode*> volNodes( (*elem)->begin_nodes(), (*elem)->end_nodes());
1318 //=======================================================================
1319 //function : AddToSameGroups
1320 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1321 //=======================================================================
1323 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1324 const SMDS_MeshElement* elemInGroups,
1325 SMESHDS_Mesh * aMesh)
1327 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1328 if (!groups.empty()) {
1329 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1330 for ( ; grIt != groups.end(); grIt++ ) {
1331 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1332 if ( group && group->Contains( elemInGroups ))
1333 group->SMDSGroup().Add( elemToAdd );
1339 //=======================================================================
1340 //function : RemoveElemFromGroups
1341 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1342 //=======================================================================
1343 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1344 SMESHDS_Mesh * aMesh)
1346 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1347 if (!groups.empty())
1349 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1350 for (; GrIt != groups.end(); GrIt++)
1352 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1353 if (!grp || grp->IsEmpty()) continue;
1354 grp->SMDSGroup().Remove(removeelem);
1359 //=======================================================================
1360 //function : ReplaceElemInGroups
1361 //purpose : replace elemToRm by elemToAdd in the all groups
1362 //=======================================================================
1364 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1365 const SMDS_MeshElement* elemToAdd,
1366 SMESHDS_Mesh * aMesh)
1368 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1369 if (!groups.empty()) {
1370 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1371 for ( ; grIt != groups.end(); grIt++ ) {
1372 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1373 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1374 group->SMDSGroup().Add( elemToAdd );
1379 //=======================================================================
1380 //function : QuadToTri
1381 //purpose : Cut quadrangles into triangles.
1382 // theCrit is used to select a diagonal to cut
1383 //=======================================================================
1385 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1386 const bool the13Diag)
1388 myLastCreatedElems.Clear();
1389 myLastCreatedNodes.Clear();
1391 MESSAGE( "::QuadToTri()" );
1393 SMESHDS_Mesh * aMesh = GetMeshDS();
1395 Handle(Geom_Surface) surface;
1396 SMESH_MesherHelper helper( *GetMesh() );
1398 TIDSortedElemSet::iterator itElem;
1399 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1400 const SMDS_MeshElement* elem = *itElem;
1401 if ( !elem || elem->GetType() != SMDSAbs_Face )
1403 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1404 if(!isquad) continue;
1406 if(elem->NbNodes()==4) {
1407 // retrieve element nodes
1408 const SMDS_MeshNode* aNodes [4];
1409 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1411 while ( itN->more() )
1412 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1414 int aShapeId = FindShape( elem );
1415 const SMDS_MeshElement* newElem = 0;
1417 aMesh->ChangeElementNodes( elem, aNodes, 3 );
1418 newElem = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1421 aMesh->ChangeElementNodes( elem, &aNodes[1], 3 );
1422 newElem = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1424 myLastCreatedElems.Append(newElem);
1425 // put a new triangle on the same shape and add to the same groups
1427 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1428 AddToSameGroups( newElem, elem, aMesh );
1431 // Quadratic quadrangle
1433 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1435 // get surface elem is on
1436 int aShapeId = FindShape( elem );
1437 if ( aShapeId != helper.GetSubShapeID() ) {
1441 shape = aMesh->IndexToShape( aShapeId );
1442 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1443 TopoDS_Face face = TopoDS::Face( shape );
1444 surface = BRep_Tool::Surface( face );
1445 if ( !surface.IsNull() )
1446 helper.SetSubShape( shape );
1450 const SMDS_MeshNode* aNodes [8];
1451 const SMDS_MeshNode* inFaceNode = 0;
1452 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1454 while ( itN->more() ) {
1455 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1456 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1457 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1459 inFaceNode = aNodes[ i-1 ];
1463 // find middle point for (0,1,2,3)
1464 // and create a node in this point;
1466 if ( surface.IsNull() ) {
1468 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1472 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1475 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1477 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1479 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1480 myLastCreatedNodes.Append(newN);
1482 // create a new element
1483 const SMDS_MeshElement* newElem = 0;
1484 const SMDS_MeshNode* N[6];
1492 newElem = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1493 aNodes[6], aNodes[7], newN );
1502 newElem = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1503 aNodes[7], aNodes[4], newN );
1505 myLastCreatedElems.Append(newElem);
1506 aMesh->ChangeElementNodes( elem, N, 6 );
1507 // put a new triangle on the same shape and add to the same groups
1509 aMesh->SetMeshElementOnShape( newElem, aShapeId );
1510 AddToSameGroups( newElem, elem, aMesh );
1517 //=======================================================================
1518 //function : getAngle
1520 //=======================================================================
1522 double getAngle(const SMDS_MeshElement * tr1,
1523 const SMDS_MeshElement * tr2,
1524 const SMDS_MeshNode * n1,
1525 const SMDS_MeshNode * n2)
1527 double angle = 2*PI; // bad angle
1530 SMESH::Controls::TSequenceOfXYZ P1, P2;
1531 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1532 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1535 if(!tr1->IsQuadratic())
1536 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1538 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1539 if ( N1.SquareMagnitude() <= gp::Resolution() )
1541 if(!tr2->IsQuadratic())
1542 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1544 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1545 if ( N2.SquareMagnitude() <= gp::Resolution() )
1548 // find the first diagonal node n1 in the triangles:
1549 // take in account a diagonal link orientation
1550 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1551 for ( int t = 0; t < 2; t++ ) {
1552 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1553 int i = 0, iDiag = -1;
1554 while ( it->more()) {
1555 const SMDS_MeshElement *n = it->next();
1556 if ( n == n1 || n == n2 )
1560 if ( i - iDiag == 1 )
1561 nFirst[ t ] = ( n == n1 ? n2 : n1 );
1569 if ( nFirst[ 0 ] == nFirst[ 1 ] )
1572 angle = N1.Angle( N2 );
1577 // =================================================
1578 // class generating a unique ID for a pair of nodes
1579 // and able to return nodes by that ID
1580 // =================================================
1584 LinkID_Gen( const SMESHDS_Mesh* theMesh )
1585 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
1588 long GetLinkID (const SMDS_MeshNode * n1,
1589 const SMDS_MeshNode * n2) const
1591 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
1594 bool GetNodes (const long theLinkID,
1595 const SMDS_MeshNode* & theNode1,
1596 const SMDS_MeshNode* & theNode2) const
1598 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
1599 if ( !theNode1 ) return false;
1600 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
1601 if ( !theNode2 ) return false;
1607 const SMESHDS_Mesh* myMesh;
1612 //=======================================================================
1613 //function : TriToQuad
1614 //purpose : Fuse neighbour triangles into quadrangles.
1615 // theCrit is used to select a neighbour to fuse with.
1616 // theMaxAngle is a max angle between element normals at which
1617 // fusion is still performed.
1618 //=======================================================================
1620 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
1621 SMESH::Controls::NumericalFunctorPtr theCrit,
1622 const double theMaxAngle)
1624 myLastCreatedElems.Clear();
1625 myLastCreatedNodes.Clear();
1627 MESSAGE( "::TriToQuad()" );
1629 if ( !theCrit.get() )
1632 SMESHDS_Mesh * aMesh = GetMeshDS();
1634 // Prepare data for algo: build
1635 // 1. map of elements with their linkIDs
1636 // 2. map of linkIDs with their elements
1638 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
1639 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
1640 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
1641 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
1643 TIDSortedElemSet::iterator itElem;
1644 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1645 const SMDS_MeshElement* elem = *itElem;
1646 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
1647 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
1648 if(!IsTria) continue;
1650 // retrieve element nodes
1651 const SMDS_MeshNode* aNodes [4];
1652 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1655 aNodes[ i++ ] = cast2Node( itN->next() );
1656 aNodes[ 3 ] = aNodes[ 0 ];
1659 for ( i = 0; i < 3; i++ ) {
1660 SMESH_TLink link( aNodes[i], aNodes[i+1] );
1661 // check if elements sharing a link can be fused
1662 itLE = mapLi_listEl.find( link );
1663 if ( itLE != mapLi_listEl.end() ) {
1664 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
1666 const SMDS_MeshElement* elem2 = (*itLE).second.front();
1667 //if ( FindShape( elem ) != FindShape( elem2 ))
1668 // continue; // do not fuse triangles laying on different shapes
1669 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
1670 continue; // avoid making badly shaped quads
1671 (*itLE).second.push_back( elem );
1674 mapLi_listEl[ link ].push_back( elem );
1676 mapEl_setLi [ elem ].insert( link );
1679 // Clean the maps from the links shared by a sole element, ie
1680 // links to which only one element is bound in mapLi_listEl
1682 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
1683 int nbElems = (*itLE).second.size();
1684 if ( nbElems < 2 ) {
1685 const SMDS_MeshElement* elem = (*itLE).second.front();
1686 SMESH_TLink link = (*itLE).first;
1687 mapEl_setLi[ elem ].erase( link );
1688 if ( mapEl_setLi[ elem ].empty() )
1689 mapEl_setLi.erase( elem );
1693 // Algo: fuse triangles into quadrangles
1695 while ( ! mapEl_setLi.empty() ) {
1696 // Look for the start element:
1697 // the element having the least nb of shared links
1698 const SMDS_MeshElement* startElem = 0;
1700 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
1701 int nbLinks = (*itEL).second.size();
1702 if ( nbLinks < minNbLinks ) {
1703 startElem = (*itEL).first;
1704 minNbLinks = nbLinks;
1705 if ( minNbLinks == 1 )
1710 // search elements to fuse starting from startElem or links of elements
1711 // fused earlyer - startLinks
1712 list< SMESH_TLink > startLinks;
1713 while ( startElem || !startLinks.empty() ) {
1714 while ( !startElem && !startLinks.empty() ) {
1715 // Get an element to start, by a link
1716 SMESH_TLink linkId = startLinks.front();
1717 startLinks.pop_front();
1718 itLE = mapLi_listEl.find( linkId );
1719 if ( itLE != mapLi_listEl.end() ) {
1720 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
1721 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
1722 for ( ; itE != listElem.end() ; itE++ )
1723 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
1725 mapLi_listEl.erase( itLE );
1730 // Get candidates to be fused
1731 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
1732 const SMESH_TLink *link12, *link13;
1734 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
1735 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
1736 ASSERT( !setLi.empty() );
1737 set< SMESH_TLink >::iterator itLi;
1738 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
1740 const SMESH_TLink & link = (*itLi);
1741 itLE = mapLi_listEl.find( link );
1742 if ( itLE == mapLi_listEl.end() )
1745 const SMDS_MeshElement* elem = (*itLE).second.front();
1747 elem = (*itLE).second.back();
1748 mapLi_listEl.erase( itLE );
1749 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
1760 // add other links of elem to list of links to re-start from
1761 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
1762 set< SMESH_TLink >::iterator it;
1763 for ( it = links.begin(); it != links.end(); it++ ) {
1764 const SMESH_TLink& link2 = (*it);
1765 if ( link2 != link )
1766 startLinks.push_back( link2 );
1770 // Get nodes of possible quadrangles
1771 const SMDS_MeshNode *n12 [4], *n13 [4];
1772 bool Ok12 = false, Ok13 = false;
1773 const SMDS_MeshNode *linkNode1, *linkNode2;
1775 linkNode1 = link12->first;
1776 linkNode2 = link12->second;
1777 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
1781 linkNode1 = link13->first;
1782 linkNode2 = link13->second;
1783 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
1787 // Choose a pair to fuse
1788 if ( Ok12 && Ok13 ) {
1789 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
1790 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
1791 double aBadRate12 = getBadRate( &quad12, theCrit );
1792 double aBadRate13 = getBadRate( &quad13, theCrit );
1793 if ( aBadRate13 < aBadRate12 )
1800 // and remove fused elems and removed links from the maps
1801 mapEl_setLi.erase( tr1 );
1803 mapEl_setLi.erase( tr2 );
1804 mapLi_listEl.erase( *link12 );
1805 if(tr1->NbNodes()==3) {
1806 if( tr1->GetID() < tr2->GetID() ) {
1807 aMesh->ChangeElementNodes( tr1, n12, 4 );
1808 myLastCreatedElems.Append(tr1);
1809 aMesh->RemoveElement( tr2 );
1812 aMesh->ChangeElementNodes( tr2, n12, 4 );
1813 myLastCreatedElems.Append(tr2);
1814 aMesh->RemoveElement( tr1);
1818 const SMDS_MeshNode* N1 [6];
1819 const SMDS_MeshNode* N2 [6];
1820 GetNodesFromTwoTria(tr1,tr2,N1,N2);
1821 // now we receive following N1 and N2 (using numeration as above image)
1822 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1823 // i.e. first nodes from both arrays determ new diagonal
1824 const SMDS_MeshNode* aNodes[8];
1833 if( tr1->GetID() < tr2->GetID() ) {
1834 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1835 myLastCreatedElems.Append(tr1);
1836 GetMeshDS()->RemoveElement( tr2 );
1839 GetMeshDS()->ChangeElementNodes( tr2, aNodes, 8 );
1840 myLastCreatedElems.Append(tr2);
1841 GetMeshDS()->RemoveElement( tr1 );
1843 // remove middle node (9)
1844 GetMeshDS()->RemoveNode( N1[4] );
1848 mapEl_setLi.erase( tr3 );
1849 mapLi_listEl.erase( *link13 );
1850 if(tr1->NbNodes()==3) {
1851 if( tr1->GetID() < tr2->GetID() ) {
1852 aMesh->ChangeElementNodes( tr1, n13, 4 );
1853 myLastCreatedElems.Append(tr1);
1854 aMesh->RemoveElement( tr3 );
1857 aMesh->ChangeElementNodes( tr3, n13, 4 );
1858 myLastCreatedElems.Append(tr3);
1859 aMesh->RemoveElement( tr1 );
1863 const SMDS_MeshNode* N1 [6];
1864 const SMDS_MeshNode* N2 [6];
1865 GetNodesFromTwoTria(tr1,tr3,N1,N2);
1866 // now we receive following N1 and N2 (using numeration as above image)
1867 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
1868 // i.e. first nodes from both arrays determ new diagonal
1869 const SMDS_MeshNode* aNodes[8];
1878 if( tr1->GetID() < tr2->GetID() ) {
1879 GetMeshDS()->ChangeElementNodes( tr1, aNodes, 8 );
1880 myLastCreatedElems.Append(tr1);
1881 GetMeshDS()->RemoveElement( tr3 );
1884 GetMeshDS()->ChangeElementNodes( tr3, aNodes, 8 );
1885 myLastCreatedElems.Append(tr3);
1886 GetMeshDS()->RemoveElement( tr1 );
1888 // remove middle node (9)
1889 GetMeshDS()->RemoveNode( N1[4] );
1893 // Next element to fuse: the rejected one
1895 startElem = Ok12 ? tr3 : tr2;
1897 } // if ( startElem )
1898 } // while ( startElem || !startLinks.empty() )
1899 } // while ( ! mapEl_setLi.empty() )
1905 /*#define DUMPSO(txt) \
1906 // cout << txt << endl;
1907 //=============================================================================
1911 //=============================================================================
1912 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
1916 int tmp = idNodes[ i1 ];
1917 idNodes[ i1 ] = idNodes[ i2 ];
1918 idNodes[ i2 ] = tmp;
1919 gp_Pnt Ptmp = P[ i1 ];
1922 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
1925 //=======================================================================
1926 //function : SortQuadNodes
1927 //purpose : Set 4 nodes of a quadrangle face in a good order.
1928 // Swap 1<->2 or 2<->3 nodes and correspondingly return
1930 //=======================================================================
1932 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
1937 for ( i = 0; i < 4; i++ ) {
1938 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1940 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1943 gp_Vec V1(P[0], P[1]);
1944 gp_Vec V2(P[0], P[2]);
1945 gp_Vec V3(P[0], P[3]);
1947 gp_Vec Cross1 = V1 ^ V2;
1948 gp_Vec Cross2 = V2 ^ V3;
1951 if (Cross1.Dot(Cross2) < 0)
1956 if (Cross1.Dot(Cross2) < 0)
1960 swap ( i, i + 1, idNodes, P );
1962 // for ( int ii = 0; ii < 4; ii++ ) {
1963 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
1964 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1970 //=======================================================================
1971 //function : SortHexaNodes
1972 //purpose : Set 8 nodes of a hexahedron in a good order.
1973 // Return success status
1974 //=======================================================================
1976 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
1981 DUMPSO( "INPUT: ========================================");
1982 for ( i = 0; i < 8; i++ ) {
1983 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
1984 if ( !n ) return false;
1985 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
1986 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
1988 DUMPSO( "========================================");
1991 set<int> faceNodes; // ids of bottom face nodes, to be found
1992 set<int> checkedId1; // ids of tried 2-nd nodes
1993 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
1994 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
1995 int iMin, iLoop1 = 0;
1997 // Loop to try the 2-nd nodes
1999 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2001 // Find not checked 2-nd node
2002 for ( i = 1; i < 8; i++ )
2003 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2004 int id1 = idNodes[i];
2005 swap ( 1, i, idNodes, P );
2006 checkedId1.insert ( id1 );
2010 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2011 // ie that all but meybe one (id3 which is on the same face) nodes
2012 // lay on the same side from the triangle plane.
2014 bool manyInPlane = false; // more than 4 nodes lay in plane
2016 while ( ++iLoop2 < 6 ) {
2018 // get 1-2-3 plane coeffs
2019 Standard_Real A, B, C, D;
2020 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2021 if ( N.SquareMagnitude() > gp::Resolution() )
2023 gp_Pln pln ( P[0], N );
2024 pln.Coefficients( A, B, C, D );
2026 // find the node (iMin) closest to pln
2027 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2029 for ( i = 3; i < 8; i++ ) {
2030 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2031 if ( fabs( dist[i] ) < minDist ) {
2032 minDist = fabs( dist[i] );
2035 if ( fabs( dist[i] ) <= tol )
2036 idInPln.insert( idNodes[i] );
2039 // there should not be more than 4 nodes in bottom plane
2040 if ( idInPln.size() > 1 )
2042 DUMPSO( "### idInPln.size() = " << idInPln.size());
2043 // idInPlane does not contain the first 3 nodes
2044 if ( manyInPlane || idInPln.size() == 5)
2045 return false; // all nodes in one plane
2048 // set the 1-st node to be not in plane
2049 for ( i = 3; i < 8; i++ ) {
2050 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2051 DUMPSO( "### Reset 0-th node");
2052 swap( 0, i, idNodes, P );
2057 // reset to re-check second nodes
2058 leastDist = DBL_MAX;
2062 break; // from iLoop2;
2065 // check that the other 4 nodes are on the same side
2066 bool sameSide = true;
2067 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2068 for ( i = 3; sameSide && i < 8; i++ ) {
2070 sameSide = ( isNeg == dist[i] <= 0.);
2073 // keep best solution
2074 if ( sameSide && minDist < leastDist ) {
2075 leastDist = minDist;
2077 faceNodes.insert( idNodes[ 1 ] );
2078 faceNodes.insert( idNodes[ 2 ] );
2079 faceNodes.insert( idNodes[ iMin ] );
2080 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2081 << " leastDist = " << leastDist);
2082 if ( leastDist <= DBL_MIN )
2087 // set next 3-d node to check
2088 int iNext = 2 + iLoop2;
2090 DUMPSO( "Try 2-nd");
2091 swap ( 2, iNext, idNodes, P );
2093 } // while ( iLoop2 < 6 )
2096 if ( faceNodes.empty() ) return false;
2098 // Put the faceNodes in proper places
2099 for ( i = 4; i < 8; i++ ) {
2100 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2101 // find a place to put
2103 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2105 DUMPSO( "Set faceNodes");
2106 swap ( iTo, i, idNodes, P );
2111 // Set nodes of the found bottom face in good order
2112 DUMPSO( " Found bottom face: ");
2113 i = SortQuadNodes( theMesh, idNodes );
2115 gp_Pnt Ptmp = P[ i ];
2120 // for ( int ii = 0; ii < 4; ii++ ) {
2121 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2122 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2125 // Gravity center of the top and bottom faces
2126 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2127 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2129 // Get direction from the bottom to the top face
2130 gp_Vec upDir ( aGCb, aGCt );
2131 Standard_Real upDirSize = upDir.Magnitude();
2132 if ( upDirSize <= gp::Resolution() ) return false;
2135 // Assure that the bottom face normal points up
2136 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2137 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2138 if ( Nb.Dot( upDir ) < 0 ) {
2139 DUMPSO( "Reverse bottom face");
2140 swap( 1, 3, idNodes, P );
2143 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2144 Standard_Real minDist = DBL_MAX;
2145 for ( i = 4; i < 8; i++ ) {
2146 // projection of P[i] to the plane defined by P[0] and upDir
2147 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2148 Standard_Real sqDist = P[0].SquareDistance( Pp );
2149 if ( sqDist < minDist ) {
2154 DUMPSO( "Set 4-th");
2155 swap ( 4, iMin, idNodes, P );
2157 // Set nodes of the top face in good order
2158 DUMPSO( "Sort top face");
2159 i = SortQuadNodes( theMesh, &idNodes[4] );
2162 gp_Pnt Ptmp = P[ i ];
2167 // Assure that direction of the top face normal is from the bottom face
2168 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2169 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2170 if ( Nt.Dot( upDir ) < 0 ) {
2171 DUMPSO( "Reverse top face");
2172 swap( 5, 7, idNodes, P );
2175 // DUMPSO( "OUTPUT: ========================================");
2176 // for ( i = 0; i < 8; i++ ) {
2177 // float *p = ugrid->GetPoint(idNodes[i]);
2178 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2184 //================================================================================
2186 * \brief Return nodes linked to the given one
2187 * \param theNode - the node
2188 * \param linkedNodes - the found nodes
2189 * \param type - the type of elements to check
2191 * Medium nodes are ignored
2193 //================================================================================
2195 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2196 TIDSortedElemSet & linkedNodes,
2197 SMDSAbs_ElementType type )
2199 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2200 while ( elemIt->more() )
2202 const SMDS_MeshElement* elem = elemIt->next();
2203 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2204 if ( elem->GetType() == SMDSAbs_Volume )
2206 SMDS_VolumeTool vol( elem );
2207 while ( nodeIt->more() ) {
2208 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2209 if ( theNode != n && vol.IsLinked( theNode, n ))
2210 linkedNodes.insert( n );
2215 for ( int i = 0; nodeIt->more(); ++i ) {
2216 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2217 if ( n == theNode ) {
2218 int iBefore = i - 1;
2220 if ( elem->IsQuadratic() ) {
2221 int nb = elem->NbNodes() / 2;
2222 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2223 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2225 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2226 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2233 //=======================================================================
2234 //function : laplacianSmooth
2235 //purpose : pulls theNode toward the center of surrounding nodes directly
2236 // connected to that node along an element edge
2237 //=======================================================================
2239 void laplacianSmooth(const SMDS_MeshNode* theNode,
2240 const Handle(Geom_Surface)& theSurface,
2241 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2243 // find surrounding nodes
2245 TIDSortedElemSet nodeSet;
2246 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2248 // compute new coodrs
2250 double coord[] = { 0., 0., 0. };
2251 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2252 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2253 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2254 if ( theSurface.IsNull() ) { // smooth in 3D
2255 coord[0] += node->X();
2256 coord[1] += node->Y();
2257 coord[2] += node->Z();
2259 else { // smooth in 2D
2260 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2261 gp_XY* uv = theUVMap[ node ];
2262 coord[0] += uv->X();
2263 coord[1] += uv->Y();
2266 int nbNodes = nodeSet.size();
2269 coord[0] /= nbNodes;
2270 coord[1] /= nbNodes;
2272 if ( !theSurface.IsNull() ) {
2273 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2274 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2275 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2281 coord[2] /= nbNodes;
2285 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2288 //=======================================================================
2289 //function : centroidalSmooth
2290 //purpose : pulls theNode toward the element-area-weighted centroid of the
2291 // surrounding elements
2292 //=======================================================================
2294 void centroidalSmooth(const SMDS_MeshNode* theNode,
2295 const Handle(Geom_Surface)& theSurface,
2296 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2298 gp_XYZ aNewXYZ(0.,0.,0.);
2299 SMESH::Controls::Area anAreaFunc;
2300 double totalArea = 0.;
2305 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2306 while ( elemIt->more() )
2308 const SMDS_MeshElement* elem = elemIt->next();
2311 gp_XYZ elemCenter(0.,0.,0.);
2312 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2313 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2314 int nn = elem->NbNodes();
2315 if(elem->IsQuadratic()) nn = nn/2;
2317 //while ( itN->more() ) {
2319 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2321 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2322 aNodePoints.push_back( aP );
2323 if ( !theSurface.IsNull() ) { // smooth in 2D
2324 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2325 gp_XY* uv = theUVMap[ aNode ];
2326 aP.SetCoord( uv->X(), uv->Y(), 0. );
2330 double elemArea = anAreaFunc.GetValue( aNodePoints );
2331 totalArea += elemArea;
2333 aNewXYZ += elemCenter * elemArea;
2335 aNewXYZ /= totalArea;
2336 if ( !theSurface.IsNull() ) {
2337 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2338 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2343 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2346 //=======================================================================
2347 //function : getClosestUV
2348 //purpose : return UV of closest projection
2349 //=======================================================================
2351 static bool getClosestUV (Extrema_GenExtPS& projector,
2352 const gp_Pnt& point,
2355 projector.Perform( point );
2356 if ( projector.IsDone() ) {
2357 double u, v, minVal = DBL_MAX;
2358 for ( int i = projector.NbExt(); i > 0; i-- )
2359 if ( projector.Value( i ) < minVal ) {
2360 minVal = projector.Value( i );
2361 projector.Point( i ).Parameter( u, v );
2363 result.SetCoord( u, v );
2369 //=======================================================================
2371 //purpose : Smooth theElements during theNbIterations or until a worst
2372 // element has aspect ratio <= theTgtAspectRatio.
2373 // Aspect Ratio varies in range [1.0, inf].
2374 // If theElements is empty, the whole mesh is smoothed.
2375 // theFixedNodes contains additionally fixed nodes. Nodes built
2376 // on edges and boundary nodes are always fixed.
2377 //=======================================================================
2379 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2380 set<const SMDS_MeshNode*> & theFixedNodes,
2381 const SmoothMethod theSmoothMethod,
2382 const int theNbIterations,
2383 double theTgtAspectRatio,
2386 myLastCreatedElems.Clear();
2387 myLastCreatedNodes.Clear();
2389 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2391 if ( theTgtAspectRatio < 1.0 )
2392 theTgtAspectRatio = 1.0;
2394 const double disttol = 1.e-16;
2396 SMESH::Controls::AspectRatio aQualityFunc;
2398 SMESHDS_Mesh* aMesh = GetMeshDS();
2400 if ( theElems.empty() ) {
2401 // add all faces to theElems
2402 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2403 while ( fIt->more() ) {
2404 const SMDS_MeshElement* face = fIt->next();
2405 theElems.insert( face );
2408 // get all face ids theElems are on
2409 set< int > faceIdSet;
2410 TIDSortedElemSet::iterator itElem;
2412 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2413 int fId = FindShape( *itElem );
2414 // check that corresponding submesh exists and a shape is face
2416 faceIdSet.find( fId ) == faceIdSet.end() &&
2417 aMesh->MeshElements( fId )) {
2418 TopoDS_Shape F = aMesh->IndexToShape( fId );
2419 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2420 faceIdSet.insert( fId );
2423 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2425 // ===============================================
2426 // smooth elements on each TopoDS_Face separately
2427 // ===============================================
2429 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2430 for ( ; fId != faceIdSet.rend(); ++fId ) {
2431 // get face surface and submesh
2432 Handle(Geom_Surface) surface;
2433 SMESHDS_SubMesh* faceSubMesh = 0;
2435 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2436 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2437 bool isUPeriodic = false, isVPeriodic = false;
2439 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2440 surface = BRep_Tool::Surface( face );
2441 faceSubMesh = aMesh->MeshElements( *fId );
2442 fToler2 = BRep_Tool::Tolerance( face );
2443 fToler2 *= fToler2 * 10.;
2444 isUPeriodic = surface->IsUPeriodic();
2446 vPeriod = surface->UPeriod();
2447 isVPeriodic = surface->IsVPeriodic();
2449 uPeriod = surface->VPeriod();
2450 surface->Bounds( u1, u2, v1, v2 );
2452 // ---------------------------------------------------------
2453 // for elements on a face, find movable and fixed nodes and
2454 // compute UV for them
2455 // ---------------------------------------------------------
2456 bool checkBoundaryNodes = false;
2457 bool isQuadratic = false;
2458 set<const SMDS_MeshNode*> setMovableNodes;
2459 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2460 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2461 list< const SMDS_MeshElement* > elemsOnFace;
2463 Extrema_GenExtPS projector;
2464 GeomAdaptor_Surface surfAdaptor;
2465 if ( !surface.IsNull() ) {
2466 surfAdaptor.Load( surface );
2467 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2469 int nbElemOnFace = 0;
2470 itElem = theElems.begin();
2471 // loop on not yet smoothed elements: look for elems on a face
2472 while ( itElem != theElems.end() ) {
2473 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2474 break; // all elements found
2476 const SMDS_MeshElement* elem = *itElem;
2477 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2478 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2482 elemsOnFace.push_back( elem );
2483 theElems.erase( itElem++ );
2487 isQuadratic = elem->IsQuadratic();
2489 // get movable nodes of elem
2490 const SMDS_MeshNode* node;
2491 SMDS_TypeOfPosition posType;
2492 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2493 int nn = 0, nbn = elem->NbNodes();
2494 if(elem->IsQuadratic())
2496 while ( nn++ < nbn ) {
2497 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2498 const SMDS_PositionPtr& pos = node->GetPosition();
2499 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2500 if (posType != SMDS_TOP_EDGE &&
2501 posType != SMDS_TOP_VERTEX &&
2502 theFixedNodes.find( node ) == theFixedNodes.end())
2504 // check if all faces around the node are on faceSubMesh
2505 // because a node on edge may be bound to face
2506 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2508 if ( faceSubMesh ) {
2509 while ( eIt->more() && all ) {
2510 const SMDS_MeshElement* e = eIt->next();
2511 all = faceSubMesh->Contains( e );
2515 setMovableNodes.insert( node );
2517 checkBoundaryNodes = true;
2519 if ( posType == SMDS_TOP_3DSPACE )
2520 checkBoundaryNodes = true;
2523 if ( surface.IsNull() )
2526 // get nodes to check UV
2527 list< const SMDS_MeshNode* > uvCheckNodes;
2528 itN = elem->nodesIterator();
2529 nn = 0; nbn = elem->NbNodes();
2530 if(elem->IsQuadratic())
2532 while ( nn++ < nbn ) {
2533 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2534 if ( uvMap.find( node ) == uvMap.end() )
2535 uvCheckNodes.push_back( node );
2536 // add nodes of elems sharing node
2537 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2538 // while ( eIt->more() ) {
2539 // const SMDS_MeshElement* e = eIt->next();
2540 // if ( e != elem ) {
2541 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2542 // while ( nIt->more() ) {
2543 // const SMDS_MeshNode* n =
2544 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2545 // if ( uvMap.find( n ) == uvMap.end() )
2546 // uvCheckNodes.push_back( n );
2552 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
2553 for ( ; n != uvCheckNodes.end(); ++n ) {
2556 const SMDS_PositionPtr& pos = node->GetPosition();
2557 posType = pos.get() ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2559 switch ( posType ) {
2560 case SMDS_TOP_FACE: {
2561 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos.get();
2562 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
2565 case SMDS_TOP_EDGE: {
2566 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2567 Handle(Geom2d_Curve) pcurve;
2568 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
2569 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
2570 if ( !pcurve.IsNull() ) {
2571 double u = (( SMDS_EdgePosition* ) pos.get() )->GetUParameter();
2572 uv = pcurve->Value( u ).XY();
2576 case SMDS_TOP_VERTEX: {
2577 TopoDS_Shape S = aMesh->IndexToShape( pos->GetShapeId() );
2578 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
2579 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
2584 // check existing UV
2585 bool project = true;
2586 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
2587 double dist1 = DBL_MAX, dist2 = 0;
2588 if ( posType != SMDS_TOP_3DSPACE ) {
2589 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
2590 project = dist1 > fToler2;
2592 if ( project ) { // compute new UV
2594 if ( !getClosestUV( projector, pNode, newUV )) {
2595 MESSAGE("Node Projection Failed " << node);
2599 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
2601 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
2603 if ( posType != SMDS_TOP_3DSPACE )
2604 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
2605 if ( dist2 < dist1 )
2609 // store UV in the map
2610 listUV.push_back( uv );
2611 uvMap.insert( make_pair( node, &listUV.back() ));
2613 } // loop on not yet smoothed elements
2615 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
2616 checkBoundaryNodes = true;
2618 // fix nodes on mesh boundary
2620 if ( checkBoundaryNodes ) {
2621 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
2622 map< NLink, int >::iterator link_nb;
2623 // put all elements links to linkNbMap
2624 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2625 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2626 const SMDS_MeshElement* elem = (*elemIt);
2627 int nbn = elem->NbNodes();
2628 if(elem->IsQuadratic())
2630 // loop on elem links: insert them in linkNbMap
2631 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
2632 for ( int iN = 0; iN < nbn; ++iN ) {
2633 curNode = elem->GetNode( iN );
2635 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
2636 else link = make_pair( prevNode , curNode );
2638 link_nb = linkNbMap.find( link );
2639 if ( link_nb == linkNbMap.end() )
2640 linkNbMap.insert( make_pair ( link, 1 ));
2645 // remove nodes that are in links encountered only once from setMovableNodes
2646 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
2647 if ( link_nb->second == 1 ) {
2648 setMovableNodes.erase( link_nb->first.first );
2649 setMovableNodes.erase( link_nb->first.second );
2654 // -----------------------------------------------------
2655 // for nodes on seam edge, compute one more UV ( uvMap2 );
2656 // find movable nodes linked to nodes on seam and which
2657 // are to be smoothed using the second UV ( uvMap2 )
2658 // -----------------------------------------------------
2660 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
2661 if ( !surface.IsNull() ) {
2662 TopExp_Explorer eExp( face, TopAbs_EDGE );
2663 for ( ; eExp.More(); eExp.Next() ) {
2664 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
2665 if ( !BRep_Tool::IsClosed( edge, face ))
2667 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
2668 if ( !sm ) continue;
2669 // find out which parameter varies for a node on seam
2672 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2673 if ( pcurve.IsNull() ) continue;
2674 uv1 = pcurve->Value( f );
2676 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
2677 if ( pcurve.IsNull() ) continue;
2678 uv2 = pcurve->Value( f );
2679 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
2681 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
2682 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
2684 // get nodes on seam and its vertices
2685 list< const SMDS_MeshNode* > seamNodes;
2686 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
2687 while ( nSeamIt->more() ) {
2688 const SMDS_MeshNode* node = nSeamIt->next();
2689 if ( !isQuadratic || !IsMedium( node ))
2690 seamNodes.push_back( node );
2692 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
2693 for ( ; vExp.More(); vExp.Next() ) {
2694 sm = aMesh->MeshElements( vExp.Current() );
2696 nSeamIt = sm->GetNodes();
2697 while ( nSeamIt->more() )
2698 seamNodes.push_back( nSeamIt->next() );
2701 // loop on nodes on seam
2702 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
2703 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
2704 const SMDS_MeshNode* nSeam = *noSeIt;
2705 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
2706 if ( n_uv == uvMap.end() )
2709 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
2710 // set the second UV
2711 listUV.push_back( *n_uv->second );
2712 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
2713 if ( uvMap2.empty() )
2714 uvMap2 = uvMap; // copy the uvMap contents
2715 uvMap2[ nSeam ] = &listUV.back();
2717 // collect movable nodes linked to ones on seam in nodesNearSeam
2718 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
2719 while ( eIt->more() ) {
2720 const SMDS_MeshElement* e = eIt->next();
2721 int nbUseMap1 = 0, nbUseMap2 = 0;
2722 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2723 int nn = 0, nbn = e->NbNodes();
2724 if(e->IsQuadratic()) nbn = nbn/2;
2725 while ( nn++ < nbn )
2727 const SMDS_MeshNode* n =
2728 static_cast<const SMDS_MeshNode*>( nIt->next() );
2730 setMovableNodes.find( n ) == setMovableNodes.end() )
2732 // add only nodes being closer to uv2 than to uv1
2733 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
2734 0.5 * ( n->Y() + nSeam->Y() ),
2735 0.5 * ( n->Z() + nSeam->Z() ));
2737 getClosestUV( projector, pMid, uv );
2738 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
2739 nodesNearSeam.insert( n );
2745 // for centroidalSmooth all element nodes must
2746 // be on one side of a seam
2747 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
2748 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2750 while ( nn++ < nbn ) {
2751 const SMDS_MeshNode* n =
2752 static_cast<const SMDS_MeshNode*>( nIt->next() );
2753 setMovableNodes.erase( n );
2757 } // loop on nodes on seam
2758 } // loop on edge of a face
2759 } // if ( !face.IsNull() )
2761 if ( setMovableNodes.empty() ) {
2762 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
2763 continue; // goto next face
2771 double maxRatio = -1., maxDisplacement = -1.;
2772 set<const SMDS_MeshNode*>::iterator nodeToMove;
2773 for ( it = 0; it < theNbIterations; it++ ) {
2774 maxDisplacement = 0.;
2775 nodeToMove = setMovableNodes.begin();
2776 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2777 const SMDS_MeshNode* node = (*nodeToMove);
2778 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
2781 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
2782 if ( theSmoothMethod == LAPLACIAN )
2783 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
2785 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
2787 // node displacement
2788 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
2789 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
2790 if ( aDispl > maxDisplacement )
2791 maxDisplacement = aDispl;
2793 // no node movement => exit
2794 //if ( maxDisplacement < 1.e-16 ) {
2795 if ( maxDisplacement < disttol ) {
2796 MESSAGE("-- no node movement --");
2800 // check elements quality
2802 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2803 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2804 const SMDS_MeshElement* elem = (*elemIt);
2805 if ( !elem || elem->GetType() != SMDSAbs_Face )
2807 SMESH::Controls::TSequenceOfXYZ aPoints;
2808 if ( aQualityFunc.GetPoints( elem, aPoints )) {
2809 double aValue = aQualityFunc.GetValue( aPoints );
2810 if ( aValue > maxRatio )
2814 if ( maxRatio <= theTgtAspectRatio ) {
2815 MESSAGE("-- quality achived --");
2818 if (it+1 == theNbIterations) {
2819 MESSAGE("-- Iteration limit exceeded --");
2821 } // smoothing iterations
2823 MESSAGE(" Face id: " << *fId <<
2824 " Nb iterstions: " << it <<
2825 " Displacement: " << maxDisplacement <<
2826 " Aspect Ratio " << maxRatio);
2828 // ---------------------------------------
2829 // new nodes positions are computed,
2830 // record movement in DS and set new UV
2831 // ---------------------------------------
2832 nodeToMove = setMovableNodes.begin();
2833 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
2834 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
2835 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
2836 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
2837 if ( node_uv != uvMap.end() ) {
2838 gp_XY* uv = node_uv->second;
2840 ( SMDS_PositionPtr( new SMDS_FacePosition( *fId, uv->X(), uv->Y() )));
2844 // move medium nodes of quadratic elements
2847 SMESH_MesherHelper helper( *GetMesh() );
2848 if ( !face.IsNull() )
2849 helper.SetSubShape( face );
2850 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
2851 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
2852 const SMDS_QuadraticFaceOfNodes* QF =
2853 dynamic_cast<const SMDS_QuadraticFaceOfNodes*> (*elemIt);
2855 vector<const SMDS_MeshNode*> Ns;
2856 Ns.reserve(QF->NbNodes()+1);
2857 SMDS_NodeIteratorPtr anIter = QF->interlacedNodesIterator();
2858 while ( anIter->more() )
2859 Ns.push_back( anIter->next() );
2860 Ns.push_back( Ns[0] );
2862 for(int i=0; i<QF->NbNodes(); i=i+2) {
2863 if ( !surface.IsNull() ) {
2864 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
2865 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
2866 gp_XY uv = ( uv1 + uv2 ) / 2.;
2867 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
2868 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
2871 x = (Ns[i]->X() + Ns[i+2]->X())/2;
2872 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
2873 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
2875 if( fabs( Ns[i+1]->X() - x ) > disttol ||
2876 fabs( Ns[i+1]->Y() - y ) > disttol ||
2877 fabs( Ns[i+1]->Z() - z ) > disttol ) {
2878 // we have to move i+1 node
2879 aMesh->MoveNode( Ns[i+1], x, y, z );
2886 } // loop on face ids
2890 //=======================================================================
2891 //function : isReverse
2892 //purpose : Return true if normal of prevNodes is not co-directied with
2893 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
2894 // iNotSame is where prevNodes and nextNodes are different
2895 //=======================================================================
2897 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
2898 vector<const SMDS_MeshNode*> nextNodes,
2902 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
2903 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
2905 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
2906 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
2907 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
2908 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
2910 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
2911 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
2912 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
2913 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
2915 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
2917 return (vA ^ vB) * vN < 0.0;
2920 //=======================================================================
2922 * \brief Create elements by sweeping an element
2923 * \param elem - element to sweep
2924 * \param newNodesItVec - nodes generated from each node of the element
2925 * \param newElems - generated elements
2926 * \param nbSteps - number of sweeping steps
2927 * \param srcElements - to append elem for each generated element
2929 //=======================================================================
2931 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
2932 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
2933 list<const SMDS_MeshElement*>& newElems,
2935 SMESH_SequenceOfElemPtr& srcElements)
2937 SMESHDS_Mesh* aMesh = GetMeshDS();
2939 // Loop on elem nodes:
2940 // find new nodes and detect same nodes indices
2941 int nbNodes = elem->NbNodes();
2942 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
2943 vector<const SMDS_MeshNode*> prevNod( nbNodes );
2944 vector<const SMDS_MeshNode*> nextNod( nbNodes );
2945 vector<const SMDS_MeshNode*> midlNod( nbNodes );
2947 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
2948 vector<int> sames(nbNodes);
2949 vector<bool> issimple(nbNodes);
2951 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
2952 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
2953 const SMDS_MeshNode* node = nnIt->first;
2954 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
2955 if ( listNewNodes.empty() ) {
2959 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
2961 itNN[ iNode ] = listNewNodes.begin();
2962 prevNod[ iNode ] = node;
2963 nextNod[ iNode ] = listNewNodes.front();
2964 if( !elem->IsQuadratic() || !issimple[iNode] ) {
2965 if ( prevNod[ iNode ] != nextNod [ iNode ])
2966 iNotSameNode = iNode;
2970 sames[nbSame++] = iNode;
2975 //cout<<" nbSame = "<<nbSame<<endl;
2976 if ( nbSame == nbNodes || nbSame > 2) {
2977 MESSAGE( " Too many same nodes of element " << elem->GetID() );
2978 //INFOS( " Too many same nodes of element " << elem->GetID() );
2982 // if( elem->IsQuadratic() && nbSame>0 ) {
2983 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
2987 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
2988 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
2990 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
2991 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
2992 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
2996 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
2997 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
2998 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
2999 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3001 // check element orientation
3003 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3004 //MESSAGE("Reversed elem " << elem );
3008 std::swap( iBeforeSame, iAfterSame );
3011 // make new elements
3012 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3014 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3015 if(issimple[iNode]) {
3016 nextNod[ iNode ] = *itNN[ iNode ];
3020 if( elem->GetType()==SMDSAbs_Node ) {
3021 // we have to use two nodes
3022 midlNod[ iNode ] = *itNN[ iNode ];
3024 nextNod[ iNode ] = *itNN[ iNode ];
3027 else if(!elem->IsQuadratic() || elem->IsMediumNode(prevNod[iNode]) ) {
3028 // we have to use each second node
3030 nextNod[ iNode ] = *itNN[ iNode ];
3034 // we have to use two nodes
3035 midlNod[ iNode ] = *itNN[ iNode ];
3037 nextNod[ iNode ] = *itNN[ iNode ];
3042 SMDS_MeshElement* aNewElem = 0;
3043 if(!elem->IsPoly()) {
3044 switch ( nbNodes ) {
3048 if ( nbSame == 0 ) {
3050 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3052 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3058 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3059 nextNod[ 1 ], nextNod[ 0 ] );
3061 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3062 nextNod[ iNotSameNode ] );
3066 case 3: { // TRIANGLE or quadratic edge
3067 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3069 if ( nbSame == 0 ) // --- pentahedron
3070 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3071 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3073 else if ( nbSame == 1 ) // --- pyramid
3074 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3075 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3076 nextNod[ iSameNode ]);
3078 else // 2 same nodes: --- tetrahedron
3079 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3080 nextNod[ iNotSameNode ]);
3082 else { // quadratic edge
3083 if(nbSame==0) { // quadratic quadrangle
3084 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3085 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3087 else if(nbSame==1) { // quadratic triangle
3089 return; // medium node on axis
3091 else if(sames[0]==0) {
3092 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3093 nextNod[2], midlNod[1], prevNod[2]);
3095 else { // sames[0]==1
3096 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3097 midlNod[0], nextNod[2], prevNod[2]);
3106 case 4: { // QUADRANGLE
3108 if ( nbSame == 0 ) // --- hexahedron
3109 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3110 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3112 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3113 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3114 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3115 nextNod[ iSameNode ]);
3116 newElems.push_back( aNewElem );
3117 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3118 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3119 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3121 else if ( nbSame == 2 ) { // pentahedron
3122 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3123 // iBeforeSame is same too
3124 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3125 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3126 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3128 // iAfterSame is same too
3129 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3130 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3131 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3135 case 6: { // quadratic triangle
3136 // create pentahedron with 15 nodes
3138 if(i0>0) { // reversed case
3139 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3140 nextNod[0], nextNod[2], nextNod[1],
3141 prevNod[5], prevNod[4], prevNod[3],
3142 nextNod[5], nextNod[4], nextNod[3],
3143 midlNod[0], midlNod[2], midlNod[1]);
3145 else { // not reversed case
3146 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3147 nextNod[0], nextNod[1], nextNod[2],
3148 prevNod[3], prevNod[4], prevNod[5],
3149 nextNod[3], nextNod[4], nextNod[5],
3150 midlNod[0], midlNod[1], midlNod[2]);
3153 else if(nbSame==1) {
3154 // 2d order pyramid of 13 nodes
3155 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3156 // int n12,int n23,int n34,int n41,
3157 // int n15,int n25,int n35,int n45, int ID);
3159 int n1,n4,n41,n15,n45;
3160 if(i0>0) { // reversed case
3161 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3162 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3168 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3169 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3174 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3175 nextNod[n4], prevNod[n4], prevNod[n5],
3176 midlNod[n1], nextNod[n41],
3177 midlNod[n4], prevNod[n41],
3178 prevNod[n15], nextNod[n15],
3179 nextNod[n45], prevNod[n45]);
3181 else if(nbSame==2) {
3182 // 2d order tetrahedron of 10 nodes
3183 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3184 // int n12,int n23,int n31,
3185 // int n14,int n24,int n34, int ID);
3186 int n1 = iNotSameNode;
3187 int n2,n3,n12,n23,n31;
3188 if(i0>0) { // reversed case
3189 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3190 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3196 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3197 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3202 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3203 prevNod[n12], prevNod[n23], prevNod[n31],
3204 midlNod[n1], nextNod[n12], nextNod[n31]);
3208 case 8: { // quadratic quadrangle
3210 // create hexahedron with 20 nodes
3211 if(i0>0) { // reversed case
3212 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3213 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3214 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3215 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3216 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3218 else { // not reversed case
3219 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3220 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3221 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3222 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3223 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3226 else if(nbSame==1) {
3227 // --- pyramid + pentahedron - can not be created since it is needed
3228 // additional middle node ot the center of face
3229 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3232 else if(nbSame==2) {
3233 // 2d order Pentahedron with 15 nodes
3234 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3235 // int n12,int n23,int n31,int n45,int n56,int n64,
3236 // int n14,int n25,int n36, int ID);
3238 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3239 // iBeforeSame is same too
3246 // iAfterSame is same too
3252 int n12,n45,n14,n25;
3253 if(i0>0) { //reversed case
3265 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3266 prevNod[n4], prevNod[n5], nextNod[n5],
3267 prevNod[n12], midlNod[n2], nextNod[n12],
3268 prevNod[n45], midlNod[n5], nextNod[n45],
3269 prevNod[n14], prevNod[n25], nextNod[n25]);
3274 // realized for extrusion only
3275 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3276 //vector<int> quantities (nbNodes + 2);
3278 //quantities[0] = nbNodes; // bottom of prism
3279 //for (int inode = 0; inode < nbNodes; inode++) {
3280 // polyedre_nodes[inode] = prevNod[inode];
3283 //quantities[1] = nbNodes; // top of prism
3284 //for (int inode = 0; inode < nbNodes; inode++) {
3285 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3288 //for (int iface = 0; iface < nbNodes; iface++) {
3289 // quantities[iface + 2] = 4;
3290 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3291 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3292 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3293 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3294 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3296 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3303 // realized for extrusion only
3304 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3305 vector<int> quantities (nbNodes + 2);
3307 quantities[0] = nbNodes; // bottom of prism
3308 for (int inode = 0; inode < nbNodes; inode++) {
3309 polyedre_nodes[inode] = prevNod[inode];
3312 quantities[1] = nbNodes; // top of prism
3313 for (int inode = 0; inode < nbNodes; inode++) {
3314 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3317 for (int iface = 0; iface < nbNodes; iface++) {
3318 quantities[iface + 2] = 4;
3319 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3320 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3321 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3322 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3323 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3325 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3329 newElems.push_back( aNewElem );
3330 myLastCreatedElems.Append(aNewElem);
3331 srcElements.Append( elem );
3334 // set new prev nodes
3335 for ( iNode = 0; iNode < nbNodes; iNode++ )
3336 prevNod[ iNode ] = nextNod[ iNode ];
3341 //=======================================================================
3343 * \brief Create 1D and 2D elements around swept elements
3344 * \param mapNewNodes - source nodes and ones generated from them
3345 * \param newElemsMap - source elements and ones generated from them
3346 * \param elemNewNodesMap - nodes generated from each node of each element
3347 * \param elemSet - all swept elements
3348 * \param nbSteps - number of sweeping steps
3349 * \param srcElements - to append elem for each generated element
3351 //=======================================================================
3353 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3354 TElemOfElemListMap & newElemsMap,
3355 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3356 TIDSortedElemSet& elemSet,
3358 SMESH_SequenceOfElemPtr& srcElements)
3360 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3361 SMESHDS_Mesh* aMesh = GetMeshDS();
3363 // Find nodes belonging to only one initial element - sweep them to get edges.
3365 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3366 for ( ; nList != mapNewNodes.end(); nList++ ) {
3367 const SMDS_MeshNode* node =
3368 static_cast<const SMDS_MeshNode*>( nList->first );
3369 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3370 int nbInitElems = 0;
3371 const SMDS_MeshElement* el = 0;
3372 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3373 while ( eIt->more() && nbInitElems < 2 ) {
3375 SMDSAbs_ElementType type = el->GetType();
3376 if ( type == SMDSAbs_Volume || type < highType ) continue;
3377 if ( type > highType ) {
3381 if ( elemSet.find(el) != elemSet.end() )
3384 if ( nbInitElems < 2 ) {
3385 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3386 if(!NotCreateEdge) {
3387 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3388 list<const SMDS_MeshElement*> newEdges;
3389 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3394 // Make a ceiling for each element ie an equal element of last new nodes.
3395 // Find free links of faces - make edges and sweep them into faces.
3397 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3398 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3399 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3400 const SMDS_MeshElement* elem = itElem->first;
3401 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3403 if ( elem->GetType() == SMDSAbs_Edge ) {
3404 // create a ceiling edge
3405 if (!elem->IsQuadratic()) {
3406 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3407 vecNewNodes[ 1 ]->second.back())) {
3408 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3409 vecNewNodes[ 1 ]->second.back()));
3410 srcElements.Append( myLastCreatedElems.Last() );
3414 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3415 vecNewNodes[ 1 ]->second.back(),
3416 vecNewNodes[ 2 ]->second.back())) {
3417 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3418 vecNewNodes[ 1 ]->second.back(),
3419 vecNewNodes[ 2 ]->second.back()));
3420 srcElements.Append( myLastCreatedElems.Last() );
3424 if ( elem->GetType() != SMDSAbs_Face )
3427 if(itElem->second.size()==0) continue;
3429 bool hasFreeLinks = false;
3431 TIDSortedElemSet avoidSet;
3432 avoidSet.insert( elem );
3434 set<const SMDS_MeshNode*> aFaceLastNodes;
3435 int iNode, nbNodes = vecNewNodes.size();
3436 if(!elem->IsQuadratic()) {
3437 // loop on the face nodes
3438 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3439 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3440 // look for free links of the face
3441 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3442 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3443 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3444 // check if a link is free
3445 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3446 hasFreeLinks = true;
3447 // make an edge and a ceiling for a new edge
3448 if ( !aMesh->FindEdge( n1, n2 )) {
3449 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3450 srcElements.Append( myLastCreatedElems.Last() );
3452 n1 = vecNewNodes[ iNode ]->second.back();
3453 n2 = vecNewNodes[ iNext ]->second.back();
3454 if ( !aMesh->FindEdge( n1, n2 )) {
3455 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3456 srcElements.Append( myLastCreatedElems.Last() );
3461 else { // elem is quadratic face
3462 int nbn = nbNodes/2;
3463 for ( iNode = 0; iNode < nbn; iNode++ ) {
3464 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3465 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3466 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3467 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3468 // check if a link is free
3469 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3470 hasFreeLinks = true;
3471 // make an edge and a ceiling for a new edge
3473 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3474 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3475 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3476 srcElements.Append( myLastCreatedElems.Last() );
3478 n1 = vecNewNodes[ iNode ]->second.back();
3479 n2 = vecNewNodes[ iNext ]->second.back();
3480 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3481 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3482 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3483 srcElements.Append( myLastCreatedElems.Last() );
3487 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3488 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3492 // sweep free links into faces
3494 if ( hasFreeLinks ) {
3495 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3496 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3498 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3499 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3500 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3501 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3503 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3504 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3506 while ( iVol++ < volNb ) v++;
3507 // find indices of free faces of a volume and their source edges
3508 list< int > freeInd;
3509 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3510 SMDS_VolumeTool vTool( *v );
3511 int iF, nbF = vTool.NbFaces();
3512 for ( iF = 0; iF < nbF; iF ++ ) {
3513 if (vTool.IsFreeFace( iF ) &&
3514 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3515 initNodeSet != faceNodeSet) // except an initial face
3517 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3519 freeInd.push_back( iF );
3520 // find source edge of a free face iF
3521 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3522 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3523 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3524 initNodeSet.begin(), initNodeSet.end(),
3525 commonNodes.begin());
3526 if ( (*v)->IsQuadratic() )
3527 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3529 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3531 if ( !srcEdges.back() )
3533 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3534 << iF << " of volume #" << vTool.ID() << endl;
3539 if ( freeInd.empty() )
3542 // create faces for all steps;
3543 // if such a face has been already created by sweep of edge,
3544 // assure that its orientation is OK
3545 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
3547 vTool.SetExternalNormal();
3548 list< int >::iterator ind = freeInd.begin();
3549 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
3550 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
3552 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
3553 int nbn = vTool.NbFaceNodes( *ind );
3555 case 3: { ///// triangle
3556 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
3558 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3559 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3560 aMesh->ChangeElementNodes( f, nodes, nbn );
3563 case 4: { ///// quadrangle
3564 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
3566 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3567 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3568 aMesh->ChangeElementNodes( f, nodes, nbn );
3572 if( (*v)->IsQuadratic() ) {
3573 if(nbn==6) { /////// quadratic triangle
3574 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
3575 nodes[1], nodes[3], nodes[5] );
3577 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3578 nodes[1], nodes[3], nodes[5]));
3580 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3581 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
3582 tmpnodes[0] = nodes[0];
3583 tmpnodes[1] = nodes[2];
3584 tmpnodes[2] = nodes[4];
3585 tmpnodes[3] = nodes[1];
3586 tmpnodes[4] = nodes[3];
3587 tmpnodes[5] = nodes[5];
3588 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3591 else { /////// quadratic quadrangle
3592 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
3593 nodes[1], nodes[3], nodes[5], nodes[7] );
3595 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3596 nodes[1], nodes[3], nodes[5], nodes[7]));
3598 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
3599 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
3600 tmpnodes[0] = nodes[0];
3601 tmpnodes[1] = nodes[2];
3602 tmpnodes[2] = nodes[4];
3603 tmpnodes[3] = nodes[6];
3604 tmpnodes[4] = nodes[1];
3605 tmpnodes[5] = nodes[3];
3606 tmpnodes[6] = nodes[5];
3607 tmpnodes[7] = nodes[7];
3608 aMesh->ChangeElementNodes( f, tmpnodes, nbn );
3612 else { //////// polygon
3613 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3614 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
3616 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3617 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
3618 aMesh->ChangeElementNodes( f, nodes, nbn );
3621 while ( srcElements.Length() < myLastCreatedElems.Length() )
3622 srcElements.Append( *srcEdge );
3624 } // loop on free faces
3626 // go to the next volume
3628 while ( iVol++ < nbVolumesByStep ) v++;
3631 } // sweep free links into faces
3633 // Make a ceiling face with a normal external to a volume
3635 SMDS_VolumeTool lastVol( itElem->second.back() );
3637 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
3639 lastVol.SetExternalNormal();
3640 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
3641 int nbn = lastVol.NbFaceNodes( iF );
3644 if (!hasFreeLinks ||
3645 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
3646 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
3649 if (!hasFreeLinks ||
3650 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
3651 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
3654 if(itElem->second.back()->IsQuadratic()) {
3656 if (!hasFreeLinks ||
3657 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
3658 nodes[1], nodes[3], nodes[5]) ) {
3659 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
3660 nodes[1], nodes[3], nodes[5]));
3664 if (!hasFreeLinks ||
3665 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
3666 nodes[1], nodes[3], nodes[5], nodes[7]) )
3667 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
3668 nodes[1], nodes[3], nodes[5], nodes[7]));
3672 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
3673 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
3674 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
3678 while ( srcElements.Length() < myLastCreatedElems.Length() )
3679 srcElements.Append( myLastCreatedElems.Last() );
3681 } // loop on swept elements
3684 //=======================================================================
3685 //function : RotationSweep
3687 //=======================================================================
3689 SMESH_MeshEditor::PGroupIDs
3690 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
3691 const gp_Ax1& theAxis,
3692 const double theAngle,
3693 const int theNbSteps,
3694 const double theTol,
3695 const bool theMakeGroups,
3696 const bool theMakeWalls)
3698 myLastCreatedElems.Clear();
3699 myLastCreatedNodes.Clear();
3701 // source elements for each generated one
3702 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3704 MESSAGE( "RotationSweep()");
3706 aTrsf.SetRotation( theAxis, theAngle );
3708 aTrsf2.SetRotation( theAxis, theAngle/2. );
3710 gp_Lin aLine( theAxis );
3711 double aSqTol = theTol * theTol;
3713 SMESHDS_Mesh* aMesh = GetMeshDS();
3715 TNodeOfNodeListMap mapNewNodes;
3716 TElemOfVecOfNnlmiMap mapElemNewNodes;
3717 TElemOfElemListMap newElemsMap;
3720 TIDSortedElemSet::iterator itElem;
3721 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3722 const SMDS_MeshElement* elem = *itElem;
3723 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3725 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3726 newNodesItVec.reserve( elem->NbNodes() );
3728 // loop on elem nodes
3729 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3730 while ( itN->more() ) {
3731 // check if a node has been already sweeped
3732 const SMDS_MeshNode* node = cast2Node( itN->next() );
3734 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3736 aXYZ.Coord( coord[0], coord[1], coord[2] );
3737 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3739 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
3740 if ( nIt == mapNewNodes.end() ) {
3741 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3742 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3745 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3747 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3748 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
3749 const SMDS_MeshNode * newNode = node;
3750 for ( int i = 0; i < theNbSteps; i++ ) {
3752 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3754 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3755 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3756 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3757 myLastCreatedNodes.Append(newNode);
3758 srcNodes.Append( node );
3759 listNewNodes.push_back( newNode );
3760 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3761 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3764 aTrsf.Transforms( coord[0], coord[1], coord[2] );
3766 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3767 myLastCreatedNodes.Append(newNode);
3768 srcNodes.Append( node );
3769 listNewNodes.push_back( newNode );
3772 listNewNodes.push_back( newNode );
3773 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3774 listNewNodes.push_back( newNode );
3781 // if current elem is quadratic and current node is not medium
3782 // we have to check - may be it is needed to insert additional nodes
3783 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3784 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
3785 if(listNewNodes.size()==theNbSteps) {
3786 listNewNodes.clear();
3788 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
3790 //aXYZ.Coord( coord[0], coord[1], coord[2] );
3791 const SMDS_MeshNode * newNode = node;
3793 for(int i = 0; i<theNbSteps; i++) {
3794 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3795 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3796 cout<<" 3 AddNode: "<<newNode;
3797 myLastCreatedNodes.Append(newNode);
3798 listNewNodes.push_back( newNode );
3799 srcNodes.Append( node );
3800 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
3801 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3802 cout<<" 4 AddNode: "<<newNode;
3803 myLastCreatedNodes.Append(newNode);
3804 srcNodes.Append( node );
3805 listNewNodes.push_back( newNode );
3809 listNewNodes.push_back( newNode );
3815 newNodesItVec.push_back( nIt );
3817 // make new elements
3818 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
3822 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
3824 PGroupIDs newGroupIDs;
3825 if ( theMakeGroups )
3826 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
3832 //=======================================================================
3833 //function : CreateNode
3835 //=======================================================================
3836 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
3839 const double tolnode,
3840 SMESH_SequenceOfNode& aNodes)
3842 myLastCreatedElems.Clear();
3843 myLastCreatedNodes.Clear();
3846 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
3848 // try to search in sequence of existing nodes
3849 // if aNodes.Length()>0 we 'nave to use given sequence
3850 // else - use all nodes of mesh
3851 if(aNodes.Length()>0) {
3853 for(i=1; i<=aNodes.Length(); i++) {
3854 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
3855 if(P1.Distance(P2)<tolnode)
3856 return aNodes.Value(i);
3860 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
3861 while(itn->more()) {
3862 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
3863 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
3864 if(P1.Distance(P2)<tolnode)
3869 // create new node and return it
3870 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
3871 myLastCreatedNodes.Append(NewNode);
3876 //=======================================================================
3877 //function : ExtrusionSweep
3879 //=======================================================================
3881 SMESH_MeshEditor::PGroupIDs
3882 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3883 const gp_Vec& theStep,
3884 const int theNbSteps,
3885 TElemOfElemListMap& newElemsMap,
3886 const bool theMakeGroups,
3888 const double theTolerance)
3890 ExtrusParam aParams;
3891 aParams.myDir = gp_Dir(theStep);
3892 aParams.myNodes.Clear();
3893 aParams.mySteps = new TColStd_HSequenceOfReal;
3895 for(i=1; i<=theNbSteps; i++)
3896 aParams.mySteps->Append(theStep.Magnitude());
3899 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
3903 //=======================================================================
3904 //function : ExtrusionSweep
3906 //=======================================================================
3908 SMESH_MeshEditor::PGroupIDs
3909 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
3910 ExtrusParam& theParams,
3911 TElemOfElemListMap& newElemsMap,
3912 const bool theMakeGroups,
3914 const double theTolerance)
3916 myLastCreatedElems.Clear();
3917 myLastCreatedNodes.Clear();
3919 // source elements for each generated one
3920 SMESH_SequenceOfElemPtr srcElems, srcNodes;
3922 SMESHDS_Mesh* aMesh = GetMeshDS();
3924 int nbsteps = theParams.mySteps->Length();
3926 TNodeOfNodeListMap mapNewNodes;
3927 //TNodeOfNodeVecMap mapNewNodes;
3928 TElemOfVecOfNnlmiMap mapElemNewNodes;
3929 //TElemOfVecOfMapNodesMap mapElemNewNodes;
3932 TIDSortedElemSet::iterator itElem;
3933 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
3934 // check element type
3935 const SMDS_MeshElement* elem = *itElem;
3936 if ( !elem || elem->GetType() == SMDSAbs_Volume )
3939 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3940 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
3941 newNodesItVec.reserve( elem->NbNodes() );
3943 // loop on elem nodes
3944 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
3945 while ( itN->more() )
3947 // check if a node has been already sweeped
3948 const SMDS_MeshNode* node = cast2Node( itN->next() );
3949 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
3950 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
3951 if ( nIt == mapNewNodes.end() ) {
3952 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
3953 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
3954 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
3955 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
3956 //vecNewNodes.reserve(nbsteps);
3959 double coord[] = { node->X(), node->Y(), node->Z() };
3960 //int nbsteps = theParams.mySteps->Length();
3961 for ( int i = 0; i < nbsteps; i++ ) {
3962 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
3963 // create additional node
3964 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
3965 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
3966 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
3967 if( theFlags & EXTRUSION_FLAG_SEW ) {
3968 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
3969 theTolerance, theParams.myNodes);
3970 listNewNodes.push_back( newNode );
3973 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
3974 myLastCreatedNodes.Append(newNode);
3975 srcNodes.Append( node );
3976 listNewNodes.push_back( newNode );
3979 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
3980 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
3981 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
3982 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
3983 if( theFlags & EXTRUSION_FLAG_SEW ) {
3984 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
3985 theTolerance, theParams.myNodes);
3986 listNewNodes.push_back( newNode );
3987 //vecNewNodes[i]=newNode;
3990 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
3991 myLastCreatedNodes.Append(newNode);
3992 srcNodes.Append( node );
3993 listNewNodes.push_back( newNode );
3994 //vecNewNodes[i]=newNode;
3999 // if current elem is quadratic and current node is not medium
4000 // we have to check - may be it is needed to insert additional nodes
4001 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4002 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4003 if(listNewNodes.size()==nbsteps) {
4004 listNewNodes.clear();
4005 double coord[] = { node->X(), node->Y(), node->Z() };
4006 for ( int i = 0; i < nbsteps; i++ ) {
4007 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4008 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4009 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4010 if( theFlags & EXTRUSION_FLAG_SEW ) {
4011 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4012 theTolerance, theParams.myNodes);
4013 listNewNodes.push_back( newNode );
4016 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4017 myLastCreatedNodes.Append(newNode);
4018 srcNodes.Append( node );
4019 listNewNodes.push_back( newNode );
4021 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4022 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4023 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4024 if( theFlags & EXTRUSION_FLAG_SEW ) {
4025 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4026 theTolerance, theParams.myNodes);
4027 listNewNodes.push_back( newNode );
4030 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4031 myLastCreatedNodes.Append(newNode);
4032 srcNodes.Append( node );
4033 listNewNodes.push_back( newNode );
4039 newNodesItVec.push_back( nIt );
4041 // make new elements
4042 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4045 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4046 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4048 PGroupIDs newGroupIDs;
4049 if ( theMakeGroups )
4050 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4056 //=======================================================================
4057 //class : SMESH_MeshEditor_PathPoint
4058 //purpose : auxiliary class
4059 //=======================================================================
4060 class SMESH_MeshEditor_PathPoint {
4062 SMESH_MeshEditor_PathPoint() {
4063 myPnt.SetCoord(99., 99., 99.);
4064 myTgt.SetCoord(1.,0.,0.);
4068 void SetPnt(const gp_Pnt& aP3D){
4071 void SetTangent(const gp_Dir& aTgt){
4074 void SetAngle(const double& aBeta){
4077 void SetParameter(const double& aPrm){
4080 const gp_Pnt& Pnt()const{
4083 const gp_Dir& Tangent()const{
4086 double Angle()const{
4089 double Parameter()const{
4101 //=======================================================================
4102 //function : ExtrusionAlongTrack
4104 //=======================================================================
4105 SMESH_MeshEditor::Extrusion_Error
4106 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4107 SMESH_subMesh* theTrack,
4108 const SMDS_MeshNode* theN1,
4109 const bool theHasAngles,
4110 list<double>& theAngles,
4111 const bool theLinearVariation,
4112 const bool theHasRefPoint,
4113 const gp_Pnt& theRefPoint,
4114 const bool theMakeGroups)
4116 myLastCreatedElems.Clear();
4117 myLastCreatedNodes.Clear();
4120 std::list<double> aPrms;
4121 TIDSortedElemSet::iterator itElem;
4124 TopoDS_Edge aTrackEdge;
4125 TopoDS_Vertex aV1, aV2;
4127 SMDS_ElemIteratorPtr aItE;
4128 SMDS_NodeIteratorPtr aItN;
4129 SMDSAbs_ElementType aTypeE;
4131 TNodeOfNodeListMap mapNewNodes;
4134 aNbE = theElements.size();
4137 return EXTR_NO_ELEMENTS;
4139 // 1.1 Track Pattern
4142 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4144 aItE = pSubMeshDS->GetElements();
4145 while ( aItE->more() ) {
4146 const SMDS_MeshElement* pE = aItE->next();
4147 aTypeE = pE->GetType();
4148 // Pattern must contain links only
4149 if ( aTypeE != SMDSAbs_Edge )
4150 return EXTR_PATH_NOT_EDGE;
4153 list<SMESH_MeshEditor_PathPoint> fullList;
4155 const TopoDS_Shape& aS = theTrack->GetSubShape();
4156 // Sub shape for the Pattern must be an Edge or Wire
4157 if( aS.ShapeType() == TopAbs_EDGE ) {
4158 aTrackEdge = TopoDS::Edge( aS );
4159 // the Edge must not be degenerated
4160 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4161 return EXTR_BAD_PATH_SHAPE;
4162 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4163 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4164 const SMDS_MeshNode* aN1 = aItN->next();
4165 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4166 const SMDS_MeshNode* aN2 = aItN->next();
4167 // starting node must be aN1 or aN2
4168 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4169 return EXTR_BAD_STARTING_NODE;
4170 aItN = pSubMeshDS->GetNodes();
4171 while ( aItN->more() ) {
4172 const SMDS_MeshNode* pNode = aItN->next();
4173 const SMDS_EdgePosition* pEPos =
4174 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4175 double aT = pEPos->GetUParameter();
4176 aPrms.push_back( aT );
4178 //Extrusion_Error err =
4179 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4181 else if( aS.ShapeType() == TopAbs_WIRE ) {
4182 list< SMESH_subMesh* > LSM;
4183 TopTools_SequenceOfShape Edges;
4184 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4185 while(itSM->more()) {
4186 SMESH_subMesh* SM = itSM->next();
4188 const TopoDS_Shape& aS = SM->GetSubShape();
4191 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4192 int startNid = theN1->GetID();
4193 TColStd_MapOfInteger UsedNums;
4194 int NbEdges = Edges.Length();
4196 for(; i<=NbEdges; i++) {
4198 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4199 for(; itLSM!=LSM.end(); itLSM++) {
4201 if(UsedNums.Contains(k)) continue;
4202 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4203 SMESH_subMesh* locTrack = *itLSM;
4204 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4205 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4206 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4207 const SMDS_MeshNode* aN1 = aItN->next();
4208 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4209 const SMDS_MeshNode* aN2 = aItN->next();
4210 // starting node must be aN1 or aN2
4211 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4212 // 2. Collect parameters on the track edge
4214 aItN = locMeshDS->GetNodes();
4215 while ( aItN->more() ) {
4216 const SMDS_MeshNode* pNode = aItN->next();
4217 const SMDS_EdgePosition* pEPos =
4218 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4219 double aT = pEPos->GetUParameter();
4220 aPrms.push_back( aT );
4222 list<SMESH_MeshEditor_PathPoint> LPP;
4223 //Extrusion_Error err =
4224 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4225 LLPPs.push_back(LPP);
4227 // update startN for search following egde
4228 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4229 else startNid = aN1->GetID();
4233 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4234 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4235 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4236 for(; itPP!=firstList.end(); itPP++) {
4237 fullList.push_back( *itPP );
4239 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4240 fullList.pop_back();
4242 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4243 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4244 itPP = currList.begin();
4245 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4246 gp_Dir D1 = PP1.Tangent();
4247 gp_Dir D2 = PP2.Tangent();
4248 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4249 (D1.Z()+D2.Z())/2 ) );
4250 PP1.SetTangent(Dnew);
4251 fullList.push_back(PP1);
4253 for(; itPP!=firstList.end(); itPP++) {
4254 fullList.push_back( *itPP );
4256 PP1 = fullList.back();
4257 fullList.pop_back();
4259 // if wire not closed
4260 fullList.push_back(PP1);
4264 return EXTR_BAD_PATH_SHAPE;
4267 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4268 theHasRefPoint, theRefPoint, theMakeGroups);
4272 //=======================================================================
4273 //function : ExtrusionAlongTrack
4275 //=======================================================================
4276 SMESH_MeshEditor::Extrusion_Error
4277 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4278 SMESH_Mesh* theTrack,
4279 const SMDS_MeshNode* theN1,
4280 const bool theHasAngles,
4281 list<double>& theAngles,
4282 const bool theLinearVariation,
4283 const bool theHasRefPoint,
4284 const gp_Pnt& theRefPoint,
4285 const bool theMakeGroups)
4287 myLastCreatedElems.Clear();
4288 myLastCreatedNodes.Clear();
4291 std::list<double> aPrms;
4292 TIDSortedElemSet::iterator itElem;
4295 TopoDS_Edge aTrackEdge;
4296 TopoDS_Vertex aV1, aV2;
4298 SMDS_ElemIteratorPtr aItE;
4299 SMDS_NodeIteratorPtr aItN;
4300 SMDSAbs_ElementType aTypeE;
4302 TNodeOfNodeListMap mapNewNodes;
4305 aNbE = theElements.size();
4308 return EXTR_NO_ELEMENTS;
4310 // 1.1 Track Pattern
4313 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4315 aItE = pMeshDS->elementsIterator();
4316 while ( aItE->more() ) {
4317 const SMDS_MeshElement* pE = aItE->next();
4318 aTypeE = pE->GetType();
4319 // Pattern must contain links only
4320 if ( aTypeE != SMDSAbs_Edge )
4321 return EXTR_PATH_NOT_EDGE;
4324 list<SMESH_MeshEditor_PathPoint> fullList;
4326 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4327 // Sub shape for the Pattern must be an Edge or Wire
4328 if( aS.ShapeType() == TopAbs_EDGE ) {
4329 aTrackEdge = TopoDS::Edge( aS );
4330 // the Edge must not be degenerated
4331 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4332 return EXTR_BAD_PATH_SHAPE;
4333 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4334 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4335 const SMDS_MeshNode* aN1 = aItN->next();
4336 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4337 const SMDS_MeshNode* aN2 = aItN->next();
4338 // starting node must be aN1 or aN2
4339 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4340 return EXTR_BAD_STARTING_NODE;
4341 aItN = pMeshDS->nodesIterator();
4342 while ( aItN->more() ) {
4343 const SMDS_MeshNode* pNode = aItN->next();
4344 if( pNode==aN1 || pNode==aN2 ) continue;
4345 const SMDS_EdgePosition* pEPos =
4346 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4347 double aT = pEPos->GetUParameter();
4348 aPrms.push_back( aT );
4350 //Extrusion_Error err =
4351 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4353 else if( aS.ShapeType() == TopAbs_WIRE ) {
4354 list< SMESH_subMesh* > LSM;
4355 TopTools_SequenceOfShape Edges;
4356 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4357 for(; eExp.More(); eExp.Next()) {
4358 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4359 if( BRep_Tool::Degenerated(E) ) continue;
4360 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4366 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4367 int startNid = theN1->GetID();
4368 TColStd_MapOfInteger UsedNums;
4369 int NbEdges = Edges.Length();
4371 for(; i<=NbEdges; i++) {
4373 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4374 for(; itLSM!=LSM.end(); itLSM++) {
4376 if(UsedNums.Contains(k)) continue;
4377 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4378 SMESH_subMesh* locTrack = *itLSM;
4379 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4380 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4381 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4382 const SMDS_MeshNode* aN1 = aItN->next();
4383 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4384 const SMDS_MeshNode* aN2 = aItN->next();
4385 // starting node must be aN1 or aN2
4386 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4387 // 2. Collect parameters on the track edge
4389 aItN = locMeshDS->GetNodes();
4390 while ( aItN->more() ) {
4391 const SMDS_MeshNode* pNode = aItN->next();
4392 const SMDS_EdgePosition* pEPos =
4393 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition().get() );
4394 double aT = pEPos->GetUParameter();
4395 aPrms.push_back( aT );
4397 list<SMESH_MeshEditor_PathPoint> LPP;
4398 //Extrusion_Error err =
4399 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4400 LLPPs.push_back(LPP);
4402 // update startN for search following egde
4403 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4404 else startNid = aN1->GetID();
4408 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4409 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4410 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4411 for(; itPP!=firstList.end(); itPP++) {
4412 fullList.push_back( *itPP );
4414 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4415 fullList.pop_back();
4417 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4418 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4419 itPP = currList.begin();
4420 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4421 gp_Pnt P1 = PP1.Pnt();
4422 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4423 gp_Pnt P2 = PP2.Pnt();
4424 gp_Dir D1 = PP1.Tangent();
4425 gp_Dir D2 = PP2.Tangent();
4426 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4427 (D1.Z()+D2.Z())/2 ) );
4428 PP1.SetTangent(Dnew);
4429 fullList.push_back(PP1);
4431 for(; itPP!=currList.end(); itPP++) {
4432 fullList.push_back( *itPP );
4434 PP1 = fullList.back();
4435 fullList.pop_back();
4437 // if wire not closed
4438 fullList.push_back(PP1);
4442 return EXTR_BAD_PATH_SHAPE;
4445 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4446 theHasRefPoint, theRefPoint, theMakeGroups);
4450 //=======================================================================
4451 //function : MakeEdgePathPoints
4452 //purpose : auxilary for ExtrusionAlongTrack
4453 //=======================================================================
4454 SMESH_MeshEditor::Extrusion_Error
4455 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4456 const TopoDS_Edge& aTrackEdge,
4458 list<SMESH_MeshEditor_PathPoint>& LPP)
4460 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4462 aTolVec2=aTolVec*aTolVec;
4464 TopoDS_Vertex aV1, aV2;
4465 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4466 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4467 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4468 // 2. Collect parameters on the track edge
4469 aPrms.push_front( aT1 );
4470 aPrms.push_back( aT2 );
4473 if( FirstIsStart ) {
4484 SMESH_MeshEditor_PathPoint aPP;
4485 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4486 std::list<double>::iterator aItD = aPrms.begin();
4487 for(; aItD != aPrms.end(); ++aItD) {
4491 aC3D->D1( aT, aP3D, aVec );
4492 aL2 = aVec.SquareMagnitude();
4493 if ( aL2 < aTolVec2 )
4494 return EXTR_CANT_GET_TANGENT;
4495 gp_Dir aTgt( aVec );
4497 aPP.SetTangent( aTgt );
4498 aPP.SetParameter( aT );
4505 //=======================================================================
4506 //function : MakeExtrElements
4507 //purpose : auxilary for ExtrusionAlongTrack
4508 //=======================================================================
4509 SMESH_MeshEditor::Extrusion_Error
4510 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4511 list<SMESH_MeshEditor_PathPoint>& fullList,
4512 const bool theHasAngles,
4513 list<double>& theAngles,
4514 const bool theLinearVariation,
4515 const bool theHasRefPoint,
4516 const gp_Pnt& theRefPoint,
4517 const bool theMakeGroups)
4519 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4520 int aNbTP = fullList.size();
4521 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4523 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4524 LinearAngleVariation(aNbTP-1, theAngles);
4526 vector<double> aAngles( aNbTP );
4528 for(; j<aNbTP; ++j) {
4531 if ( theHasAngles ) {
4533 std::list<double>::iterator aItD = theAngles.begin();
4534 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
4536 aAngles[j] = anAngle;
4539 // fill vector of path points with angles
4540 //aPPs.resize(fullList.size());
4542 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
4543 for(; itPP!=fullList.end(); itPP++) {
4545 SMESH_MeshEditor_PathPoint PP = *itPP;
4546 PP.SetAngle(aAngles[j]);
4550 TNodeOfNodeListMap mapNewNodes;
4551 TElemOfVecOfNnlmiMap mapElemNewNodes;
4552 TElemOfElemListMap newElemsMap;
4553 TIDSortedElemSet::iterator itElem;
4556 SMDSAbs_ElementType aTypeE;
4557 // source elements for each generated one
4558 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4560 // 3. Center of rotation aV0
4561 gp_Pnt aV0 = theRefPoint;
4563 if ( !theHasRefPoint ) {
4565 aGC.SetCoord( 0.,0.,0. );
4567 itElem = theElements.begin();
4568 for ( ; itElem != theElements.end(); itElem++ ) {
4569 const SMDS_MeshElement* elem = *itElem;
4571 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4572 while ( itN->more() ) {
4573 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
4578 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
4579 list<const SMDS_MeshNode*> aLNx;
4580 mapNewNodes[node] = aLNx;
4582 gp_XYZ aXYZ( aX, aY, aZ );
4590 } // if (!theHasRefPoint) {
4591 mapNewNodes.clear();
4593 // 4. Processing the elements
4594 SMESHDS_Mesh* aMesh = GetMeshDS();
4596 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
4597 // check element type
4598 const SMDS_MeshElement* elem = *itElem;
4599 aTypeE = elem->GetType();
4600 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
4603 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4604 newNodesItVec.reserve( elem->NbNodes() );
4606 // loop on elem nodes
4608 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4609 while ( itN->more() )
4612 // check if a node has been already processed
4613 const SMDS_MeshNode* node =
4614 static_cast<const SMDS_MeshNode*>( itN->next() );
4615 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4616 if ( nIt == mapNewNodes.end() ) {
4617 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4618 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4621 aX = node->X(); aY = node->Y(); aZ = node->Z();
4623 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
4624 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
4625 gp_Ax1 anAx1, anAxT1T0;
4626 gp_Dir aDT1x, aDT0x, aDT1T0;
4631 aPN0.SetCoord(aX, aY, aZ);
4633 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
4635 aDT0x= aPP0.Tangent();
4636 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
4638 for ( j = 1; j < aNbTP; ++j ) {
4639 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
4641 aDT1x = aPP1.Tangent();
4642 aAngle1x = aPP1.Angle();
4644 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
4646 gp_Vec aV01x( aP0x, aP1x );
4647 aTrsf.SetTranslation( aV01x );
4650 aV1x = aV0x.Transformed( aTrsf );
4651 aPN1 = aPN0.Transformed( aTrsf );
4653 // rotation 1 [ T1,T0 ]
4654 aAngleT1T0=-aDT1x.Angle( aDT0x );
4655 if (fabs(aAngleT1T0) > aTolAng) {
4657 anAxT1T0.SetLocation( aV1x );
4658 anAxT1T0.SetDirection( aDT1T0 );
4659 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
4661 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
4665 if ( theHasAngles ) {
4666 anAx1.SetLocation( aV1x );
4667 anAx1.SetDirection( aDT1x );
4668 aTrsfRot.SetRotation( anAx1, aAngle1x );
4670 aPN1 = aPN1.Transformed( aTrsfRot );
4674 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4675 // create additional node
4676 double x = ( aPN1.X() + aPN0.X() )/2.;
4677 double y = ( aPN1.Y() + aPN0.Y() )/2.;
4678 double z = ( aPN1.Z() + aPN0.Z() )/2.;
4679 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
4680 myLastCreatedNodes.Append(newNode);
4681 srcNodes.Append( node );
4682 listNewNodes.push_back( newNode );
4687 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
4688 myLastCreatedNodes.Append(newNode);
4689 srcNodes.Append( node );
4690 listNewNodes.push_back( newNode );
4700 // if current elem is quadratic and current node is not medium
4701 // we have to check - may be it is needed to insert additional nodes
4702 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4703 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4704 if(listNewNodes.size()==aNbTP-1) {
4705 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
4706 gp_XYZ P(node->X(), node->Y(), node->Z());
4707 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
4709 for(i=0; i<aNbTP-1; i++) {
4710 const SMDS_MeshNode* N = *it;
4711 double x = ( N->X() + P.X() )/2.;
4712 double y = ( N->Y() + P.Y() )/2.;
4713 double z = ( N->Z() + P.Z() )/2.;
4714 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
4715 srcNodes.Append( node );
4716 myLastCreatedNodes.Append(newN);
4719 P = gp_XYZ(N->X(),N->Y(),N->Z());
4721 listNewNodes.clear();
4722 for(i=0; i<2*(aNbTP-1); i++) {
4723 listNewNodes.push_back(aNodes[i]);
4729 newNodesItVec.push_back( nIt );
4731 // make new elements
4732 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
4733 // newNodesItVec[0]->second.size(), myLastCreatedElems );
4734 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
4737 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
4739 if ( theMakeGroups )
4740 generateGroups( srcNodes, srcElems, "extruded");
4746 //=======================================================================
4747 //function : LinearAngleVariation
4748 //purpose : auxilary for ExtrusionAlongTrack
4749 //=======================================================================
4750 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
4751 list<double>& Angles)
4753 int nbAngles = Angles.size();
4754 if( nbSteps > nbAngles ) {
4755 vector<double> theAngles(nbAngles);
4756 list<double>::iterator it = Angles.begin();
4758 for(; it!=Angles.end(); it++) {
4760 theAngles[i] = (*it);
4763 double rAn2St = double( nbAngles ) / double( nbSteps );
4764 double angPrev = 0, angle;
4765 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
4766 double angCur = rAn2St * ( iSt+1 );
4767 double angCurFloor = floor( angCur );
4768 double angPrevFloor = floor( angPrev );
4769 if ( angPrevFloor == angCurFloor )
4770 angle = rAn2St * theAngles[ int( angCurFloor ) ];
4772 int iP = int( angPrevFloor );
4773 double angPrevCeil = ceil(angPrev);
4774 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
4776 int iC = int( angCurFloor );
4777 if ( iC < nbAngles )
4778 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
4780 iP = int( angPrevCeil );
4782 angle += theAngles[ iC ];
4784 res.push_back(angle);
4789 for(; it!=res.end(); it++)
4790 Angles.push_back( *it );
4795 //=======================================================================
4796 //function : Transform
4798 //=======================================================================
4800 SMESH_MeshEditor::PGroupIDs
4801 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
4802 const gp_Trsf& theTrsf,
4804 const bool theMakeGroups,
4805 SMESH_Mesh* theTargetMesh)
4807 myLastCreatedElems.Clear();
4808 myLastCreatedNodes.Clear();
4810 bool needReverse = false;
4811 string groupPostfix;
4812 switch ( theTrsf.Form() ) {
4817 groupPostfix = "mirrored";
4820 groupPostfix = "rotated";
4822 case gp_Translation:
4823 groupPostfix = "translated";
4826 groupPostfix = "scaled";
4829 needReverse = false;
4830 groupPostfix = "transformed";
4833 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
4834 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
4835 SMESHDS_Mesh* aMesh = GetMeshDS();
4838 // map old node to new one
4839 TNodeNodeMap nodeMap;
4841 // elements sharing moved nodes; those of them which have all
4842 // nodes mirrored but are not in theElems are to be reversed
4843 TIDSortedElemSet inverseElemSet;
4845 // source elements for each generated one
4846 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4849 TIDSortedElemSet::iterator itElem;
4850 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4851 const SMDS_MeshElement* elem = *itElem;
4855 // loop on elem nodes
4856 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4857 while ( itN->more() ) {
4859 // check if a node has been already transformed
4860 const SMDS_MeshNode* node = cast2Node( itN->next() );
4861 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
4862 nodeMap.insert( make_pair ( node, node ));
4863 if ( !n2n_isnew.second )
4867 coord[0] = node->X();
4868 coord[1] = node->Y();
4869 coord[2] = node->Z();
4870 theTrsf.Transforms( coord[0], coord[1], coord[2] );
4871 if ( theTargetMesh ) {
4872 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
4873 n2n_isnew.first->second = newNode;
4874 myLastCreatedNodes.Append(newNode);
4875 srcNodes.Append( node );
4877 else if ( theCopy ) {
4878 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4879 n2n_isnew.first->second = newNode;
4880 myLastCreatedNodes.Append(newNode);
4881 srcNodes.Append( node );
4884 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
4885 // node position on shape becomes invalid
4886 const_cast< SMDS_MeshNode* > ( node )->SetPosition
4887 ( SMDS_SpacePosition::originSpacePosition() );
4890 // keep inverse elements
4891 if ( !theCopy && !theTargetMesh && needReverse ) {
4892 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
4893 while ( invElemIt->more() ) {
4894 const SMDS_MeshElement* iel = invElemIt->next();
4895 inverseElemSet.insert( iel );
4901 // either create new elements or reverse mirrored ones
4902 if ( !theCopy && !needReverse && !theTargetMesh )
4905 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
4906 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
4907 theElems.insert( *invElemIt );
4909 // replicate or reverse elements
4912 REV_TETRA = 0, // = nbNodes - 4
4913 REV_PYRAMID = 1, // = nbNodes - 4
4914 REV_PENTA = 2, // = nbNodes - 4
4916 REV_HEXA = 4, // = nbNodes - 4
4920 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
4921 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
4922 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
4923 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
4924 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
4925 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
4928 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
4930 const SMDS_MeshElement* elem = *itElem;
4931 if ( !elem || elem->GetType() == SMDSAbs_Node )
4934 int nbNodes = elem->NbNodes();
4935 int elemType = elem->GetType();
4937 if (elem->IsPoly()) {
4938 // Polygon or Polyhedral Volume
4939 switch ( elemType ) {
4942 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
4944 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4945 while (itN->more()) {
4946 const SMDS_MeshNode* node =
4947 static_cast<const SMDS_MeshNode*>(itN->next());
4948 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4949 if (nodeMapIt == nodeMap.end())
4950 break; // not all nodes transformed
4952 // reverse mirrored faces and volumes
4953 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
4955 poly_nodes[iNode] = (*nodeMapIt).second;
4959 if ( iNode != nbNodes )
4960 continue; // not all nodes transformed
4962 if ( theTargetMesh ) {
4963 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
4964 srcElems.Append( elem );
4966 else if ( theCopy ) {
4967 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
4968 srcElems.Append( elem );
4971 aMesh->ChangePolygonNodes(elem, poly_nodes);
4975 case SMDSAbs_Volume:
4977 // ATTENTION: Reversing is not yet done!!!
4978 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
4979 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
4981 MESSAGE("Warning: bad volumic element");
4985 vector<const SMDS_MeshNode*> poly_nodes;
4986 vector<int> quantities;
4988 bool allTransformed = true;
4989 int nbFaces = aPolyedre->NbFaces();
4990 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
4991 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
4992 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
4993 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
4994 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
4995 if (nodeMapIt == nodeMap.end()) {
4996 allTransformed = false; // not all nodes transformed
4998 poly_nodes.push_back((*nodeMapIt).second);
5001 quantities.push_back(nbFaceNodes);
5003 if ( !allTransformed )
5004 continue; // not all nodes transformed
5006 if ( theTargetMesh ) {
5007 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5008 srcElems.Append( elem );
5010 else if ( theCopy ) {
5011 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5012 srcElems.Append( elem );
5015 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5025 int* i = index[ FORWARD ];
5026 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5027 if ( elemType == SMDSAbs_Face )
5028 i = index[ REV_FACE ];
5030 i = index[ nbNodes - 4 ];
5032 if(elem->IsQuadratic()) {
5033 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5036 if(nbNodes==3) { // quadratic edge
5037 static int anIds[] = {1,0,2};
5040 else if(nbNodes==6) { // quadratic triangle
5041 static int anIds[] = {0,2,1,5,4,3};
5044 else if(nbNodes==8) { // quadratic quadrangle
5045 static int anIds[] = {0,3,2,1,7,6,5,4};
5048 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5049 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5052 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5053 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5056 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5057 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5060 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5061 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5067 // find transformed nodes
5068 vector<const SMDS_MeshNode*> nodes(nbNodes);
5070 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5071 while ( itN->more() ) {
5072 const SMDS_MeshNode* node =
5073 static_cast<const SMDS_MeshNode*>( itN->next() );
5074 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5075 if ( nodeMapIt == nodeMap.end() )
5076 break; // not all nodes transformed
5077 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5079 if ( iNode != nbNodes )
5080 continue; // not all nodes transformed
5082 if ( theTargetMesh ) {
5083 if ( SMDS_MeshElement* copy =
5084 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5085 myLastCreatedElems.Append( copy );
5086 srcElems.Append( elem );
5089 else if ( theCopy ) {
5090 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5091 myLastCreatedElems.Append( copy );
5092 srcElems.Append( elem );
5096 // reverse element as it was reversed by transformation
5098 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5102 PGroupIDs newGroupIDs;
5104 if ( theMakeGroups && theCopy ||
5105 theMakeGroups && theTargetMesh )
5106 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5112 //=======================================================================
5115 //=======================================================================
5117 SMESH_MeshEditor::PGroupIDs
5118 SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5119 const gp_Pnt& thePoint,
5120 const std::list<double>& theScaleFact,
5122 const bool theMakeGroups,
5123 SMESH_Mesh* theTargetMesh)
5125 myLastCreatedElems.Clear();
5126 myLastCreatedNodes.Clear();
5128 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5129 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5130 SMESHDS_Mesh* aMesh = GetMeshDS();
5132 double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5133 std::list<double>::const_iterator itS = theScaleFact.begin();
5135 if(theScaleFact.size()==1) {
5139 if(theScaleFact.size()==2) {
5144 if(theScaleFact.size()>2) {
5151 // map old node to new one
5152 TNodeNodeMap nodeMap;
5154 // elements sharing moved nodes; those of them which have all
5155 // nodes mirrored but are not in theElems are to be reversed
5156 TIDSortedElemSet inverseElemSet;
5158 // source elements for each generated one
5159 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5162 TIDSortedElemSet::iterator itElem;
5163 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5164 const SMDS_MeshElement* elem = *itElem;
5168 // loop on elem nodes
5169 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5170 while ( itN->more() ) {
5172 // check if a node has been already transformed
5173 const SMDS_MeshNode* node = cast2Node( itN->next() );
5174 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5175 nodeMap.insert( make_pair ( node, node ));
5176 if ( !n2n_isnew.second )
5180 //coord[0] = node->X();
5181 //coord[1] = node->Y();
5182 //coord[2] = node->Z();
5183 //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5184 double dx = (node->X() - thePoint.X()) * scaleX;
5185 double dy = (node->Y() - thePoint.Y()) * scaleY;
5186 double dz = (node->Z() - thePoint.Z()) * scaleZ;
5187 if ( theTargetMesh ) {
5188 //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5189 const SMDS_MeshNode * newNode =
5190 aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5191 n2n_isnew.first->second = newNode;
5192 myLastCreatedNodes.Append(newNode);
5193 srcNodes.Append( node );
5195 else if ( theCopy ) {
5196 //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5197 const SMDS_MeshNode * newNode =
5198 aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5199 n2n_isnew.first->second = newNode;
5200 myLastCreatedNodes.Append(newNode);
5201 srcNodes.Append( node );
5204 //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5205 aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5206 // node position on shape becomes invalid
5207 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5208 ( SMDS_SpacePosition::originSpacePosition() );
5211 // keep inverse elements
5212 //if ( !theCopy && !theTargetMesh && needReverse ) {
5213 // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5214 // while ( invElemIt->more() ) {
5215 // const SMDS_MeshElement* iel = invElemIt->next();
5216 // inverseElemSet.insert( iel );
5222 // either create new elements or reverse mirrored ones
5223 //if ( !theCopy && !needReverse && !theTargetMesh )
5224 if ( !theCopy && !theTargetMesh )
5227 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5228 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5229 theElems.insert( *invElemIt );
5231 // replicate or reverse elements
5234 REV_TETRA = 0, // = nbNodes - 4
5235 REV_PYRAMID = 1, // = nbNodes - 4
5236 REV_PENTA = 2, // = nbNodes - 4
5238 REV_HEXA = 4, // = nbNodes - 4
5242 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5243 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5244 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5245 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5246 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5247 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5250 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5252 const SMDS_MeshElement* elem = *itElem;
5253 if ( !elem || elem->GetType() == SMDSAbs_Node )
5256 int nbNodes = elem->NbNodes();
5257 int elemType = elem->GetType();
5259 if (elem->IsPoly()) {
5260 // Polygon or Polyhedral Volume
5261 switch ( elemType ) {
5264 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5266 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5267 while (itN->more()) {
5268 const SMDS_MeshNode* node =
5269 static_cast<const SMDS_MeshNode*>(itN->next());
5270 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5271 if (nodeMapIt == nodeMap.end())
5272 break; // not all nodes transformed
5273 //if (needReverse) {
5274 // // reverse mirrored faces and volumes
5275 // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5277 poly_nodes[iNode] = (*nodeMapIt).second;
5281 if ( iNode != nbNodes )
5282 continue; // not all nodes transformed
5284 if ( theTargetMesh ) {
5285 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5286 srcElems.Append( elem );
5288 else if ( theCopy ) {
5289 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5290 srcElems.Append( elem );
5293 aMesh->ChangePolygonNodes(elem, poly_nodes);
5297 case SMDSAbs_Volume:
5299 // ATTENTION: Reversing is not yet done!!!
5300 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
5301 dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
5303 MESSAGE("Warning: bad volumic element");
5307 vector<const SMDS_MeshNode*> poly_nodes;
5308 vector<int> quantities;
5310 bool allTransformed = true;
5311 int nbFaces = aPolyedre->NbFaces();
5312 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5313 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5314 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5315 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5316 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5317 if (nodeMapIt == nodeMap.end()) {
5318 allTransformed = false; // not all nodes transformed
5320 poly_nodes.push_back((*nodeMapIt).second);
5323 quantities.push_back(nbFaceNodes);
5325 if ( !allTransformed )
5326 continue; // not all nodes transformed
5328 if ( theTargetMesh ) {
5329 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5330 srcElems.Append( elem );
5332 else if ( theCopy ) {
5333 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5334 srcElems.Append( elem );
5337 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5347 int* i = index[ FORWARD ];
5348 //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5349 // if ( elemType == SMDSAbs_Face )
5350 // i = index[ REV_FACE ];
5352 // i = index[ nbNodes - 4 ];
5354 if(elem->IsQuadratic()) {
5355 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5358 // if(nbNodes==3) { // quadratic edge
5359 // static int anIds[] = {1,0,2};
5362 // else if(nbNodes==6) { // quadratic triangle
5363 // static int anIds[] = {0,2,1,5,4,3};
5366 // else if(nbNodes==8) { // quadratic quadrangle
5367 // static int anIds[] = {0,3,2,1,7,6,5,4};
5370 // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5371 // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5374 // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5375 // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5378 // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5379 // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5382 // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5383 // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5389 // find transformed nodes
5390 vector<const SMDS_MeshNode*> nodes(nbNodes);
5392 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5393 while ( itN->more() ) {
5394 const SMDS_MeshNode* node =
5395 static_cast<const SMDS_MeshNode*>( itN->next() );
5396 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5397 if ( nodeMapIt == nodeMap.end() )
5398 break; // not all nodes transformed
5399 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5401 if ( iNode != nbNodes )
5402 continue; // not all nodes transformed
5404 if ( theTargetMesh ) {
5405 if ( SMDS_MeshElement* copy =
5406 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5407 myLastCreatedElems.Append( copy );
5408 srcElems.Append( elem );
5411 else if ( theCopy ) {
5412 if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5413 myLastCreatedElems.Append( copy );
5414 srcElems.Append( elem );
5418 // reverse element as it was reversed by transformation
5420 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5424 PGroupIDs newGroupIDs;
5426 if ( theMakeGroups && theCopy ||
5427 theMakeGroups && theTargetMesh ) {
5428 string groupPostfix = "scaled";
5429 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5436 //=======================================================================
5438 * \brief Create groups of elements made during transformation
5439 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5440 * \param elemGens - elements making corresponding myLastCreatedElems
5441 * \param postfix - to append to names of new groups
5443 //=======================================================================
5445 SMESH_MeshEditor::PGroupIDs
5446 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5447 const SMESH_SequenceOfElemPtr& elemGens,
5448 const std::string& postfix,
5449 SMESH_Mesh* targetMesh)
5451 PGroupIDs newGroupIDs( new list<int> );
5452 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5454 // Sort existing groups by types and collect their names
5456 // to store an old group and a generated new one
5457 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5458 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5460 set< string > groupNames;
5462 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5463 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5464 while ( groupIt->more() ) {
5465 SMESH_Group * group = groupIt->next();
5466 if ( !group ) continue;
5467 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5468 if ( !groupDS || groupDS->IsEmpty() ) continue;
5469 groupNames.insert( group->GetName() );
5470 groupDS->SetStoreName( group->GetName() );
5471 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5476 // loop on nodes and elements
5477 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5479 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5480 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5481 if ( gens.Length() != elems.Length() )
5482 throw SALOME_Exception(LOCALIZED("invalid args"));
5484 // loop on created elements
5485 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5487 const SMDS_MeshElement* sourceElem = gens( iElem );
5488 if ( !sourceElem ) {
5489 MESSAGE("generateGroups(): NULL source element");
5492 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
5493 if ( groupsOldNew.empty() ) {
5494 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5495 ++iElem; // skip all elements made by sourceElem
5498 // collect all elements made by sourceElem
5499 list< const SMDS_MeshElement* > resultElems;
5500 if ( const SMDS_MeshElement* resElem = elems( iElem ))
5501 if ( resElem != sourceElem )
5502 resultElems.push_back( resElem );
5503 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
5504 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
5505 if ( resElem != sourceElem )
5506 resultElems.push_back( resElem );
5507 // do not generate element groups from node ones
5508 if ( sourceElem->GetType() == SMDSAbs_Node &&
5509 elems( iElem )->GetType() != SMDSAbs_Node )
5512 // add resultElems to groups made by ones the sourceElem belongs to
5513 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
5514 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
5516 SMESHDS_GroupBase* oldGroup = gOldNew->first;
5517 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
5519 SMDS_MeshGroup* & newGroup = gOldNew->second;
5520 if ( !newGroup )// create a new group
5523 string name = oldGroup->GetStoreName();
5524 if ( !targetMesh ) {
5528 while ( !groupNames.insert( name ).second ) // name exists
5534 TCollection_AsciiString nbStr(nb+1);
5535 name.resize( name.rfind('_')+1 );
5536 name += nbStr.ToCString();
5543 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
5545 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
5546 newGroup = & groupDS->SMDSGroup();
5547 newGroupIDs->push_back( id );
5550 // fill in a new group
5551 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
5552 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
5553 newGroup->Add( *resElemIt );
5556 } // loop on created elements
5557 }// loop on nodes and elements
5562 //================================================================================
5564 * \brief Return list of group of nodes close to each other within theTolerance
5565 * Search among theNodes or in the whole mesh if theNodes is empty using
5566 * an Octree algorithm
5568 //================================================================================
5570 void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes,
5571 const double theTolerance,
5572 TListOfListOfNodes & theGroupsOfNodes)
5574 myLastCreatedElems.Clear();
5575 myLastCreatedNodes.Clear();
5577 set<const SMDS_MeshNode*> nodes;
5578 if ( theNodes.empty() )
5579 { // get all nodes in the mesh
5580 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator();
5581 while ( nIt->more() )
5582 nodes.insert( nodes.end(),nIt->next());
5587 SMESH_OctreeNode::FindCoincidentNodes ( nodes, &theGroupsOfNodes, theTolerance);
5591 //=======================================================================
5593 * \brief Implementation of search for the node closest to point
5595 //=======================================================================
5597 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
5599 //---------------------------------------------------------------------
5601 * \brief Constructor
5603 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
5605 myMesh = ( SMESHDS_Mesh* ) theMesh;
5607 set<const SMDS_MeshNode*> nodes;
5609 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator();
5610 while ( nIt->more() )
5611 nodes.insert( nodes.end(), nIt->next() );
5613 myOctreeNode = new SMESH_OctreeNode(nodes) ;
5615 // get max size of a leaf box
5616 SMESH_OctreeNode* tree = myOctreeNode;
5617 while ( !tree->isLeaf() )
5619 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5623 myHalfLeafSize = tree->maxSize() / 2.;
5626 //---------------------------------------------------------------------
5628 * \brief Move node and update myOctreeNode accordingly
5630 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
5632 myOctreeNode->UpdateByMoveNode( node, toPnt );
5633 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
5636 //---------------------------------------------------------------------
5638 * \brief Do it's job
5640 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
5642 SMDS_MeshNode tgtNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5643 map<double, const SMDS_MeshNode*> dist2Nodes;
5644 myOctreeNode->NodesAround( &tgtNode, dist2Nodes, myHalfLeafSize );
5645 if ( !dist2Nodes.empty() )
5646 return dist2Nodes.begin()->second;
5647 list<const SMDS_MeshNode*> nodes;
5648 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
5650 double minSqDist = DBL_MAX;
5651 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
5653 // sort leafs by their distance from thePnt
5654 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
5655 TDistTreeMap treeMap;
5656 list< SMESH_OctreeNode* > treeList;
5657 list< SMESH_OctreeNode* >::iterator trIt;
5658 treeList.push_back( myOctreeNode );
5660 SMDS_MeshNode pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
5661 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
5663 SMESH_OctreeNode* tree = *trIt;
5664 if ( !tree->isLeaf() ) // put children to the queue
5666 if ( !tree->isInside( &pointNode, myHalfLeafSize )) continue;
5667 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
5668 while ( cIt->more() )
5669 treeList.push_back( cIt->next() );
5671 else if ( tree->NbNodes() ) // put a tree to the treeMap
5673 const Bnd_B3d& box = tree->getBox();
5674 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
5675 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
5676 if ( !it_in.second ) // not unique distance to box center
5677 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
5680 // find distance after which there is no sense to check tree's
5681 double sqLimit = DBL_MAX;
5682 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
5683 if ( treeMap.size() > 5 ) {
5684 SMESH_OctreeNode* closestTree = sqDist_tree->second;
5685 const Bnd_B3d& box = closestTree->getBox();
5686 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
5687 sqLimit = limit * limit;
5689 // get all nodes from trees
5690 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
5691 if ( sqDist_tree->first > sqLimit )
5693 SMESH_OctreeNode* tree = sqDist_tree->second;
5694 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
5697 // find closest among nodes
5698 minSqDist = DBL_MAX;
5699 const SMDS_MeshNode* closestNode = 0;
5700 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
5701 for ( ; nIt != nodes.end(); ++nIt ) {
5702 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
5703 if ( minSqDist > sqDist ) {
5711 //---------------------------------------------------------------------
5715 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
5717 //---------------------------------------------------------------------
5719 * \brief Return the node tree
5721 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
5724 SMESH_OctreeNode* myOctreeNode;
5725 SMESHDS_Mesh* myMesh;
5726 double myHalfLeafSize; // max size of a leaf box
5729 //=======================================================================
5731 * \brief Return SMESH_NodeSearcher
5733 //=======================================================================
5735 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
5737 return new SMESH_NodeSearcherImpl( GetMeshDS() );
5740 // ========================================================================
5741 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
5743 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
5744 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
5745 const double NodeRadius = 1e-9; // to enlarge bnd box of element
5747 //=======================================================================
5749 * \brief Octal tree of bounding boxes of elements
5751 //=======================================================================
5753 class ElementBndBoxTree : public SMESH_Octree
5757 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType);
5758 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
5759 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
5760 ~ElementBndBoxTree();
5763 ElementBndBoxTree() {}
5764 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
5765 void buildChildrenData();
5766 Bnd_B3d* buildRootBox();
5768 //!< Bounding box of element
5769 struct ElementBox : public Bnd_B3d
5771 const SMDS_MeshElement* _element;
5772 int _refCount; // an ElementBox can be included in several tree branches
5773 ElementBox(const SMDS_MeshElement* elem);
5775 vector< ElementBox* > _elements;
5778 //================================================================================
5780 * \brief ElementBndBoxTree creation
5782 //================================================================================
5784 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType)
5785 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
5787 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
5788 _elements.reserve( nbElems );
5790 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
5791 while ( elemIt->more() )
5792 _elements.push_back( new ElementBox( elemIt->next() ));
5794 if ( _elements.size() > MaxNbElemsInLeaf )
5800 //================================================================================
5804 //================================================================================
5806 ElementBndBoxTree::~ElementBndBoxTree()
5808 for ( int i = 0; i < _elements.size(); ++i )
5809 if ( --_elements[i]->_refCount <= 0 )
5810 delete _elements[i];
5813 //================================================================================
5815 * \brief Return the maximal box
5817 //================================================================================
5819 Bnd_B3d* ElementBndBoxTree::buildRootBox()
5821 Bnd_B3d* box = new Bnd_B3d;
5822 for ( int i = 0; i < _elements.size(); ++i )
5823 box->Add( *_elements[i] );
5827 //================================================================================
5829 * \brief Redistrubute element boxes among children
5831 //================================================================================
5833 void ElementBndBoxTree::buildChildrenData()
5835 for ( int i = 0; i < _elements.size(); ++i )
5837 for (int j = 0; j < 8; j++)
5839 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
5841 _elements[i]->_refCount++;
5842 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
5845 _elements[i]->_refCount--;
5849 for (int j = 0; j < 8; j++)
5851 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
5852 if ( child->_elements.size() <= MaxNbElemsInLeaf )
5853 child->myIsLeaf = true;
5855 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
5856 child->_elements.resize( child->_elements.size() ); // compact
5860 //================================================================================
5862 * \brief Return elements which can include the point
5864 //================================================================================
5866 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
5867 TIDSortedElemSet& foundElems)
5869 if ( level() && getBox().IsOut( point.XYZ() ))
5874 for ( int i = 0; i < _elements.size(); ++i )
5875 if ( !_elements[i]->IsOut( point.XYZ() ))
5876 foundElems.insert( _elements[i]->_element );
5880 for (int i = 0; i < 8; i++)
5881 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
5885 //================================================================================
5887 * \brief Return elements which can be intersected by the line
5889 //================================================================================
5891 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
5892 TIDSortedElemSet& foundElems)
5894 if ( level() && getBox().IsOut( line ))
5899 for ( int i = 0; i < _elements.size(); ++i )
5900 if ( !_elements[i]->IsOut( line ))
5901 foundElems.insert( _elements[i]->_element );
5905 for (int i = 0; i < 8; i++)
5906 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
5910 //================================================================================
5912 * \brief Construct the element box
5914 //================================================================================
5916 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem)
5920 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
5921 while ( nIt->more() )
5922 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
5923 Enlarge( NodeRadius );
5928 //=======================================================================
5930 * \brief Implementation of search for the elements by point and
5931 * of classification of point in 2D mesh
5933 //=======================================================================
5935 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
5937 SMESHDS_Mesh* _mesh;
5938 ElementBndBoxTree* _ebbTree;
5939 SMESH_NodeSearcherImpl* _nodeSearcher;
5940 SMDSAbs_ElementType _elementType;
5942 bool _outerFacesFound;
5943 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
5945 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
5946 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
5947 ~SMESH_ElementSearcherImpl()
5949 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
5950 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
5952 virtual int FindElementsByPoint(const gp_Pnt& point,
5953 SMDSAbs_ElementType type,
5954 vector< const SMDS_MeshElement* >& foundElements);
5955 virtual TopAbs_State GetPointState(const gp_Pnt& point);
5957 double getTolerance();
5958 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
5959 const double tolerance, double & param);
5960 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
5961 bool isOuterBoundary(const SMDS_MeshElement* face) const
5963 return _outerFaces.empty() || _outerFaces.count(face);
5965 struct TInters //!< data of intersection of the line and the mesh face used in GetPointState()
5967 const SMDS_MeshElement* _face;
5969 bool _coincides; //!< the line lays in face plane
5970 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
5971 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
5973 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
5976 TIDSortedElemSet _faces;
5977 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
5978 : _link( n1, n2 ), _faces( &face, &face + 1) {}
5982 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
5984 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
5985 << ", _coincides="<<i._coincides << ")";
5988 //=======================================================================
5990 * \brief define tolerance for search
5992 //=======================================================================
5994 double SMESH_ElementSearcherImpl::getTolerance()
5996 if ( _tolerance < 0 )
5998 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6001 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6003 double boxSize = _nodeSearcher->getTree()->maxSize();
6004 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6006 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6008 double boxSize = _ebbTree->maxSize();
6009 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6011 if ( _tolerance == 0 )
6013 // define tolerance by size of a most complex element
6014 int complexType = SMDSAbs_Volume;
6015 while ( complexType > SMDSAbs_All &&
6016 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6018 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6021 if ( complexType == int( SMDSAbs_Node ))
6023 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6025 if ( meshInfo.NbNodes() > 2 )
6026 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6030 const SMDS_MeshElement* elem =
6031 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ))->next();
6032 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6033 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6034 while ( nodeIt->more() )
6036 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6037 elemSize = max( dist, elemSize );
6040 _tolerance = 1e-6 * elemSize;
6046 //================================================================================
6048 * \brief Find intersection of the line and an edge of face and return parameter on line
6050 //================================================================================
6052 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6053 const SMDS_MeshElement* face,
6060 GeomAPI_ExtremaCurveCurve anExtCC;
6061 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6063 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6064 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6066 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6067 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6068 anExtCC.Init( lineCurve, edge);
6069 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6071 Quantity_Parameter pl, pe;
6072 anExtCC.LowerDistanceParameters( pl, pe );
6074 if ( ++nbInts == 2 )
6078 if ( nbInts > 0 ) param /= nbInts;
6081 //================================================================================
6083 * \brief Find all faces belonging to the outer boundary of mesh
6085 //================================================================================
6087 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6089 if ( _outerFacesFound ) return;
6091 // Collect all outer faces by passing from one outer face to another via their links
6092 // and BTW find out if there are internal faces at all.
6094 // checked links and links where outer boundary meets internal one
6095 set< SMESH_TLink > visitedLinks, seamLinks;
6097 // links to treat with already visited faces sharing them
6098 list < TFaceLink > startLinks;
6100 // load startLinks with the first outerFace
6101 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6102 _outerFaces.insert( outerFace );
6104 TIDSortedElemSet emptySet;
6105 while ( !startLinks.empty() )
6107 const SMESH_TLink& link = startLinks.front()._link;
6108 TIDSortedElemSet& faces = startLinks.front()._faces;
6110 outerFace = *faces.begin();
6111 // find other faces sharing the link
6112 const SMDS_MeshElement* f;
6113 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6116 // select another outer face among the found
6117 const SMDS_MeshElement* outerFace2 = 0;
6118 if ( faces.size() == 2 )
6120 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6122 else if ( faces.size() > 2 )
6124 seamLinks.insert( link );
6126 // link direction within the outerFace
6127 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6128 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6129 int i1 = outerFace->GetNodeIndex( link.node1() );
6130 int i2 = outerFace->GetNodeIndex( link.node2() );
6131 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6132 if ( rev ) n1n2.Reverse();
6134 gp_XYZ ofNorm, fNorm;
6135 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6137 // direction from the link inside outerFace
6138 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6139 // sort all other faces by angle with the dirInOF
6140 map< double, const SMDS_MeshElement* > angle2Face;
6141 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6142 for ( ; face != faces.end(); ++face )
6144 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6146 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6147 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6148 if ( angle < 0 ) angle += 2*PI;
6149 angle2Face.insert( make_pair( angle, *face ));
6151 if ( !angle2Face.empty() )
6152 outerFace2 = angle2Face.begin()->second;
6155 // store the found outer face and add its links to continue seaching from
6158 _outerFaces.insert( outerFace );
6159 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6160 for ( int i = 0; i < nbNodes; ++i )
6162 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6163 if ( visitedLinks.insert( link2 ).second )
6164 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6167 startLinks.pop_front();
6169 _outerFacesFound = true;
6171 if ( !seamLinks.empty() )
6173 // There are internal boundaries touching the outher one,
6174 // find all faces of internal boundaries in order to find
6175 // faces of boundaries of holes, if any.
6180 _outerFaces.clear();
6184 //=======================================================================
6186 * \brief Find elements of given type where the given point is IN or ON.
6187 * Returns nb of found elements and elements them-selves.
6189 * 'ALL' type means elements of any type excluding nodes and 0D elements
6191 //=======================================================================
6193 int SMESH_ElementSearcherImpl::
6194 FindElementsByPoint(const gp_Pnt& point,
6195 SMDSAbs_ElementType type,
6196 vector< const SMDS_MeshElement* >& foundElements)
6198 foundElements.clear();
6200 double tolerance = getTolerance();
6202 // =================================================================================
6203 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6205 if ( !_nodeSearcher )
6206 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6208 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6209 if ( !closeNode ) return foundElements.size();
6211 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6212 return foundElements.size(); // to far from any node
6214 if ( type == SMDSAbs_Node )
6216 foundElements.push_back( closeNode );
6220 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6221 while ( elemIt->more() )
6222 foundElements.push_back( elemIt->next() );
6225 // =================================================================================
6226 else // elements more complex than 0D
6228 if ( !_ebbTree || _elementType != type )
6230 if ( _ebbTree ) delete _ebbTree;
6231 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6233 TIDSortedElemSet suspectElems;
6234 _ebbTree->getElementsNearPoint( point, suspectElems );
6235 TIDSortedElemSet::iterator elem = suspectElems.begin();
6236 for ( ; elem != suspectElems.end(); ++elem )
6237 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6238 foundElements.push_back( *elem );
6240 return foundElements.size();
6243 //================================================================================
6245 * \brief Classify the given point in the closed 2D mesh
6247 //================================================================================
6249 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6251 double tolerance = getTolerance();
6252 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6254 if ( _ebbTree ) delete _ebbTree;
6255 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6257 // Algo: analyse transition of a line starting at the point through mesh boundary;
6258 // try three lines parallel to axis of the coordinate system and perform rough
6259 // analysis. If solution is not clear perform thorough analysis.
6261 const int nbAxes = 3;
6262 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6263 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6264 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6265 multimap< int, int > nbInt2Axis; // to find the simplest case
6266 for ( int axis = 0; axis < nbAxes; ++axis )
6268 gp_Ax1 lineAxis( point, axisDir[axis]);
6269 gp_Lin line ( lineAxis );
6271 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6272 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6274 // Intersect faces with the line
6276 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6277 TIDSortedElemSet::iterator face = suspectFaces.begin();
6278 for ( ; face != suspectFaces.end(); ++face )
6282 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6283 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6285 // perform intersection
6286 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6287 if ( !intersection.IsDone() )
6289 if ( intersection.IsInQuadric() )
6291 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6293 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6295 gp_Pnt intersectionPoint = intersection.Point(1);
6296 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6297 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6300 // Analyse intersections roughly
6302 int nbInter = u2inters.size();
6306 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6307 if ( nbInter == 1 ) // not closed mesh
6308 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6310 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6313 if ( (f<0) == (l<0) )
6316 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6317 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6318 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6321 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6323 if ( _outerFacesFound ) break; // pass to thorough analysis
6325 } // three attempts - loop on CS axes
6327 // Analyse intersections thoroughly.
6328 // We make two loops maximum, on the first one we only exclude touching intersections,
6329 // on the second, if situation is still unclear, we gather and use information on
6330 // position of faces (internal or outer). If faces position is already gathered,
6331 // we make the second loop right away.
6333 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6335 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6336 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6338 int axis = nb_axis->second;
6339 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6341 gp_Ax1 lineAxis( point, axisDir[axis]);
6342 gp_Lin line ( lineAxis );
6344 // add tangent intersections to u2inters
6346 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6347 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6348 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6349 u2inters.insert(make_pair( param, *tgtInt ));
6350 tangentInters[ axis ].clear();
6352 // Count intersections before and after the point excluding touching ones.
6353 // If hasPositionInfo we count intersections of outer boundary only
6355 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6356 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6357 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6358 bool ok = ! u_int1->second._coincides;
6359 while ( ok && u_int1 != u2inters.end() )
6361 double u = u_int1->first;
6362 bool touchingInt = false;
6363 if ( ++u_int2 != u2inters.end() )
6365 // skip intersections at the same point (if the line passes through edge or node)
6367 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6373 // skip tangent intersections
6375 const SMDS_MeshElement* prevFace = u_int1->second._face;
6376 while ( ok && u_int2->second._coincides )
6378 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6384 ok = ( u_int2 != u2inters.end() );
6389 // skip intersections at the same point after tangent intersections
6392 double u2 = u_int2->first;
6394 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6400 // decide if we skipped a touching intersection
6401 if ( nbSamePnt + nbTgt > 0 )
6403 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6404 map< double, TInters >::iterator u_int = u_int1;
6405 for ( ; u_int != u_int2; ++u_int )
6407 if ( u_int->second._coincides ) continue;
6408 double dot = u_int->second._faceNorm * line.Direction();
6409 if ( dot > maxDot ) maxDot = dot;
6410 if ( dot < minDot ) minDot = dot;
6412 touchingInt = ( minDot*maxDot < 0 );
6417 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6428 u_int1 = u_int2; // to next intersection
6430 } // loop on intersections with one line
6434 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6437 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6440 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6441 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6443 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6446 if ( (f<0) == (l<0) )
6449 if ( hasPositionInfo )
6450 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6452 } // loop on intersections of the tree lines - thorough analysis
6454 if ( !hasPositionInfo )
6456 // gather info on faces position - is face in the outer boundary or not
6457 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6458 findOuterBoundary( u2inters.begin()->second._face );
6461 } // two attempts - with and w/o faces position info in the mesh
6463 return TopAbs_UNKNOWN;
6466 //=======================================================================
6468 * \brief Return SMESH_ElementSearcher
6470 //=======================================================================
6472 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
6474 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
6477 //=======================================================================
6479 * \brief Return true if the point is IN or ON of the element
6481 //=======================================================================
6483 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
6485 if ( element->GetType() == SMDSAbs_Volume)
6487 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
6490 // get ordered nodes
6492 vector< gp_XYZ > xyz;
6494 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
6495 if ( element->IsQuadratic() )
6496 if (const SMDS_QuadraticFaceOfNodes* f=dynamic_cast<const SMDS_QuadraticFaceOfNodes*>(element))
6497 nodeIt = f->interlacedNodesElemIterator();
6498 else if (const SMDS_QuadraticEdge* e =dynamic_cast<const SMDS_QuadraticEdge*>(element))
6499 nodeIt = e->interlacedNodesElemIterator();
6501 while ( nodeIt->more() )
6502 xyz.push_back( TNodeXYZ( cast2Node( nodeIt->next() )));
6504 int i, nbNodes = element->NbNodes();
6506 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
6508 // compute face normal
6509 gp_Vec faceNorm(0,0,0);
6510 xyz.push_back( xyz.front() );
6511 for ( i = 0; i < nbNodes; ++i )
6513 gp_Vec edge1( xyz[i+1], xyz[i]);
6514 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
6515 faceNorm += edge1 ^ edge2;
6517 double normSize = faceNorm.Magnitude();
6518 if ( normSize <= tol )
6520 // degenerated face: point is out if it is out of all face edges
6521 for ( i = 0; i < nbNodes; ++i )
6523 SMDS_MeshNode n1( xyz[i].X(), xyz[i].Y(), xyz[i].Z() );
6524 SMDS_MeshNode n2( xyz[i+1].X(), xyz[i+1].Y(), xyz[i+1].Z() );
6525 SMDS_MeshEdge edge( &n1, &n2 );
6526 if ( !isOut( &edge, point, tol ))
6531 faceNorm /= normSize;
6533 // check if the point lays on face plane
6534 gp_Vec n2p( xyz[0], point );
6535 if ( fabs( n2p * faceNorm ) > tol )
6536 return true; // not on face plane
6538 // check if point is out of face boundary:
6539 // define it by closest transition of a ray point->infinity through face boundary
6540 // on the face plane.
6541 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
6542 // to find intersections of the ray with the boundary.
6544 gp_Vec plnNorm = ray ^ faceNorm;
6545 normSize = plnNorm.Magnitude();
6546 if ( normSize <= tol ) return false; // point coincides with the first node
6547 plnNorm /= normSize;
6548 // for each node of the face, compute its signed distance to the plane
6549 vector<double> dist( nbNodes + 1);
6550 for ( i = 0; i < nbNodes; ++i )
6552 gp_Vec n2p( xyz[i], point );
6553 dist[i] = n2p * plnNorm;
6555 dist.back() = dist.front();
6556 // find the closest intersection
6558 double rClosest, distClosest = 1e100;;
6560 for ( i = 0; i < nbNodes; ++i )
6563 if ( fabs( dist[i]) < tol )
6565 else if ( fabs( dist[i+1]) < tol )
6567 else if ( dist[i] * dist[i+1] < 0 )
6568 r = dist[i] / ( dist[i] - dist[i+1] );
6570 continue; // no intersection
6571 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
6572 gp_Vec p2int ( point, pInt);
6573 if ( p2int * ray > -tol ) // right half-space
6575 double intDist = p2int.SquareMagnitude();
6576 if ( intDist < distClosest )
6581 distClosest = intDist;
6586 return true; // no intesections - out
6588 // analyse transition
6589 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
6590 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
6591 gp_Vec p2int ( point, pClosest );
6592 bool out = (edgeNorm * p2int) < -tol;
6593 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
6596 // ray pass through a face node; analyze transition through an adjacent edge
6597 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
6598 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
6599 gp_Vec edgeAdjacent( p1, p2 );
6600 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
6601 bool out2 = (edgeNorm2 * p2int) < -tol;
6603 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
6604 return covexCorner ? (out || out2) : (out && out2);
6606 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
6608 // point is out of edge if it is NOT ON any straight part of edge
6609 // (we consider quadratic edge as being composed of two straight parts)
6610 for ( i = 1; i < nbNodes; ++i )
6612 gp_Vec edge( xyz[i-1], xyz[i]);
6613 gp_Vec n1p ( xyz[i-1], point);
6614 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
6617 gp_Vec n2p( xyz[i], point );
6618 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
6620 return false; // point is ON this part
6624 // Node or 0D element -------------------------------------------------------------------------
6626 gp_Vec n2p ( xyz[0], point );
6627 return n2p.Magnitude() <= tol;
6632 //=======================================================================
6633 //function : SimplifyFace
6635 //=======================================================================
6636 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
6637 vector<const SMDS_MeshNode *>& poly_nodes,
6638 vector<int>& quantities) const
6640 int nbNodes = faceNodes.size();
6645 set<const SMDS_MeshNode*> nodeSet;
6647 // get simple seq of nodes
6648 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
6649 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
6650 int iSimple = 0, nbUnique = 0;
6652 simpleNodes[iSimple++] = faceNodes[0];
6654 for (int iCur = 1; iCur < nbNodes; iCur++) {
6655 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
6656 simpleNodes[iSimple++] = faceNodes[iCur];
6657 if (nodeSet.insert( faceNodes[iCur] ).second)
6661 int nbSimple = iSimple;
6662 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
6672 bool foundLoop = (nbSimple > nbUnique);
6675 set<const SMDS_MeshNode*> loopSet;
6676 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
6677 const SMDS_MeshNode* n = simpleNodes[iSimple];
6678 if (!loopSet.insert( n ).second) {
6682 int iC = 0, curLast = iSimple;
6683 for (; iC < curLast; iC++) {
6684 if (simpleNodes[iC] == n) break;
6686 int loopLen = curLast - iC;
6688 // create sub-element
6690 quantities.push_back(loopLen);
6691 for (; iC < curLast; iC++) {
6692 poly_nodes.push_back(simpleNodes[iC]);
6695 // shift the rest nodes (place from the first loop position)
6696 for (iC = curLast + 1; iC < nbSimple; iC++) {
6697 simpleNodes[iC - loopLen] = simpleNodes[iC];
6699 nbSimple -= loopLen;
6702 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
6703 } // while (foundLoop)
6707 quantities.push_back(iSimple);
6708 for (int i = 0; i < iSimple; i++)
6709 poly_nodes.push_back(simpleNodes[i]);
6715 //=======================================================================
6716 //function : MergeNodes
6717 //purpose : In each group, the cdr of nodes are substituted by the first one
6719 //=======================================================================
6721 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
6723 myLastCreatedElems.Clear();
6724 myLastCreatedNodes.Clear();
6726 SMESHDS_Mesh* aMesh = GetMeshDS();
6728 TNodeNodeMap nodeNodeMap; // node to replace - new node
6729 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
6730 list< int > rmElemIds, rmNodeIds;
6732 // Fill nodeNodeMap and elems
6734 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
6735 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
6736 list<const SMDS_MeshNode*>& nodes = *grIt;
6737 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6738 const SMDS_MeshNode* nToKeep = *nIt;
6739 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
6740 const SMDS_MeshNode* nToRemove = *nIt;
6741 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
6742 if ( nToRemove != nToKeep ) {
6743 rmNodeIds.push_back( nToRemove->GetID() );
6744 AddToSameGroups( nToKeep, nToRemove, aMesh );
6747 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
6748 while ( invElemIt->more() ) {
6749 const SMDS_MeshElement* elem = invElemIt->next();
6754 // Change element nodes or remove an element
6756 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
6757 for ( ; eIt != elems.end(); eIt++ ) {
6758 const SMDS_MeshElement* elem = *eIt;
6759 int nbNodes = elem->NbNodes();
6760 int aShapeId = FindShape( elem );
6762 set<const SMDS_MeshNode*> nodeSet;
6763 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
6764 int iUnique = 0, iCur = 0, nbRepl = 0;
6765 vector<int> iRepl( nbNodes );
6767 // get new seq of nodes
6768 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6769 while ( itN->more() ) {
6770 const SMDS_MeshNode* n =
6771 static_cast<const SMDS_MeshNode*>( itN->next() );
6773 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
6774 if ( nnIt != nodeNodeMap.end() ) { // n sticks
6776 // BUG 0020185: begin
6778 bool stopRecur = false;
6779 set<const SMDS_MeshNode*> nodesRecur;
6780 nodesRecur.insert(n);
6781 while (!stopRecur) {
6782 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
6783 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
6784 n = (*nnIt_i).second;
6785 if (!nodesRecur.insert(n).second) {
6786 // error: recursive dependancy
6795 iRepl[ nbRepl++ ] = iCur;
6797 curNodes[ iCur ] = n;
6798 bool isUnique = nodeSet.insert( n ).second;
6800 uniqueNodes[ iUnique++ ] = n;
6804 // Analyse element topology after replacement
6807 int nbUniqueNodes = nodeSet.size();
6808 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
6809 // Polygons and Polyhedral volumes
6810 if (elem->IsPoly()) {
6812 if (elem->GetType() == SMDSAbs_Face) {
6814 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
6816 for (; inode < nbNodes; inode++) {
6817 face_nodes[inode] = curNodes[inode];
6820 vector<const SMDS_MeshNode *> polygons_nodes;
6821 vector<int> quantities;
6822 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
6826 for (int iface = 0; iface < nbNew - 1; iface++) {
6827 int nbNodes = quantities[iface];
6828 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
6829 for (int ii = 0; ii < nbNodes; ii++, inode++) {
6830 poly_nodes[ii] = polygons_nodes[inode];
6832 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
6833 myLastCreatedElems.Append(newElem);
6835 aMesh->SetMeshElementOnShape(newElem, aShapeId);
6837 aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
6840 rmElemIds.push_back(elem->GetID());
6844 else if (elem->GetType() == SMDSAbs_Volume) {
6845 // Polyhedral volume
6846 if (nbUniqueNodes < 4) {
6847 rmElemIds.push_back(elem->GetID());
6850 // each face has to be analized in order to check volume validity
6851 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
6852 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
6854 int nbFaces = aPolyedre->NbFaces();
6856 vector<const SMDS_MeshNode *> poly_nodes;
6857 vector<int> quantities;
6859 for (int iface = 1; iface <= nbFaces; iface++) {
6860 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6861 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
6863 for (int inode = 1; inode <= nbFaceNodes; inode++) {
6864 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
6865 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
6866 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
6867 faceNode = (*nnIt).second;
6869 faceNodes[inode - 1] = faceNode;
6872 SimplifyFace(faceNodes, poly_nodes, quantities);
6875 if (quantities.size() > 3) {
6876 // to be done: remove coincident faces
6879 if (quantities.size() > 3)
6880 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6882 rmElemIds.push_back(elem->GetID());
6886 rmElemIds.push_back(elem->GetID());
6897 switch ( nbNodes ) {
6898 case 2: ///////////////////////////////////// EDGE
6899 isOk = false; break;
6900 case 3: ///////////////////////////////////// TRIANGLE
6901 isOk = false; break;
6903 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
6905 else { //////////////////////////////////// QUADRANGLE
6906 if ( nbUniqueNodes < 3 )
6908 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
6909 isOk = false; // opposite nodes stick
6912 case 6: ///////////////////////////////////// PENTAHEDRON
6913 if ( nbUniqueNodes == 4 ) {
6914 // ---------------------------------> tetrahedron
6916 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
6917 // all top nodes stick: reverse a bottom
6918 uniqueNodes[ 0 ] = curNodes [ 1 ];
6919 uniqueNodes[ 1 ] = curNodes [ 0 ];
6921 else if (nbRepl == 3 &&
6922 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
6923 // all bottom nodes stick: set a top before
6924 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
6925 uniqueNodes[ 0 ] = curNodes [ 3 ];
6926 uniqueNodes[ 1 ] = curNodes [ 4 ];
6927 uniqueNodes[ 2 ] = curNodes [ 5 ];
6929 else if (nbRepl == 4 &&
6930 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
6931 // a lateral face turns into a line: reverse a bottom
6932 uniqueNodes[ 0 ] = curNodes [ 1 ];
6933 uniqueNodes[ 1 ] = curNodes [ 0 ];
6938 else if ( nbUniqueNodes == 5 ) {
6939 // PENTAHEDRON --------------------> 2 tetrahedrons
6940 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
6941 // a bottom node sticks with a linked top one
6943 SMDS_MeshElement* newElem =
6944 aMesh->AddVolume(curNodes[ 3 ],
6947 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
6948 myLastCreatedElems.Append(newElem);
6950 aMesh->SetMeshElementOnShape( newElem, aShapeId );
6951 // 2. : reverse a bottom
6952 uniqueNodes[ 0 ] = curNodes [ 1 ];
6953 uniqueNodes[ 1 ] = curNodes [ 0 ];
6963 if(elem->IsQuadratic()) { // Quadratic quadrangle
6976 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
6977 uniqueNodes[0] = curNodes[0];
6978 uniqueNodes[1] = curNodes[2];
6979 uniqueNodes[2] = curNodes[3];
6980 uniqueNodes[3] = curNodes[5];
6981 uniqueNodes[4] = curNodes[6];
6982 uniqueNodes[5] = curNodes[7];
6985 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
6986 uniqueNodes[0] = curNodes[0];
6987 uniqueNodes[1] = curNodes[1];
6988 uniqueNodes[2] = curNodes[2];
6989 uniqueNodes[3] = curNodes[4];
6990 uniqueNodes[4] = curNodes[5];
6991 uniqueNodes[5] = curNodes[6];
6994 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
6995 uniqueNodes[0] = curNodes[1];
6996 uniqueNodes[1] = curNodes[2];
6997 uniqueNodes[2] = curNodes[3];
6998 uniqueNodes[3] = curNodes[5];
6999 uniqueNodes[4] = curNodes[6];
7000 uniqueNodes[5] = curNodes[0];
7003 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7004 uniqueNodes[0] = curNodes[0];
7005 uniqueNodes[1] = curNodes[1];
7006 uniqueNodes[2] = curNodes[3];
7007 uniqueNodes[3] = curNodes[4];
7008 uniqueNodes[4] = curNodes[6];
7009 uniqueNodes[5] = curNodes[7];
7012 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7013 uniqueNodes[0] = curNodes[0];
7014 uniqueNodes[1] = curNodes[2];
7015 uniqueNodes[2] = curNodes[3];
7016 uniqueNodes[3] = curNodes[1];
7017 uniqueNodes[4] = curNodes[6];
7018 uniqueNodes[5] = curNodes[7];
7021 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7022 uniqueNodes[0] = curNodes[0];
7023 uniqueNodes[1] = curNodes[1];
7024 uniqueNodes[2] = curNodes[2];
7025 uniqueNodes[3] = curNodes[4];
7026 uniqueNodes[4] = curNodes[5];
7027 uniqueNodes[5] = curNodes[7];
7030 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7031 uniqueNodes[0] = curNodes[0];
7032 uniqueNodes[1] = curNodes[1];
7033 uniqueNodes[2] = curNodes[3];
7034 uniqueNodes[3] = curNodes[4];
7035 uniqueNodes[4] = curNodes[2];
7036 uniqueNodes[5] = curNodes[7];
7039 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7040 uniqueNodes[0] = curNodes[0];
7041 uniqueNodes[1] = curNodes[1];
7042 uniqueNodes[2] = curNodes[2];
7043 uniqueNodes[3] = curNodes[4];
7044 uniqueNodes[4] = curNodes[5];
7045 uniqueNodes[5] = curNodes[3];
7051 //////////////////////////////////// HEXAHEDRON
7053 SMDS_VolumeTool hexa (elem);
7054 hexa.SetExternalNormal();
7055 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7056 //////////////////////// ---> tetrahedron
7057 for ( int iFace = 0; iFace < 6; iFace++ ) {
7058 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7059 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7060 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7061 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7062 // one face turns into a point ...
7063 int iOppFace = hexa.GetOppFaceIndex( iFace );
7064 ind = hexa.GetFaceNodesIndices( iOppFace );
7066 iUnique = 2; // reverse a tetrahedron bottom
7067 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7068 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7070 else if ( iUnique >= 0 )
7071 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7073 if ( nbStick == 1 ) {
7074 // ... and the opposite one - into a triangle.
7076 ind = hexa.GetFaceNodesIndices( iFace );
7077 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7084 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7085 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7086 for ( int iFace = 0; iFace < 6; iFace++ ) {
7087 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7088 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7089 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7090 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7091 // one face turns into a point ...
7092 int iOppFace = hexa.GetOppFaceIndex( iFace );
7093 ind = hexa.GetFaceNodesIndices( iOppFace );
7095 iUnique = 2; // reverse a tetrahedron 1 bottom
7096 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7097 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7099 else if ( iUnique >= 0 )
7100 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7102 if ( nbStick == 0 ) {
7103 // ... and the opposite one is a quadrangle
7105 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7106 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7109 SMDS_MeshElement* newElem =
7110 aMesh->AddVolume(curNodes[ind[ 0 ]],
7113 curNodes[indTop[ 0 ]]);
7114 myLastCreatedElems.Append(newElem);
7116 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7123 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7124 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7125 // find indices of quad and tri faces
7126 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7127 for ( iFace = 0; iFace < 6; iFace++ ) {
7128 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7130 for ( iCur = 0; iCur < 4; iCur++ )
7131 nodeSet.insert( curNodes[ind[ iCur ]] );
7132 nbUniqueNodes = nodeSet.size();
7133 if ( nbUniqueNodes == 3 )
7134 iTriFace[ nbTri++ ] = iFace;
7135 else if ( nbUniqueNodes == 4 )
7136 iQuadFace[ nbQuad++ ] = iFace;
7138 if (nbQuad == 2 && nbTri == 4 &&
7139 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7140 // 2 opposite quadrangles stuck with a diagonal;
7141 // sample groups of merged indices: (0-4)(2-6)
7142 // --------------------------------------------> 2 tetrahedrons
7143 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7144 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7145 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7146 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7147 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7148 // stuck with 0-2 diagonal
7156 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7157 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7158 // stuck with 1-3 diagonal
7170 uniqueNodes[ 0 ] = curNodes [ i0 ];
7171 uniqueNodes[ 1 ] = curNodes [ i1d ];
7172 uniqueNodes[ 2 ] = curNodes [ i3d ];
7173 uniqueNodes[ 3 ] = curNodes [ i0t ];
7176 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7180 myLastCreatedElems.Append(newElem);
7182 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7185 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7186 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7187 // --------------------------------------------> prism
7188 // find 2 opposite triangles
7190 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7191 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7192 // find indices of kept and replaced nodes
7193 // and fill unique nodes of 2 opposite triangles
7194 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7195 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7196 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7197 // fill unique nodes
7200 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7201 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7202 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7204 // iCur of a linked node of the opposite face (make normals co-directed):
7205 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7206 // check that correspondent corners of triangles are linked
7207 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7210 uniqueNodes[ iUnique ] = n;
7211 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7220 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7226 } // switch ( nbNodes )
7228 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7231 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7232 // Change nodes of polyedre
7233 const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
7234 static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
7236 int nbFaces = aPolyedre->NbFaces();
7238 vector<const SMDS_MeshNode *> poly_nodes;
7239 vector<int> quantities (nbFaces);
7241 for (int iface = 1; iface <= nbFaces; iface++) {
7242 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7243 quantities[iface - 1] = nbFaceNodes;
7245 for (inode = 1; inode <= nbFaceNodes; inode++) {
7246 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7248 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7249 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7250 curNode = (*nnIt).second;
7252 poly_nodes.push_back(curNode);
7255 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7259 // Change regular element or polygon
7260 aMesh->ChangeElementNodes( elem, & uniqueNodes[0], nbUniqueNodes );
7264 // Remove invalid regular element or invalid polygon
7265 rmElemIds.push_back( elem->GetID() );
7268 } // loop on elements
7270 // Remove equal nodes and bad elements
7272 Remove( rmNodeIds, true );
7273 Remove( rmElemIds, false );
7278 // ========================================================
7279 // class : SortableElement
7280 // purpose : allow sorting elements basing on their nodes
7281 // ========================================================
7282 class SortableElement : public set <const SMDS_MeshElement*>
7286 SortableElement( const SMDS_MeshElement* theElem )
7289 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7290 while ( nodeIt->more() )
7291 this->insert( nodeIt->next() );
7294 const SMDS_MeshElement* Get() const
7297 void Set(const SMDS_MeshElement* e) const
7302 mutable const SMDS_MeshElement* myElem;
7305 //=======================================================================
7306 //function : FindEqualElements
7307 //purpose : Return list of group of elements built on the same nodes.
7308 // Search among theElements or in the whole mesh if theElements is empty
7309 //=======================================================================
7310 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7311 TListOfListOfElementsID & theGroupsOfElementsID)
7313 myLastCreatedElems.Clear();
7314 myLastCreatedNodes.Clear();
7316 typedef set<const SMDS_MeshElement*> TElemsSet;
7317 typedef map< SortableElement, int > TMapOfNodeSet;
7318 typedef list<int> TGroupOfElems;
7321 if ( theElements.empty() )
7322 { // get all elements in the mesh
7323 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7324 while ( eIt->more() )
7325 elems.insert( elems.end(), eIt->next());
7328 elems = theElements;
7330 vector< TGroupOfElems > arrayOfGroups;
7331 TGroupOfElems groupOfElems;
7332 TMapOfNodeSet mapOfNodeSet;
7334 TElemsSet::iterator elemIt = elems.begin();
7335 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7336 const SMDS_MeshElement* curElem = *elemIt;
7337 SortableElement SE(curElem);
7340 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7341 if( !(pp.second) ) {
7342 TMapOfNodeSet::iterator& itSE = pp.first;
7343 ind = (*itSE).second;
7344 arrayOfGroups[ind].push_back(curElem->GetID());
7347 groupOfElems.clear();
7348 groupOfElems.push_back(curElem->GetID());
7349 arrayOfGroups.push_back(groupOfElems);
7354 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7355 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7356 groupOfElems = *groupIt;
7357 if ( groupOfElems.size() > 1 ) {
7358 groupOfElems.sort();
7359 theGroupsOfElementsID.push_back(groupOfElems);
7364 //=======================================================================
7365 //function : MergeElements
7366 //purpose : In each given group, substitute all elements by the first one.
7367 //=======================================================================
7369 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7371 myLastCreatedElems.Clear();
7372 myLastCreatedNodes.Clear();
7374 typedef list<int> TListOfIDs;
7375 TListOfIDs rmElemIds; // IDs of elems to remove
7377 SMESHDS_Mesh* aMesh = GetMeshDS();
7379 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7380 while ( groupsIt != theGroupsOfElementsID.end() ) {
7381 TListOfIDs& aGroupOfElemID = *groupsIt;
7382 aGroupOfElemID.sort();
7383 int elemIDToKeep = aGroupOfElemID.front();
7384 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7385 aGroupOfElemID.pop_front();
7386 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7387 while ( idIt != aGroupOfElemID.end() ) {
7388 int elemIDToRemove = *idIt;
7389 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7390 // add the kept element in groups of removed one (PAL15188)
7391 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7392 rmElemIds.push_back( elemIDToRemove );
7398 Remove( rmElemIds, false );
7401 //=======================================================================
7402 //function : MergeEqualElements
7403 //purpose : Remove all but one of elements built on the same nodes.
7404 //=======================================================================
7406 void SMESH_MeshEditor::MergeEqualElements()
7408 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7409 to merge equal elements in the whole mesh */
7410 TListOfListOfElementsID aGroupsOfElementsID;
7411 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7412 MergeElements(aGroupsOfElementsID);
7415 //=======================================================================
7416 //function : FindFaceInSet
7417 //purpose : Return a face having linked nodes n1 and n2 and which is
7418 // - not in avoidSet,
7419 // - in elemSet provided that !elemSet.empty()
7420 // i1 and i2 optionally returns indices of n1 and n2
7421 //=======================================================================
7423 const SMDS_MeshElement*
7424 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
7425 const SMDS_MeshNode* n2,
7426 const TIDSortedElemSet& elemSet,
7427 const TIDSortedElemSet& avoidSet,
7433 const SMDS_MeshElement* face = 0;
7435 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
7436 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
7438 const SMDS_MeshElement* elem = invElemIt->next();
7439 if (avoidSet.count( elem ))
7441 if ( !elemSet.empty() && !elemSet.count( elem ))
7444 i1 = elem->GetNodeIndex( n1 );
7445 // find a n2 linked to n1
7446 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
7447 for ( int di = -1; di < 2 && !face; di += 2 )
7449 i2 = (i1+di+nbN) % nbN;
7450 if ( elem->GetNode( i2 ) == n2 )
7453 if ( !face && elem->IsQuadratic())
7455 // analysis for quadratic elements using all nodes
7456 const SMDS_QuadraticFaceOfNodes* F =
7457 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7458 // use special nodes iterator
7459 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7460 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
7461 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
7463 const SMDS_MeshNode* n = cast2Node( anIter->next() );
7464 if ( n1 == prevN && n2 == n )
7468 else if ( n2 == prevN && n1 == n )
7470 face = elem; swap( i1, i2 );
7476 if ( n1ind ) *n1ind = i1;
7477 if ( n2ind ) *n2ind = i2;
7481 //=======================================================================
7482 //function : findAdjacentFace
7484 //=======================================================================
7486 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
7487 const SMDS_MeshNode* n2,
7488 const SMDS_MeshElement* elem)
7490 TIDSortedElemSet elemSet, avoidSet;
7492 avoidSet.insert ( elem );
7493 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
7496 //=======================================================================
7497 //function : FindFreeBorder
7499 //=======================================================================
7501 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
7503 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
7504 const SMDS_MeshNode* theSecondNode,
7505 const SMDS_MeshNode* theLastNode,
7506 list< const SMDS_MeshNode* > & theNodes,
7507 list< const SMDS_MeshElement* >& theFaces)
7509 if ( !theFirstNode || !theSecondNode )
7511 // find border face between theFirstNode and theSecondNode
7512 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
7516 theFaces.push_back( curElem );
7517 theNodes.push_back( theFirstNode );
7518 theNodes.push_back( theSecondNode );
7520 //vector<const SMDS_MeshNode*> nodes;
7521 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
7522 TIDSortedElemSet foundElems;
7523 bool needTheLast = ( theLastNode != 0 );
7525 while ( nStart != theLastNode ) {
7526 if ( nStart == theFirstNode )
7527 return !needTheLast;
7529 // find all free border faces sharing form nStart
7531 list< const SMDS_MeshElement* > curElemList;
7532 list< const SMDS_MeshNode* > nStartList;
7533 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
7534 while ( invElemIt->more() ) {
7535 const SMDS_MeshElement* e = invElemIt->next();
7536 if ( e == curElem || foundElems.insert( e ).second ) {
7538 int iNode = 0, nbNodes = e->NbNodes();
7539 //const SMDS_MeshNode* nodes[nbNodes+1];
7540 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
7542 if(e->IsQuadratic()) {
7543 const SMDS_QuadraticFaceOfNodes* F =
7544 static_cast<const SMDS_QuadraticFaceOfNodes*>(e);
7545 // use special nodes iterator
7546 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7547 while( anIter->more() ) {
7548 nodes[ iNode++ ] = anIter->next();
7552 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
7553 while ( nIt->more() )
7554 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
7556 nodes[ iNode ] = nodes[ 0 ];
7558 for ( iNode = 0; iNode < nbNodes; iNode++ )
7559 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
7560 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
7561 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
7563 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
7564 curElemList.push_back( e );
7568 // analyse the found
7570 int nbNewBorders = curElemList.size();
7571 if ( nbNewBorders == 0 ) {
7572 // no free border furthermore
7573 return !needTheLast;
7575 else if ( nbNewBorders == 1 ) {
7576 // one more element found
7578 nStart = nStartList.front();
7579 curElem = curElemList.front();
7580 theFaces.push_back( curElem );
7581 theNodes.push_back( nStart );
7584 // several continuations found
7585 list< const SMDS_MeshElement* >::iterator curElemIt;
7586 list< const SMDS_MeshNode* >::iterator nStartIt;
7587 // check if one of them reached the last node
7588 if ( needTheLast ) {
7589 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7590 curElemIt!= curElemList.end();
7591 curElemIt++, nStartIt++ )
7592 if ( *nStartIt == theLastNode ) {
7593 theFaces.push_back( *curElemIt );
7594 theNodes.push_back( *nStartIt );
7598 // find the best free border by the continuations
7599 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
7600 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
7601 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
7602 curElemIt!= curElemList.end();
7603 curElemIt++, nStartIt++ )
7605 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
7606 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
7607 // find one more free border
7608 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
7612 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
7613 // choice: clear a worse one
7614 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
7615 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
7616 contNodes[ iWorse ].clear();
7617 contFaces[ iWorse ].clear();
7620 if ( contNodes[0].empty() && contNodes[1].empty() )
7623 // append the best free border
7624 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
7625 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
7626 theNodes.pop_back(); // remove nIgnore
7627 theNodes.pop_back(); // remove nStart
7628 theFaces.pop_back(); // remove curElem
7629 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
7630 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
7631 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
7632 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
7635 } // several continuations found
7636 } // while ( nStart != theLastNode )
7641 //=======================================================================
7642 //function : CheckFreeBorderNodes
7643 //purpose : Return true if the tree nodes are on a free border
7644 //=======================================================================
7646 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
7647 const SMDS_MeshNode* theNode2,
7648 const SMDS_MeshNode* theNode3)
7650 list< const SMDS_MeshNode* > nodes;
7651 list< const SMDS_MeshElement* > faces;
7652 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
7655 //=======================================================================
7656 //function : SewFreeBorder
7658 //=======================================================================
7660 SMESH_MeshEditor::Sew_Error
7661 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
7662 const SMDS_MeshNode* theBordSecondNode,
7663 const SMDS_MeshNode* theBordLastNode,
7664 const SMDS_MeshNode* theSideFirstNode,
7665 const SMDS_MeshNode* theSideSecondNode,
7666 const SMDS_MeshNode* theSideThirdNode,
7667 const bool theSideIsFreeBorder,
7668 const bool toCreatePolygons,
7669 const bool toCreatePolyedrs)
7671 myLastCreatedElems.Clear();
7672 myLastCreatedNodes.Clear();
7674 MESSAGE("::SewFreeBorder()");
7675 Sew_Error aResult = SEW_OK;
7677 // ====================================
7678 // find side nodes and elements
7679 // ====================================
7681 list< const SMDS_MeshNode* > nSide[ 2 ];
7682 list< const SMDS_MeshElement* > eSide[ 2 ];
7683 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
7684 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
7688 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
7689 nSide[0], eSide[0])) {
7690 MESSAGE(" Free Border 1 not found " );
7691 aResult = SEW_BORDER1_NOT_FOUND;
7693 if (theSideIsFreeBorder) {
7696 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
7697 nSide[1], eSide[1])) {
7698 MESSAGE(" Free Border 2 not found " );
7699 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
7702 if ( aResult != SEW_OK )
7705 if (!theSideIsFreeBorder) {
7709 // -------------------------------------------------------------------------
7711 // 1. If nodes to merge are not coincident, move nodes of the free border
7712 // from the coord sys defined by the direction from the first to last
7713 // nodes of the border to the correspondent sys of the side 2
7714 // 2. On the side 2, find the links most co-directed with the correspondent
7715 // links of the free border
7716 // -------------------------------------------------------------------------
7718 // 1. Since sewing may brake if there are volumes to split on the side 2,
7719 // we wont move nodes but just compute new coordinates for them
7720 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
7721 TNodeXYZMap nBordXYZ;
7722 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
7723 list< const SMDS_MeshNode* >::iterator nBordIt;
7725 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
7726 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
7727 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
7728 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
7729 double tol2 = 1.e-8;
7730 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
7731 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
7732 // Need node movement.
7734 // find X and Z axes to create trsf
7735 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
7737 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
7739 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
7742 gp_Ax3 toBordAx( Pb1, Zb, X );
7743 gp_Ax3 fromSideAx( Ps1, Zs, X );
7744 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
7746 gp_Trsf toBordSys, fromSide2Sys;
7747 toBordSys.SetTransformation( toBordAx );
7748 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
7749 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
7752 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7753 const SMDS_MeshNode* n = *nBordIt;
7754 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
7755 toBordSys.Transforms( xyz );
7756 fromSide2Sys.Transforms( xyz );
7757 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
7761 // just insert nodes XYZ in the nBordXYZ map
7762 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
7763 const SMDS_MeshNode* n = *nBordIt;
7764 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
7768 // 2. On the side 2, find the links most co-directed with the correspondent
7769 // links of the free border
7771 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
7772 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
7773 sideNodes.push_back( theSideFirstNode );
7775 bool hasVolumes = false;
7776 LinkID_Gen aLinkID_Gen( GetMeshDS() );
7777 set<long> foundSideLinkIDs, checkedLinkIDs;
7778 SMDS_VolumeTool volume;
7779 //const SMDS_MeshNode* faceNodes[ 4 ];
7781 const SMDS_MeshNode* sideNode;
7782 const SMDS_MeshElement* sideElem;
7783 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
7784 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
7785 nBordIt = bordNodes.begin();
7787 // border node position and border link direction to compare with
7788 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
7789 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
7790 // choose next side node by link direction or by closeness to
7791 // the current border node:
7792 bool searchByDir = ( *nBordIt != theBordLastNode );
7794 // find the next node on the Side 2
7796 double maxDot = -DBL_MAX, minDist = DBL_MAX;
7798 checkedLinkIDs.clear();
7799 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
7801 // loop on inverse elements of current node (prevSideNode) on the Side 2
7802 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
7803 while ( invElemIt->more() )
7805 const SMDS_MeshElement* elem = invElemIt->next();
7806 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
7807 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
7808 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
7809 bool isVolume = volume.Set( elem );
7810 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
7811 if ( isVolume ) // --volume
7813 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
7814 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
7815 if(elem->IsQuadratic()) {
7816 const SMDS_QuadraticFaceOfNodes* F =
7817 static_cast<const SMDS_QuadraticFaceOfNodes*>(elem);
7818 // use special nodes iterator
7819 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
7820 while( anIter->more() ) {
7821 nodes[ iNode ] = anIter->next();
7822 if ( nodes[ iNode++ ] == prevSideNode )
7823 iPrevNode = iNode - 1;
7827 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
7828 while ( nIt->more() ) {
7829 nodes[ iNode ] = cast2Node( nIt->next() );
7830 if ( nodes[ iNode++ ] == prevSideNode )
7831 iPrevNode = iNode - 1;
7834 // there are 2 links to check
7839 // loop on links, to be precise, on the second node of links
7840 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
7841 const SMDS_MeshNode* n = nodes[ iNode ];
7843 if ( !volume.IsLinked( n, prevSideNode ))
7847 if ( iNode ) // a node before prevSideNode
7848 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
7849 else // a node after prevSideNode
7850 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
7852 // check if this link was already used
7853 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
7854 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
7855 if (!isJustChecked &&
7856 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
7858 // test a link geometrically
7859 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
7860 bool linkIsBetter = false;
7861 double dot = 0.0, dist = 0.0;
7862 if ( searchByDir ) { // choose most co-directed link
7863 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
7864 linkIsBetter = ( dot > maxDot );
7866 else { // choose link with the node closest to bordPos
7867 dist = ( nextXYZ - bordPos ).SquareModulus();
7868 linkIsBetter = ( dist < minDist );
7870 if ( linkIsBetter ) {
7879 } // loop on inverse elements of prevSideNode
7882 MESSAGE(" Cant find path by links of the Side 2 ");
7883 return SEW_BAD_SIDE_NODES;
7885 sideNodes.push_back( sideNode );
7886 sideElems.push_back( sideElem );
7887 foundSideLinkIDs.insert ( linkID );
7888 prevSideNode = sideNode;
7890 if ( *nBordIt == theBordLastNode )
7891 searchByDir = false;
7893 // find the next border link to compare with
7894 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
7895 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7896 // move to next border node if sideNode is before forward border node (bordPos)
7897 while ( *nBordIt != theBordLastNode && !searchByDir ) {
7898 prevBordNode = *nBordIt;
7900 bordPos = nBordXYZ[ *nBordIt ];
7901 bordDir = bordPos - nBordXYZ[ prevBordNode ];
7902 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
7906 while ( sideNode != theSideSecondNode );
7908 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
7909 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
7910 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
7912 } // end nodes search on the side 2
7914 // ============================
7915 // sew the border to the side 2
7916 // ============================
7918 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
7919 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
7921 TListOfListOfNodes nodeGroupsToMerge;
7922 if ( nbNodes[0] == nbNodes[1] ||
7923 ( theSideIsFreeBorder && !theSideThirdNode)) {
7925 // all nodes are to be merged
7927 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
7928 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
7929 nIt[0]++, nIt[1]++ )
7931 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7932 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
7933 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
7938 // insert new nodes into the border and the side to get equal nb of segments
7940 // get normalized parameters of nodes on the borders
7941 //double param[ 2 ][ maxNbNodes ];
7943 param[0] = new double [ maxNbNodes ];
7944 param[1] = new double [ maxNbNodes ];
7946 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7947 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
7948 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
7949 const SMDS_MeshNode* nPrev = *nIt;
7950 double bordLength = 0;
7951 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
7952 const SMDS_MeshNode* nCur = *nIt;
7953 gp_XYZ segment (nCur->X() - nPrev->X(),
7954 nCur->Y() - nPrev->Y(),
7955 nCur->Z() - nPrev->Z());
7956 double segmentLen = segment.Modulus();
7957 bordLength += segmentLen;
7958 param[ iBord ][ iNode ] = bordLength;
7961 // normalize within [0,1]
7962 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
7963 param[ iBord ][ iNode ] /= bordLength;
7967 // loop on border segments
7968 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
7969 int i[ 2 ] = { 0, 0 };
7970 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
7971 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
7973 TElemOfNodeListMap insertMap;
7974 TElemOfNodeListMap::iterator insertMapIt;
7976 // key: elem to insert nodes into
7977 // value: 2 nodes to insert between + nodes to be inserted
7979 bool next[ 2 ] = { false, false };
7981 // find min adjacent segment length after sewing
7982 double nextParam = 10., prevParam = 0;
7983 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
7984 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
7985 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
7986 if ( i[ iBord ] > 0 )
7987 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
7989 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7990 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
7991 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
7993 // choose to insert or to merge nodes
7994 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
7995 if ( Abs( du ) <= minSegLen * 0.2 ) {
7998 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
7999 const SMDS_MeshNode* n0 = *nIt[0];
8000 const SMDS_MeshNode* n1 = *nIt[1];
8001 nodeGroupsToMerge.back().push_back( n1 );
8002 nodeGroupsToMerge.back().push_back( n0 );
8003 // position of node of the border changes due to merge
8004 param[ 0 ][ i[0] ] += du;
8005 // move n1 for the sake of elem shape evaluation during insertion.
8006 // n1 will be removed by MergeNodes() anyway
8007 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8008 next[0] = next[1] = true;
8013 int intoBord = ( du < 0 ) ? 0 : 1;
8014 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8015 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8016 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8017 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8018 if ( intoBord == 1 ) {
8019 // move node of the border to be on a link of elem of the side
8020 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8021 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8022 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8023 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8024 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8026 insertMapIt = insertMap.find( elem );
8027 bool notFound = ( insertMapIt == insertMap.end() );
8028 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8030 // insert into another link of the same element:
8031 // 1. perform insertion into the other link of the elem
8032 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8033 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8034 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8035 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8036 // 2. perform insertion into the link of adjacent faces
8038 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8040 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8044 if (toCreatePolyedrs) {
8045 // perform insertion into the links of adjacent volumes
8046 UpdateVolumes(n12, n22, nodeList);
8048 // 3. find an element appeared on n1 and n2 after the insertion
8049 insertMap.erase( elem );
8050 elem = findAdjacentFace( n1, n2, 0 );
8052 if ( notFound || otherLink ) {
8053 // add element and nodes of the side into the insertMap
8054 insertMapIt = insertMap.insert
8055 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8056 (*insertMapIt).second.push_back( n1 );
8057 (*insertMapIt).second.push_back( n2 );
8059 // add node to be inserted into elem
8060 (*insertMapIt).second.push_back( nIns );
8061 next[ 1 - intoBord ] = true;
8064 // go to the next segment
8065 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8066 if ( next[ iBord ] ) {
8067 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8069 nPrev[ iBord ] = *nIt[ iBord ];
8070 nIt[ iBord ]++; i[ iBord ]++;
8074 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8076 // perform insertion of nodes into elements
8078 for (insertMapIt = insertMap.begin();
8079 insertMapIt != insertMap.end();
8082 const SMDS_MeshElement* elem = (*insertMapIt).first;
8083 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8084 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8085 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8087 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8089 if ( !theSideIsFreeBorder ) {
8090 // look for and insert nodes into the faces adjacent to elem
8092 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8094 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8099 if (toCreatePolyedrs) {
8100 // perform insertion into the links of adjacent volumes
8101 UpdateVolumes(n1, n2, nodeList);
8107 } // end: insert new nodes
8109 MergeNodes ( nodeGroupsToMerge );
8114 //=======================================================================
8115 //function : InsertNodesIntoLink
8116 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8117 // and theBetweenNode2 and split theElement
8118 //=======================================================================
8120 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8121 const SMDS_MeshNode* theBetweenNode1,
8122 const SMDS_MeshNode* theBetweenNode2,
8123 list<const SMDS_MeshNode*>& theNodesToInsert,
8124 const bool toCreatePoly)
8126 if ( theFace->GetType() != SMDSAbs_Face ) return;
8128 // find indices of 2 link nodes and of the rest nodes
8129 int iNode = 0, il1, il2, i3, i4;
8130 il1 = il2 = i3 = i4 = -1;
8131 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8132 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8134 if(theFace->IsQuadratic()) {
8135 const SMDS_QuadraticFaceOfNodes* F =
8136 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8137 // use special nodes iterator
8138 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8139 while( anIter->more() ) {
8140 const SMDS_MeshNode* n = anIter->next();
8141 if ( n == theBetweenNode1 )
8143 else if ( n == theBetweenNode2 )
8149 nodes[ iNode++ ] = n;
8153 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8154 while ( nodeIt->more() ) {
8155 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8156 if ( n == theBetweenNode1 )
8158 else if ( n == theBetweenNode2 )
8164 nodes[ iNode++ ] = n;
8167 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8170 // arrange link nodes to go one after another regarding the face orientation
8171 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8172 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8177 aNodesToInsert.reverse();
8179 // check that not link nodes of a quadrangles are in good order
8180 int nbFaceNodes = theFace->NbNodes();
8181 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8187 if (toCreatePoly || theFace->IsPoly()) {
8190 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8192 // add nodes of face up to first node of link
8195 if(theFace->IsQuadratic()) {
8196 const SMDS_QuadraticFaceOfNodes* F =
8197 static_cast<const SMDS_QuadraticFaceOfNodes*>(theFace);
8198 // use special nodes iterator
8199 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
8200 while( anIter->more() && !isFLN ) {
8201 const SMDS_MeshNode* n = anIter->next();
8202 poly_nodes[iNode++] = n;
8203 if (n == nodes[il1]) {
8207 // add nodes to insert
8208 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8209 for (; nIt != aNodesToInsert.end(); nIt++) {
8210 poly_nodes[iNode++] = *nIt;
8212 // add nodes of face starting from last node of link
8213 while ( anIter->more() ) {
8214 poly_nodes[iNode++] = anIter->next();
8218 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8219 while ( nodeIt->more() && !isFLN ) {
8220 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8221 poly_nodes[iNode++] = n;
8222 if (n == nodes[il1]) {
8226 // add nodes to insert
8227 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8228 for (; nIt != aNodesToInsert.end(); nIt++) {
8229 poly_nodes[iNode++] = *nIt;
8231 // add nodes of face starting from last node of link
8232 while ( nodeIt->more() ) {
8233 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8234 poly_nodes[iNode++] = n;
8238 // edit or replace the face
8239 SMESHDS_Mesh *aMesh = GetMeshDS();
8241 if (theFace->IsPoly()) {
8242 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8245 int aShapeId = FindShape( theFace );
8247 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8248 myLastCreatedElems.Append(newElem);
8249 if ( aShapeId && newElem )
8250 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8252 aMesh->RemoveElement(theFace);
8257 if( !theFace->IsQuadratic() ) {
8259 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8260 int nbLinkNodes = 2 + aNodesToInsert.size();
8261 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8262 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8263 linkNodes[ 0 ] = nodes[ il1 ];
8264 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8265 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8266 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8267 linkNodes[ iNode++ ] = *nIt;
8269 // decide how to split a quadrangle: compare possible variants
8270 // and choose which of splits to be a quadrangle
8271 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8272 if ( nbFaceNodes == 3 ) {
8273 iBestQuad = nbSplits;
8276 else if ( nbFaceNodes == 4 ) {
8277 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8278 double aBestRate = DBL_MAX;
8279 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8281 double aBadRate = 0;
8282 // evaluate elements quality
8283 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8284 if ( iSplit == iQuad ) {
8285 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8289 aBadRate += getBadRate( &quad, aCrit );
8292 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8294 nodes[ iSplit < iQuad ? i4 : i3 ]);
8295 aBadRate += getBadRate( &tria, aCrit );
8299 if ( aBadRate < aBestRate ) {
8301 aBestRate = aBadRate;
8306 // create new elements
8307 SMESHDS_Mesh *aMesh = GetMeshDS();
8308 int aShapeId = FindShape( theFace );
8311 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8312 SMDS_MeshElement* newElem = 0;
8313 if ( iSplit == iBestQuad )
8314 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8319 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8321 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8322 myLastCreatedElems.Append(newElem);
8323 if ( aShapeId && newElem )
8324 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8327 // change nodes of theFace
8328 const SMDS_MeshNode* newNodes[ 4 ];
8329 newNodes[ 0 ] = linkNodes[ i1 ];
8330 newNodes[ 1 ] = linkNodes[ i2 ];
8331 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8332 newNodes[ 3 ] = nodes[ i4 ];
8333 aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8334 } // end if(!theFace->IsQuadratic())
8335 else { // theFace is quadratic
8336 // we have to split theFace on simple triangles and one simple quadrangle
8338 int nbshift = tmp*2;
8339 // shift nodes in nodes[] by nbshift
8341 for(i=0; i<nbshift; i++) {
8342 const SMDS_MeshNode* n = nodes[0];
8343 for(j=0; j<nbFaceNodes-1; j++) {
8344 nodes[j] = nodes[j+1];
8346 nodes[nbFaceNodes-1] = n;
8348 il1 = il1 - nbshift;
8349 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8350 // n0 n1 n2 n0 n1 n2
8351 // +-----+-----+ +-----+-----+
8360 // create new elements
8361 SMESHDS_Mesh *aMesh = GetMeshDS();
8362 int aShapeId = FindShape( theFace );
8365 if(nbFaceNodes==6) { // quadratic triangle
8366 SMDS_MeshElement* newElem =
8367 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8368 myLastCreatedElems.Append(newElem);
8369 if ( aShapeId && newElem )
8370 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8371 if(theFace->IsMediumNode(nodes[il1])) {
8372 // create quadrangle
8373 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8374 myLastCreatedElems.Append(newElem);
8375 if ( aShapeId && newElem )
8376 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8382 // create quadrangle
8383 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8384 myLastCreatedElems.Append(newElem);
8385 if ( aShapeId && newElem )
8386 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8392 else { // nbFaceNodes==8 - quadratic quadrangle
8393 SMDS_MeshElement* newElem =
8394 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8395 myLastCreatedElems.Append(newElem);
8396 if ( aShapeId && newElem )
8397 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8398 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8399 myLastCreatedElems.Append(newElem);
8400 if ( aShapeId && newElem )
8401 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8402 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8403 myLastCreatedElems.Append(newElem);
8404 if ( aShapeId && newElem )
8405 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8406 if(theFace->IsMediumNode(nodes[il1])) {
8407 // create quadrangle
8408 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
8409 myLastCreatedElems.Append(newElem);
8410 if ( aShapeId && newElem )
8411 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8417 // create quadrangle
8418 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
8419 myLastCreatedElems.Append(newElem);
8420 if ( aShapeId && newElem )
8421 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8427 // create needed triangles using n1,n2,n3 and inserted nodes
8428 int nbn = 2 + aNodesToInsert.size();
8429 //const SMDS_MeshNode* aNodes[nbn];
8430 vector<const SMDS_MeshNode*> aNodes(nbn);
8431 aNodes[0] = nodes[n1];
8432 aNodes[nbn-1] = nodes[n2];
8433 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8434 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8435 aNodes[iNode++] = *nIt;
8437 for(i=1; i<nbn; i++) {
8438 SMDS_MeshElement* newElem =
8439 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
8440 myLastCreatedElems.Append(newElem);
8441 if ( aShapeId && newElem )
8442 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8444 // remove old quadratic face
8445 aMesh->RemoveElement(theFace);
8449 //=======================================================================
8450 //function : UpdateVolumes
8452 //=======================================================================
8453 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
8454 const SMDS_MeshNode* theBetweenNode2,
8455 list<const SMDS_MeshNode*>& theNodesToInsert)
8457 myLastCreatedElems.Clear();
8458 myLastCreatedNodes.Clear();
8460 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
8461 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
8462 const SMDS_MeshElement* elem = invElemIt->next();
8464 // check, if current volume has link theBetweenNode1 - theBetweenNode2
8465 SMDS_VolumeTool aVolume (elem);
8466 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
8469 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
8470 int iface, nbFaces = aVolume.NbFaces();
8471 vector<const SMDS_MeshNode *> poly_nodes;
8472 vector<int> quantities (nbFaces);
8474 for (iface = 0; iface < nbFaces; iface++) {
8475 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
8476 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
8477 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
8479 for (int inode = 0; inode < nbFaceNodes; inode++) {
8480 poly_nodes.push_back(faceNodes[inode]);
8482 if (nbInserted == 0) {
8483 if (faceNodes[inode] == theBetweenNode1) {
8484 if (faceNodes[inode + 1] == theBetweenNode2) {
8485 nbInserted = theNodesToInsert.size();
8487 // add nodes to insert
8488 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
8489 for (; nIt != theNodesToInsert.end(); nIt++) {
8490 poly_nodes.push_back(*nIt);
8494 else if (faceNodes[inode] == theBetweenNode2) {
8495 if (faceNodes[inode + 1] == theBetweenNode1) {
8496 nbInserted = theNodesToInsert.size();
8498 // add nodes to insert in reversed order
8499 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
8501 for (; nIt != theNodesToInsert.begin(); nIt--) {
8502 poly_nodes.push_back(*nIt);
8504 poly_nodes.push_back(*nIt);
8511 quantities[iface] = nbFaceNodes + nbInserted;
8514 // Replace or update the volume
8515 SMESHDS_Mesh *aMesh = GetMeshDS();
8517 if (elem->IsPoly()) {
8518 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
8522 int aShapeId = FindShape( elem );
8524 SMDS_MeshElement* newElem =
8525 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
8526 myLastCreatedElems.Append(newElem);
8527 if (aShapeId && newElem)
8528 aMesh->SetMeshElementOnShape(newElem, aShapeId);
8530 aMesh->RemoveElement(elem);
8535 //=======================================================================
8537 * \brief Convert elements contained in a submesh to quadratic
8538 * \retval int - nb of checked elements
8540 //=======================================================================
8542 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
8543 SMESH_MesherHelper& theHelper,
8544 const bool theForce3d)
8547 if( !theSm ) return nbElem;
8549 const bool notFromGroups = false;
8550 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
8551 while(ElemItr->more())
8554 const SMDS_MeshElement* elem = ElemItr->next();
8555 if( !elem || elem->IsQuadratic() ) continue;
8557 int id = elem->GetID();
8558 int nbNodes = elem->NbNodes();
8559 vector<const SMDS_MeshNode *> aNds (nbNodes);
8561 for(int i = 0; i < nbNodes; i++)
8563 aNds[i] = elem->GetNode(i);
8565 SMDSAbs_ElementType aType = elem->GetType();
8567 GetMeshDS()->RemoveFreeElement(elem, theSm, notFromGroups);
8569 const SMDS_MeshElement* NewElem = 0;
8575 NewElem = theHelper.AddEdge(aNds[0], aNds[1], id, theForce3d);
8583 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8586 NewElem = theHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8593 case SMDSAbs_Volume :
8598 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8601 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], id, theForce3d);
8604 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3], aNds[4], aNds[5], id, theForce3d);
8607 NewElem = theHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8608 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8618 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
8620 theSm->AddElement( NewElem );
8625 //=======================================================================
8626 //function : ConvertToQuadratic
8628 //=======================================================================
8629 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
8631 SMESHDS_Mesh* meshDS = GetMeshDS();
8633 SMESH_MesherHelper aHelper(*myMesh);
8634 aHelper.SetIsQuadratic( true );
8635 const bool notFromGroups = false;
8637 int nbCheckedElems = 0;
8638 if ( myMesh->HasShapeToMesh() )
8640 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8642 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8643 while ( smIt->more() ) {
8644 SMESH_subMesh* sm = smIt->next();
8645 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
8646 aHelper.SetSubShape( sm->GetSubShape() );
8647 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
8652 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
8653 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8655 SMESHDS_SubMesh *smDS = 0;
8656 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
8657 while(aEdgeItr->more())
8659 const SMDS_MeshEdge* edge = aEdgeItr->next();
8660 if(edge && !edge->IsQuadratic())
8662 int id = edge->GetID();
8663 const SMDS_MeshNode* n1 = edge->GetNode(0);
8664 const SMDS_MeshNode* n2 = edge->GetNode(1);
8666 meshDS->RemoveFreeElement(edge, smDS, notFromGroups);
8668 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
8669 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
8672 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
8673 while(aFaceItr->more())
8675 const SMDS_MeshFace* face = aFaceItr->next();
8676 if(!face || face->IsQuadratic() ) continue;
8678 int id = face->GetID();
8679 int nbNodes = face->NbNodes();
8680 vector<const SMDS_MeshNode *> aNds (nbNodes);
8682 for(int i = 0; i < nbNodes; i++)
8684 aNds[i] = face->GetNode(i);
8687 meshDS->RemoveFreeElement(face, smDS, notFromGroups);
8689 SMDS_MeshFace * NewFace = 0;
8693 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], id, theForce3d);
8696 NewFace = aHelper.AddFace(aNds[0], aNds[1], aNds[2], aNds[3], id, theForce3d);
8701 ReplaceElemInGroups( face, NewFace, GetMeshDS());
8703 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
8704 while(aVolumeItr->more())
8706 const SMDS_MeshVolume* volume = aVolumeItr->next();
8707 if(!volume || volume->IsQuadratic() ) continue;
8709 int id = volume->GetID();
8710 int nbNodes = volume->NbNodes();
8711 vector<const SMDS_MeshNode *> aNds (nbNodes);
8713 for(int i = 0; i < nbNodes; i++)
8715 aNds[i] = volume->GetNode(i);
8718 meshDS->RemoveFreeElement(volume, smDS, notFromGroups);
8720 SMDS_MeshVolume * NewVolume = 0;
8724 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8725 aNds[3], id, theForce3d );
8728 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8729 aNds[3], aNds[4], id, theForce3d);
8732 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2],
8733 aNds[3], aNds[4], aNds[5], id, theForce3d);
8736 NewVolume = aHelper.AddVolume(aNds[0], aNds[1], aNds[2], aNds[3],
8737 aNds[4], aNds[5], aNds[6], aNds[7], id, theForce3d);
8742 ReplaceElemInGroups(volume, NewVolume, meshDS);
8745 if ( !theForce3d ) {
8746 aHelper.SetSubShape(0); // apply to the whole mesh
8747 aHelper.FixQuadraticElements();
8751 //=======================================================================
8753 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
8754 * \retval int - nb of checked elements
8756 //=======================================================================
8758 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
8759 SMDS_ElemIteratorPtr theItr,
8760 const int theShapeID)
8763 SMESHDS_Mesh* meshDS = GetMeshDS();
8764 const bool notFromGroups = false;
8766 while( theItr->more() )
8768 const SMDS_MeshElement* elem = theItr->next();
8770 if( elem && elem->IsQuadratic())
8772 int id = elem->GetID();
8773 int nbNodes = elem->NbNodes();
8774 vector<const SMDS_MeshNode *> aNds, mediumNodes;
8775 aNds.reserve( nbNodes );
8776 mediumNodes.reserve( nbNodes );
8778 for(int i = 0; i < nbNodes; i++)
8780 const SMDS_MeshNode* n = elem->GetNode(i);
8782 if( elem->IsMediumNode( n ) )
8783 mediumNodes.push_back( n );
8785 aNds.push_back( n );
8787 if( aNds.empty() ) continue;
8788 SMDSAbs_ElementType aType = elem->GetType();
8790 //remove old quadratic element
8791 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
8793 SMDS_MeshElement * NewElem = AddElement( aNds, aType, false, id );
8794 ReplaceElemInGroups(elem, NewElem, meshDS);
8795 if( theSm && NewElem )
8796 theSm->AddElement( NewElem );
8798 // remove medium nodes
8799 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
8800 for ( ; nIt != mediumNodes.end(); ++nIt ) {
8801 const SMDS_MeshNode* n = *nIt;
8802 if ( n->NbInverseElements() == 0 ) {
8803 if ( n->GetPosition()->GetShapeId() != theShapeID )
8804 meshDS->RemoveFreeNode( n, meshDS->MeshElements
8805 ( n->GetPosition()->GetShapeId() ));
8807 meshDS->RemoveFreeNode( n, theSm );
8815 //=======================================================================
8816 //function : ConvertFromQuadratic
8818 //=======================================================================
8819 bool SMESH_MeshEditor::ConvertFromQuadratic()
8821 int nbCheckedElems = 0;
8822 if ( myMesh->HasShapeToMesh() )
8824 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
8826 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
8827 while ( smIt->more() ) {
8828 SMESH_subMesh* sm = smIt->next();
8829 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
8830 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
8836 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
8837 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
8839 SMESHDS_SubMesh *aSM = 0;
8840 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
8846 //=======================================================================
8847 //function : SewSideElements
8849 //=======================================================================
8851 SMESH_MeshEditor::Sew_Error
8852 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
8853 TIDSortedElemSet& theSide2,
8854 const SMDS_MeshNode* theFirstNode1,
8855 const SMDS_MeshNode* theFirstNode2,
8856 const SMDS_MeshNode* theSecondNode1,
8857 const SMDS_MeshNode* theSecondNode2)
8859 myLastCreatedElems.Clear();
8860 myLastCreatedNodes.Clear();
8862 MESSAGE ("::::SewSideElements()");
8863 if ( theSide1.size() != theSide2.size() )
8864 return SEW_DIFF_NB_OF_ELEMENTS;
8866 Sew_Error aResult = SEW_OK;
8868 // 1. Build set of faces representing each side
8869 // 2. Find which nodes of the side 1 to merge with ones on the side 2
8870 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
8872 // =======================================================================
8873 // 1. Build set of faces representing each side:
8874 // =======================================================================
8875 // a. build set of nodes belonging to faces
8876 // b. complete set of faces: find missing fices whose nodes are in set of nodes
8877 // c. create temporary faces representing side of volumes if correspondent
8878 // face does not exist
8880 SMESHDS_Mesh* aMesh = GetMeshDS();
8881 SMDS_Mesh aTmpFacesMesh;
8882 set<const SMDS_MeshElement*> faceSet1, faceSet2;
8883 set<const SMDS_MeshElement*> volSet1, volSet2;
8884 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
8885 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
8886 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
8887 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
8888 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
8889 int iSide, iFace, iNode;
8891 for ( iSide = 0; iSide < 2; iSide++ ) {
8892 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
8893 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
8894 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
8895 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
8896 set<const SMDS_MeshElement*>::iterator vIt;
8897 TIDSortedElemSet::iterator eIt;
8898 set<const SMDS_MeshNode*>::iterator nIt;
8900 // check that given nodes belong to given elements
8901 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
8902 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
8903 int firstIndex = -1, secondIndex = -1;
8904 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8905 const SMDS_MeshElement* elem = *eIt;
8906 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
8907 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
8908 if ( firstIndex > -1 && secondIndex > -1 ) break;
8910 if ( firstIndex < 0 || secondIndex < 0 ) {
8911 // we can simply return until temporary faces created
8912 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
8915 // -----------------------------------------------------------
8916 // 1a. Collect nodes of existing faces
8917 // and build set of face nodes in order to detect missing
8918 // faces corresponing to sides of volumes
8919 // -----------------------------------------------------------
8921 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
8923 // loop on the given element of a side
8924 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
8925 //const SMDS_MeshElement* elem = *eIt;
8926 const SMDS_MeshElement* elem = *eIt;
8927 if ( elem->GetType() == SMDSAbs_Face ) {
8928 faceSet->insert( elem );
8929 set <const SMDS_MeshNode*> faceNodeSet;
8930 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
8931 while ( nodeIt->more() ) {
8932 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8933 nodeSet->insert( n );
8934 faceNodeSet.insert( n );
8936 setOfFaceNodeSet.insert( faceNodeSet );
8938 else if ( elem->GetType() == SMDSAbs_Volume )
8939 volSet->insert( elem );
8941 // ------------------------------------------------------------------------------
8942 // 1b. Complete set of faces: find missing fices whose nodes are in set of nodes
8943 // ------------------------------------------------------------------------------
8945 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
8946 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
8947 while ( fIt->more() ) { // loop on faces sharing a node
8948 const SMDS_MeshElement* f = fIt->next();
8949 if ( faceSet->find( f ) == faceSet->end() ) {
8950 // check if all nodes are in nodeSet and
8951 // complete setOfFaceNodeSet if they are
8952 set <const SMDS_MeshNode*> faceNodeSet;
8953 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
8954 bool allInSet = true;
8955 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
8956 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8957 if ( nodeSet->find( n ) == nodeSet->end() )
8960 faceNodeSet.insert( n );
8963 faceSet->insert( f );
8964 setOfFaceNodeSet.insert( faceNodeSet );
8970 // -------------------------------------------------------------------------
8971 // 1c. Create temporary faces representing sides of volumes if correspondent
8972 // face does not exist
8973 // -------------------------------------------------------------------------
8975 if ( !volSet->empty() ) {
8976 //int nodeSetSize = nodeSet->size();
8978 // loop on given volumes
8979 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
8980 SMDS_VolumeTool vol (*vIt);
8981 // loop on volume faces: find free faces
8982 // --------------------------------------
8983 list<const SMDS_MeshElement* > freeFaceList;
8984 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
8985 if ( !vol.IsFreeFace( iFace ))
8987 // check if there is already a face with same nodes in a face set
8988 const SMDS_MeshElement* aFreeFace = 0;
8989 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
8990 int nbNodes = vol.NbFaceNodes( iFace );
8991 set <const SMDS_MeshNode*> faceNodeSet;
8992 vol.GetFaceNodes( iFace, faceNodeSet );
8993 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
8995 // no such a face is given but it still can exist, check it
8996 if ( nbNodes == 3 ) {
8997 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
8999 else if ( nbNodes == 4 ) {
9000 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9003 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9004 aFreeFace = aMesh->FindFace(poly_nodes);
9008 // create a temporary face
9009 if ( nbNodes == 3 ) {
9010 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9012 else if ( nbNodes == 4 ) {
9013 aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9016 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9017 aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9021 freeFaceList.push_back( aFreeFace );
9023 } // loop on faces of a volume
9025 // choose one of several free faces
9026 // --------------------------------------
9027 if ( freeFaceList.size() > 1 ) {
9028 // choose a face having max nb of nodes shared by other elems of a side
9029 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9030 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9031 while ( fIt != freeFaceList.end() ) { // loop on free faces
9032 int nbSharedNodes = 0;
9033 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9034 while ( nodeIt->more() ) { // loop on free face nodes
9035 const SMDS_MeshNode* n =
9036 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9037 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9038 while ( invElemIt->more() ) {
9039 const SMDS_MeshElement* e = invElemIt->next();
9040 if ( faceSet->find( e ) != faceSet->end() )
9042 if ( elemSet->find( e ) != elemSet->end() )
9046 if ( nbSharedNodes >= maxNbNodes ) {
9047 maxNbNodes = nbSharedNodes;
9051 freeFaceList.erase( fIt++ ); // here fIt++ occures before erase
9053 if ( freeFaceList.size() > 1 )
9055 // could not choose one face, use another way
9056 // choose a face most close to the bary center of the opposite side
9057 gp_XYZ aBC( 0., 0., 0. );
9058 set <const SMDS_MeshNode*> addedNodes;
9059 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9060 eIt = elemSet2->begin();
9061 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9062 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9063 while ( nodeIt->more() ) { // loop on free face nodes
9064 const SMDS_MeshNode* n =
9065 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9066 if ( addedNodes.insert( n ).second )
9067 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9070 aBC /= addedNodes.size();
9071 double minDist = DBL_MAX;
9072 fIt = freeFaceList.begin();
9073 while ( fIt != freeFaceList.end() ) { // loop on free faces
9075 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9076 while ( nodeIt->more() ) { // loop on free face nodes
9077 const SMDS_MeshNode* n =
9078 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9079 gp_XYZ p( n->X(),n->Y(),n->Z() );
9080 dist += ( aBC - p ).SquareModulus();
9082 if ( dist < minDist ) {
9084 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9087 fIt = freeFaceList.erase( fIt++ );
9090 } // choose one of several free faces of a volume
9092 if ( freeFaceList.size() == 1 ) {
9093 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9094 faceSet->insert( aFreeFace );
9095 // complete a node set with nodes of a found free face
9096 // for ( iNode = 0; iNode < ; iNode++ )
9097 // nodeSet->insert( fNodes[ iNode ] );
9100 } // loop on volumes of a side
9102 // // complete a set of faces if new nodes in a nodeSet appeared
9103 // // ----------------------------------------------------------
9104 // if ( nodeSetSize != nodeSet->size() ) {
9105 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9106 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9107 // while ( fIt->more() ) { // loop on faces sharing a node
9108 // const SMDS_MeshElement* f = fIt->next();
9109 // if ( faceSet->find( f ) == faceSet->end() ) {
9110 // // check if all nodes are in nodeSet and
9111 // // complete setOfFaceNodeSet if they are
9112 // set <const SMDS_MeshNode*> faceNodeSet;
9113 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9114 // bool allInSet = true;
9115 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9116 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9117 // if ( nodeSet->find( n ) == nodeSet->end() )
9118 // allInSet = false;
9120 // faceNodeSet.insert( n );
9122 // if ( allInSet ) {
9123 // faceSet->insert( f );
9124 // setOfFaceNodeSet.insert( faceNodeSet );
9130 } // Create temporary faces, if there are volumes given
9133 if ( faceSet1.size() != faceSet2.size() ) {
9134 // delete temporary faces: they are in reverseElements of actual nodes
9135 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9136 while ( tmpFaceIt->more() )
9137 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9138 MESSAGE("Diff nb of faces");
9139 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9142 // ============================================================
9143 // 2. Find nodes to merge:
9144 // bind a node to remove to a node to put instead
9145 // ============================================================
9147 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9148 if ( theFirstNode1 != theFirstNode2 )
9149 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9150 if ( theSecondNode1 != theSecondNode2 )
9151 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9153 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9154 set< long > linkIdSet; // links to process
9155 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9157 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9158 list< NLink > linkList[2];
9159 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9160 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9161 // loop on links in linkList; find faces by links and append links
9162 // of the found faces to linkList
9163 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9164 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9165 NLink link[] = { *linkIt[0], *linkIt[1] };
9166 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9167 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9170 // by links, find faces in the face sets,
9171 // and find indices of link nodes in the found faces;
9172 // in a face set, there is only one or no face sharing a link
9173 // ---------------------------------------------------------------
9175 const SMDS_MeshElement* face[] = { 0, 0 };
9176 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9177 vector<const SMDS_MeshNode*> fnodes1(9);
9178 vector<const SMDS_MeshNode*> fnodes2(9);
9179 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9180 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9181 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9182 int iLinkNode[2][2];
9183 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9184 const SMDS_MeshNode* n1 = link[iSide].first;
9185 const SMDS_MeshNode* n2 = link[iSide].second;
9186 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9187 set< const SMDS_MeshElement* > fMap;
9188 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9189 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9190 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9191 while ( fIt->more() ) { // loop on faces sharing a node
9192 const SMDS_MeshElement* f = fIt->next();
9193 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9194 ! fMap.insert( f ).second ) // f encounters twice
9196 if ( face[ iSide ] ) {
9197 MESSAGE( "2 faces per link " );
9198 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9202 faceSet->erase( f );
9203 // get face nodes and find ones of a link
9208 fnodes1.resize(f->NbNodes()+1);
9209 notLinkNodes1.resize(f->NbNodes()-2);
9212 fnodes2.resize(f->NbNodes()+1);
9213 notLinkNodes2.resize(f->NbNodes()-2);
9216 if(!f->IsQuadratic()) {
9217 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9218 while ( nIt->more() ) {
9219 const SMDS_MeshNode* n =
9220 static_cast<const SMDS_MeshNode*>( nIt->next() );
9222 iLinkNode[ iSide ][ 0 ] = iNode;
9224 else if ( n == n2 ) {
9225 iLinkNode[ iSide ][ 1 ] = iNode;
9227 //else if ( notLinkNodes[ iSide ][ 0 ] )
9228 // notLinkNodes[ iSide ][ 1 ] = n;
9230 // notLinkNodes[ iSide ][ 0 ] = n;
9234 notLinkNodes1[nbl] = n;
9235 //notLinkNodes1.push_back(n);
9237 notLinkNodes2[nbl] = n;
9238 //notLinkNodes2.push_back(n);
9240 //faceNodes[ iSide ][ iNode++ ] = n;
9242 fnodes1[iNode++] = n;
9245 fnodes2[iNode++] = n;
9249 else { // f->IsQuadratic()
9250 const SMDS_QuadraticFaceOfNodes* F =
9251 static_cast<const SMDS_QuadraticFaceOfNodes*>(f);
9252 // use special nodes iterator
9253 SMDS_NodeIteratorPtr anIter = F->interlacedNodesIterator();
9254 while ( anIter->more() ) {
9255 const SMDS_MeshNode* n =
9256 static_cast<const SMDS_MeshNode*>( anIter->next() );
9258 iLinkNode[ iSide ][ 0 ] = iNode;
9260 else if ( n == n2 ) {
9261 iLinkNode[ iSide ][ 1 ] = iNode;
9266 notLinkNodes1[nbl] = n;
9269 notLinkNodes2[nbl] = n;
9273 fnodes1[iNode++] = n;
9276 fnodes2[iNode++] = n;
9280 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9282 fnodes1[iNode] = fnodes1[0];
9285 fnodes2[iNode] = fnodes1[0];
9292 // check similarity of elements of the sides
9293 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9294 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9295 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9296 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9299 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9301 break; // do not return because it s necessary to remove tmp faces
9304 // set nodes to merge
9305 // -------------------
9307 if ( face[0] && face[1] ) {
9308 int nbNodes = face[0]->NbNodes();
9309 if ( nbNodes != face[1]->NbNodes() ) {
9310 MESSAGE("Diff nb of face nodes");
9311 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9312 break; // do not return because it s necessary to remove tmp faces
9314 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9315 if ( nbNodes == 3 ) {
9316 //nReplaceMap.insert( TNodeNodeMap::value_type
9317 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9318 nReplaceMap.insert( TNodeNodeMap::value_type
9319 ( notLinkNodes1[0], notLinkNodes2[0] ));
9322 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9323 // analyse link orientation in faces
9324 int i1 = iLinkNode[ iSide ][ 0 ];
9325 int i2 = iLinkNode[ iSide ][ 1 ];
9326 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9327 // if notLinkNodes are the first and the last ones, then
9328 // their order does not correspond to the link orientation
9329 if (( i1 == 1 && i2 == 2 ) ||
9330 ( i1 == 2 && i2 == 1 ))
9331 reverse[ iSide ] = !reverse[ iSide ];
9333 if ( reverse[0] == reverse[1] ) {
9334 //nReplaceMap.insert( TNodeNodeMap::value_type
9335 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9336 //nReplaceMap.insert( TNodeNodeMap::value_type
9337 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9338 for(int nn=0; nn<nbNodes-2; nn++) {
9339 nReplaceMap.insert( TNodeNodeMap::value_type
9340 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9344 //nReplaceMap.insert( TNodeNodeMap::value_type
9345 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9346 //nReplaceMap.insert( TNodeNodeMap::value_type
9347 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9348 for(int nn=0; nn<nbNodes-2; nn++) {
9349 nReplaceMap.insert( TNodeNodeMap::value_type
9350 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9355 // add other links of the faces to linkList
9356 // -----------------------------------------
9358 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9359 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9360 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9361 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9362 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9363 if ( !iter_isnew.second ) { // already in a set: no need to process
9364 linkIdSet.erase( iter_isnew.first );
9366 else // new in set == encountered for the first time: add
9368 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9369 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9370 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9371 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9372 linkList[0].push_back ( NLink( n1, n2 ));
9373 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9377 } // loop on link lists
9379 if ( aResult == SEW_OK &&
9380 ( linkIt[0] != linkList[0].end() ||
9381 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9382 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9383 " " << (faceSetPtr[1]->empty()));
9384 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9387 // ====================================================================
9388 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9389 // ====================================================================
9391 // delete temporary faces: they are in reverseElements of actual nodes
9392 SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9393 while ( tmpFaceIt->more() )
9394 aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9396 if ( aResult != SEW_OK)
9399 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
9400 // loop on nodes replacement map
9401 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
9402 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
9403 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
9404 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
9405 nodeIDsToRemove.push_back( nToRemove->GetID() );
9406 // loop on elements sharing nToRemove
9407 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
9408 while ( invElemIt->more() ) {
9409 const SMDS_MeshElement* e = invElemIt->next();
9410 // get a new suite of nodes: make replacement
9411 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
9412 vector< const SMDS_MeshNode*> nodes( nbNodes );
9413 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
9414 while ( nIt->more() ) {
9415 const SMDS_MeshNode* n =
9416 static_cast<const SMDS_MeshNode*>( nIt->next() );
9417 nnIt = nReplaceMap.find( n );
9418 if ( nnIt != nReplaceMap.end() ) {
9424 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
9425 // elemIDsToRemove.push_back( e->GetID() );
9428 aMesh->ChangeElementNodes( e, & nodes[0], nbNodes );
9432 Remove( nodeIDsToRemove, true );
9437 //================================================================================
9439 * \brief Find corresponding nodes in two sets of faces
9440 * \param theSide1 - first face set
9441 * \param theSide2 - second first face
9442 * \param theFirstNode1 - a boundary node of set 1
9443 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
9444 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
9445 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
9446 * \param nReplaceMap - output map of corresponding nodes
9447 * \retval bool - is a success or not
9449 //================================================================================
9452 //#define DEBUG_MATCHING_NODES
9455 SMESH_MeshEditor::Sew_Error
9456 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
9457 set<const SMDS_MeshElement*>& theSide2,
9458 const SMDS_MeshNode* theFirstNode1,
9459 const SMDS_MeshNode* theFirstNode2,
9460 const SMDS_MeshNode* theSecondNode1,
9461 const SMDS_MeshNode* theSecondNode2,
9462 TNodeNodeMap & nReplaceMap)
9464 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
9466 nReplaceMap.clear();
9467 if ( theFirstNode1 != theFirstNode2 )
9468 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
9469 if ( theSecondNode1 != theSecondNode2 )
9470 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
9472 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
9473 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
9475 list< NLink > linkList[2];
9476 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9477 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9479 // loop on links in linkList; find faces by links and append links
9480 // of the found faces to linkList
9481 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9482 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9483 NLink link[] = { *linkIt[0], *linkIt[1] };
9484 if ( linkSet.find( link[0] ) == linkSet.end() )
9487 // by links, find faces in the face sets,
9488 // and find indices of link nodes in the found faces;
9489 // in a face set, there is only one or no face sharing a link
9490 // ---------------------------------------------------------------
9492 const SMDS_MeshElement* face[] = { 0, 0 };
9493 list<const SMDS_MeshNode*> notLinkNodes[2];
9494 //bool reverse[] = { false, false }; // order of notLinkNodes
9496 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
9498 const SMDS_MeshNode* n1 = link[iSide].first;
9499 const SMDS_MeshNode* n2 = link[iSide].second;
9500 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9501 set< const SMDS_MeshElement* > facesOfNode1;
9502 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
9504 // during a loop of the first node, we find all faces around n1,
9505 // during a loop of the second node, we find one face sharing both n1 and n2
9506 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
9507 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9508 while ( fIt->more() ) { // loop on faces sharing a node
9509 const SMDS_MeshElement* f = fIt->next();
9510 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9511 ! facesOfNode1.insert( f ).second ) // f encounters twice
9513 if ( face[ iSide ] ) {
9514 MESSAGE( "2 faces per link " );
9515 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9518 faceSet->erase( f );
9520 // get not link nodes
9521 int nbN = f->NbNodes();
9522 if ( f->IsQuadratic() )
9524 nbNodes[ iSide ] = nbN;
9525 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
9526 int i1 = f->GetNodeIndex( n1 );
9527 int i2 = f->GetNodeIndex( n2 );
9528 int iEnd = nbN, iBeg = -1, iDelta = 1;
9529 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
9531 std::swap( iEnd, iBeg ); iDelta = -1;
9536 if ( i == iEnd ) i = iBeg + iDelta;
9537 if ( i == i1 ) break;
9538 nodes.push_back ( f->GetNode( i ) );
9544 // check similarity of elements of the sides
9545 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9546 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9547 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9548 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9551 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9555 // set nodes to merge
9556 // -------------------
9558 if ( face[0] && face[1] ) {
9559 if ( nbNodes[0] != nbNodes[1] ) {
9560 MESSAGE("Diff nb of face nodes");
9561 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9563 #ifdef DEBUG_MATCHING_NODES
9564 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
9565 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
9566 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
9568 int nbN = nbNodes[0];
9570 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
9571 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
9572 for ( int i = 0 ; i < nbN - 2; ++i ) {
9573 #ifdef DEBUG_MATCHING_NODES
9574 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
9576 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
9580 // add other links of the face 1 to linkList
9581 // -----------------------------------------
9583 const SMDS_MeshElement* f0 = face[0];
9584 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
9585 for ( int i = 0; i < nbN; i++ )
9587 const SMDS_MeshNode* n2 = f0->GetNode( i );
9588 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
9589 linkSet.insert( SMESH_TLink( n1, n2 ));
9590 if ( !iter_isnew.second ) { // already in a set: no need to process
9591 linkSet.erase( iter_isnew.first );
9593 else // new in set == encountered for the first time: add
9595 #ifdef DEBUG_MATCHING_NODES
9596 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
9597 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
9599 linkList[0].push_back ( NLink( n1, n2 ));
9600 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9605 } // loop on link lists
9610 //================================================================================
9612 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9613 \param theElems - the list of elements (edges or faces) to be replicated
9614 The nodes for duplication could be found from these elements
9615 \param theNodesNot - list of nodes to NOT replicate
9616 \param theAffectedElems - the list of elements (cells and edges) to which the
9617 replicated nodes should be associated to.
9618 \return TRUE if operation has been completed successfully, FALSE otherwise
9620 //================================================================================
9622 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
9623 const TIDSortedElemSet& theNodesNot,
9624 const TIDSortedElemSet& theAffectedElems )
9626 myLastCreatedElems.Clear();
9627 myLastCreatedNodes.Clear();
9629 if ( theElems.size() == 0 )
9632 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9637 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9638 // duplicate elements and nodes
9639 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
9640 // replce nodes by duplications
9641 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
9645 //================================================================================
9647 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9648 \param theMeshDS - mesh instance
9649 \param theElems - the elements replicated or modified (nodes should be changed)
9650 \param theNodesNot - nodes to NOT replicate
9651 \param theNodeNodeMap - relation of old node to new created node
9652 \param theIsDoubleElem - flag os to replicate element or modify
9653 \return TRUE if operation has been completed successfully, FALSE otherwise
9655 //================================================================================
9657 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
9658 const TIDSortedElemSet& theElems,
9659 const TIDSortedElemSet& theNodesNot,
9660 std::map< const SMDS_MeshNode*,
9661 const SMDS_MeshNode* >& theNodeNodeMap,
9662 const bool theIsDoubleElem )
9664 // iterate on through element and duplicate them (by nodes duplication)
9666 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9667 for ( ; elemItr != theElems.end(); ++elemItr )
9669 const SMDS_MeshElement* anElem = *elemItr;
9673 bool isDuplicate = false;
9674 // duplicate nodes to duplicate element
9675 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
9676 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9678 while ( anIter->more() )
9681 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9682 SMDS_MeshNode* aNewNode = aCurrNode;
9683 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
9684 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
9685 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
9688 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
9689 theNodeNodeMap[ aCurrNode ] = aNewNode;
9690 myLastCreatedNodes.Append( aNewNode );
9692 isDuplicate |= (aCurrNode != aNewNode);
9693 newNodes[ ind++ ] = aNewNode;
9698 if ( theIsDoubleElem )
9699 myLastCreatedElems.Append( AddElement(newNodes, anElem->GetType(), anElem->IsPoly()) );
9701 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
9708 //================================================================================
9710 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9711 \param theNodes - identifiers of nodes to be doubled
9712 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
9713 nodes. If list of element identifiers is empty then nodes are doubled but
9714 they not assigned to elements
9715 \return TRUE if operation has been completed successfully, FALSE otherwise
9717 //================================================================================
9719 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
9720 const std::list< int >& theListOfModifiedElems )
9722 myLastCreatedElems.Clear();
9723 myLastCreatedNodes.Clear();
9725 if ( theListOfNodes.size() == 0 )
9728 SMESHDS_Mesh* aMeshDS = GetMeshDS();
9732 // iterate through nodes and duplicate them
9734 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
9736 std::list< int >::const_iterator aNodeIter;
9737 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
9739 int aCurr = *aNodeIter;
9740 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
9746 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
9749 anOldNodeToNewNode[ aNode ] = aNewNode;
9750 myLastCreatedNodes.Append( aNewNode );
9754 // Create map of new nodes for modified elements
9756 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
9758 std::list< int >::const_iterator anElemIter;
9759 for ( anElemIter = theListOfModifiedElems.begin();
9760 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
9762 int aCurr = *anElemIter;
9763 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
9767 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
9769 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
9771 while ( anIter->more() )
9773 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
9774 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
9776 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
9777 aNodeArr[ ind++ ] = aNewNode;
9780 aNodeArr[ ind++ ] = aCurrNode;
9782 anElemToNodes[ anElem ] = aNodeArr;
9785 // Change nodes of elements
9787 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
9788 anElemToNodesIter = anElemToNodes.begin();
9789 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
9791 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
9792 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
9794 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
9802 //================================================================================
9804 \brief Check if element located inside shape
9805 \return TRUE if IN or ON shape, FALSE otherwise
9807 //================================================================================
9809 template<class Classifier>
9810 bool isInside(const SMDS_MeshElement* theElem,
9811 Classifier& theClassifier,
9812 const double theTol)
9814 gp_XYZ centerXYZ (0, 0, 0);
9815 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
9816 while (aNodeItr->more())
9817 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
9819 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
9820 theClassifier.Perform(aPnt, theTol);
9821 TopAbs_State aState = theClassifier.State();
9822 return (aState == TopAbs_IN || aState == TopAbs_ON );
9825 //================================================================================
9827 * \brief Classifier of the 3D point on the TopoDS_Face
9828 * with interaface suitable for isInside()
9830 //================================================================================
9832 struct _FaceClassifier
9834 Extrema_ExtPS _extremum;
9835 BRepAdaptor_Surface _surface;
9836 TopAbs_State _state;
9838 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
9840 _extremum.Initialize( _surface,
9841 _surface.FirstUParameter(), _surface.LastUParameter(),
9842 _surface.FirstVParameter(), _surface.LastVParameter(),
9843 _surface.Tolerance(), _surface.Tolerance() );
9845 void Perform(const gp_Pnt& aPnt, double theTol)
9847 _state = TopAbs_OUT;
9848 _extremum.Perform(aPnt);
9849 if ( _extremum.IsDone() )
9850 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
9851 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
9853 TopAbs_State State() const
9860 //================================================================================
9862 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
9863 \param theElems - group of of elements (edges or faces) to be replicated
9864 \param theNodesNot - group of nodes not to replicate
9865 \param theShape - shape to detect affected elements (element which geometric center
9866 located on or inside shape).
9867 The replicated nodes should be associated to affected elements.
9868 \return TRUE if operation has been completed successfully, FALSE otherwise
9870 //================================================================================
9872 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
9873 const TIDSortedElemSet& theNodesNot,
9874 const TopoDS_Shape& theShape )
9876 if ( theShape.IsNull() )
9879 const double aTol = Precision::Confusion();
9880 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
9881 auto_ptr<_FaceClassifier> aFaceClassifier;
9882 if ( theShape.ShapeType() == TopAbs_SOLID )
9884 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
9885 bsc3d->PerformInfinitePoint(aTol);
9887 else if (theShape.ShapeType() == TopAbs_FACE )
9889 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
9892 // iterates on indicated elements and get elements by back references from their nodes
9893 TIDSortedElemSet anAffected;
9894 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
9895 for ( ; elemItr != theElems.end(); ++elemItr )
9897 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
9901 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
9902 while ( nodeItr->more() )
9904 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
9905 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
9907 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
9908 while ( backElemItr->more() )
9910 const SMDS_MeshElement* curElem = backElemItr->next();
9911 if ( curElem && theElems.find(curElem) == theElems.end() &&
9913 isInside( curElem, *bsc3d, aTol ) :
9914 isInside( curElem, *aFaceClassifier, aTol )))
9915 anAffected.insert( curElem );
9919 return DoubleNodes( theElems, theNodesNot, anAffected );
9922 //================================================================================
9924 * \brief Generated skin mesh (containing 2D cells) from 3D mesh
9925 * The created 2D mesh elements based on nodes of free faces of boundary volumes
9926 * \return TRUE if operation has been completed successfully, FALSE otherwise
9928 //================================================================================
9930 bool SMESH_MeshEditor::Make2DMeshFrom3D()
9932 // iterates on volume elements and detect all free faces on them
9933 SMESHDS_Mesh* aMesh = GetMeshDS();
9937 int nbFree = 0, nbExisted = 0, nbCreated = 0;
9938 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
9941 const SMDS_MeshVolume* volume = vIt->next();
9942 SMDS_VolumeTool vTool( volume );
9943 vTool.SetExternalNormal();
9944 const bool isPoly = volume->IsPoly();
9945 const bool isQuad = volume->IsQuadratic();
9946 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
9948 if (!vTool.IsFreeFace(iface))
9951 vector<const SMDS_MeshNode *> nodes;
9952 int nbFaceNodes = vTool.NbFaceNodes(iface);
9953 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
9955 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
9956 nodes.push_back(faceNodes[inode]);
9958 for ( inode = 1; inode < nbFaceNodes; inode += 2)
9959 nodes.push_back(faceNodes[inode]);
9961 // add new face based on volume nodes
9962 if (aMesh->FindFace( nodes ) ) {
9964 continue; // face already exsist
9966 myLastCreatedElems.Append( AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1) );
9970 return ( nbFree==(nbExisted+nbCreated) );