1 // Copyright (C) 2007-2010 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
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
98 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
101 using namespace SMESH::Controls;
103 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
106 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
108 //=======================================================================
109 //function : SMESH_MeshEditor
111 //=======================================================================
113 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
114 :myMesh( theMesh ) // theMesh may be NULL
118 //=======================================================================
122 //=======================================================================
125 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
126 const SMDSAbs_ElementType type,
130 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
131 SMDS_MeshElement* e = 0;
132 int nbnode = node.size();
133 SMESHDS_Mesh* mesh = GetMeshDS();
135 case SMDSAbs_0DElement:
137 if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
138 else e = mesh->Add0DElement (node[0] );
142 if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
143 else e = mesh->AddEdge (node[0], node[1] );
144 else if ( nbnode == 3 )
145 if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
146 else e = mesh->AddEdge (node[0], node[1], node[2] );
151 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
152 else e = mesh->AddFace (node[0], node[1], node[2] );
153 else if (nbnode == 4)
154 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
155 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
156 else if (nbnode == 6)
157 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
158 node[4], node[5], ID);
159 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
161 else if (nbnode == 8)
162 if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
163 node[4], node[5], node[6], node[7], ID);
164 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
165 node[4], node[5], node[6], node[7] );
167 if ( ID >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
168 else e = mesh->AddPolygonalFace (node );
174 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
175 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
176 else if (nbnode == 5)
177 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
181 else if (nbnode == 6)
182 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
183 node[4], node[5], ID);
184 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
186 else if (nbnode == 8)
187 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
188 node[4], node[5], node[6], node[7], ID);
189 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
190 node[4], node[5], node[6], node[7] );
191 else if (nbnode == 10)
192 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
193 node[4], node[5], node[6], node[7],
194 node[8], node[9], ID);
195 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
196 node[4], node[5], node[6], node[7],
198 else if (nbnode == 13)
199 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
200 node[4], node[5], node[6], node[7],
201 node[8], node[9], node[10],node[11],
203 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
204 node[4], node[5], node[6], node[7],
205 node[8], node[9], node[10],node[11],
207 else if (nbnode == 15)
208 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209 node[4], node[5], node[6], node[7],
210 node[8], node[9], node[10],node[11],
211 node[12],node[13],node[14],ID);
212 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
213 node[4], node[5], node[6], node[7],
214 node[8], node[9], node[10],node[11],
215 node[12],node[13],node[14] );
216 else if (nbnode == 20)
217 if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218 node[4], node[5], node[6], node[7],
219 node[8], node[9], node[10],node[11],
220 node[12],node[13],node[14],node[15],
221 node[16],node[17],node[18],node[19],ID);
222 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
223 node[4], node[5], node[6], node[7],
224 node[8], node[9], node[10],node[11],
225 node[12],node[13],node[14],node[15],
226 node[16],node[17],node[18],node[19] );
229 if ( e ) myLastCreatedElems.Append( e );
233 //=======================================================================
237 //=======================================================================
239 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
240 const SMDSAbs_ElementType type,
244 vector<const SMDS_MeshNode*> nodes;
245 nodes.reserve( nodeIDs.size() );
246 vector<int>::const_iterator id = nodeIDs.begin();
247 while ( id != nodeIDs.end() ) {
248 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
249 nodes.push_back( node );
253 return AddElement( nodes, type, isPoly, ID );
256 //=======================================================================
258 //purpose : Remove a node or an element.
259 // Modify a compute state of sub-meshes which become empty
260 //=======================================================================
262 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
265 myLastCreatedElems.Clear();
266 myLastCreatedNodes.Clear();
268 SMESHDS_Mesh* aMesh = GetMeshDS();
269 set< SMESH_subMesh *> smmap;
272 list<int>::const_iterator it = theIDs.begin();
273 for ( ; it != theIDs.end(); it++ ) {
274 const SMDS_MeshElement * elem;
276 elem = aMesh->FindNode( *it );
278 elem = aMesh->FindElement( *it );
282 // Notify VERTEX sub-meshes about modification
284 const SMDS_MeshNode* node = cast2Node( elem );
285 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
286 if ( int aShapeID = node->getshapeId() )
287 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
290 // Find sub-meshes to notify about modification
291 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
292 // while ( nodeIt->more() ) {
293 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
294 // const SMDS_PositionPtr& aPosition = node->GetPosition();
295 // if ( aPosition.get() ) {
296 // if ( int aShapeID = aPosition->GetShapeId() ) {
297 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
298 // smmap.insert( sm );
305 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
307 aMesh->RemoveElement( elem );
311 // Notify sub-meshes about modification
312 if ( !smmap.empty() ) {
313 set< SMESH_subMesh *>::iterator smIt;
314 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
315 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
318 // // Check if the whole mesh becomes empty
319 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
320 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
325 //=======================================================================
326 //function : FindShape
327 //purpose : Return an index of the shape theElem is on
328 // or zero if a shape not found
329 //=======================================================================
331 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
333 myLastCreatedElems.Clear();
334 myLastCreatedNodes.Clear();
336 SMESHDS_Mesh * aMesh = GetMeshDS();
337 if ( aMesh->ShapeToMesh().IsNull() )
340 if ( theElem->GetType() == SMDSAbs_Node )
342 int aShapeID = theElem->getshapeId();
349 TopoDS_Shape aShape; // the shape a node is on
350 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
351 while ( nodeIt->more() ) {
352 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
353 int aShapeID = node->getshapeId();
355 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
357 if ( sm->Contains( theElem ))
359 if ( aShape.IsNull() )
360 aShape = aMesh->IndexToShape( aShapeID );
363 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
368 // None of nodes is on a proper shape,
369 // find the shape among ancestors of aShape on which a node is
370 if ( aShape.IsNull() ) {
371 //MESSAGE ("::FindShape() - NONE node is on shape")
374 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
375 for ( ; ancIt.More(); ancIt.Next() ) {
376 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
377 if ( sm && sm->Contains( theElem ))
378 return aMesh->ShapeToIndex( ancIt.Value() );
381 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
385 //=======================================================================
386 //function : IsMedium
388 //=======================================================================
390 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
391 const SMDSAbs_ElementType typeToCheck)
393 bool isMedium = false;
394 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
395 while (it->more() && !isMedium ) {
396 const SMDS_MeshElement* elem = it->next();
397 isMedium = elem->IsMediumNode(node);
402 //=======================================================================
403 //function : ShiftNodesQuadTria
405 // Shift nodes in the array corresponded to quadratic triangle
406 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
407 //=======================================================================
408 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
410 const SMDS_MeshNode* nd1 = aNodes[0];
411 aNodes[0] = aNodes[1];
412 aNodes[1] = aNodes[2];
414 const SMDS_MeshNode* nd2 = aNodes[3];
415 aNodes[3] = aNodes[4];
416 aNodes[4] = aNodes[5];
420 //=======================================================================
421 //function : GetNodesFromTwoTria
423 // Shift nodes in the array corresponded to quadratic triangle
424 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
425 //=======================================================================
426 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
427 const SMDS_MeshElement * theTria2,
428 const SMDS_MeshNode* N1[],
429 const SMDS_MeshNode* N2[])
431 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
434 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
437 if(it->more()) return false;
438 it = theTria2->nodesIterator();
441 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
444 if(it->more()) return false;
446 int sames[3] = {-1,-1,-1};
458 if(nbsames!=2) return false;
460 ShiftNodesQuadTria(N1);
462 ShiftNodesQuadTria(N1);
465 i = sames[0] + sames[1] + sames[2];
467 ShiftNodesQuadTria(N2);
469 // now we receive following N1 and N2 (using numeration as above image)
470 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
471 // i.e. first nodes from both arrays determ new diagonal
475 //=======================================================================
476 //function : InverseDiag
477 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
478 // but having other common link.
479 // Return False if args are improper
480 //=======================================================================
482 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
483 const SMDS_MeshElement * theTria2 )
485 MESSAGE("InverseDiag");
486 myLastCreatedElems.Clear();
487 myLastCreatedNodes.Clear();
489 if (!theTria1 || !theTria2)
492 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
493 if (!F1) return false;
494 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
495 if (!F2) return false;
496 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
497 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
499 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
500 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
504 // put nodes in array and find out indices of the same ones
505 const SMDS_MeshNode* aNodes [6];
506 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
508 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
509 while ( it->more() ) {
510 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
512 if ( i > 2 ) // theTria2
513 // find same node of theTria1
514 for ( int j = 0; j < 3; j++ )
515 if ( aNodes[ i ] == aNodes[ j ]) {
524 return false; // theTria1 is not a triangle
525 it = theTria2->nodesIterator();
527 if ( i == 6 && it->more() )
528 return false; // theTria2 is not a triangle
531 // find indices of 1,2 and of A,B in theTria1
532 int iA = 0, iB = 0, i1 = 0, i2 = 0;
533 for ( i = 0; i < 6; i++ ) {
534 if ( sameInd [ i ] == 0 )
541 // nodes 1 and 2 should not be the same
542 if ( aNodes[ i1 ] == aNodes[ i2 ] )
546 aNodes[ iA ] = aNodes[ i2 ];
548 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
550 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
551 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
555 } // end if(F1 && F2)
557 // check case of quadratic faces
558 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
560 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
564 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
565 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
573 const SMDS_MeshNode* N1 [6];
574 const SMDS_MeshNode* N2 [6];
575 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
577 // now we receive following N1 and N2 (using numeration as above image)
578 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
579 // i.e. first nodes from both arrays determ new diagonal
581 const SMDS_MeshNode* N1new [6];
582 const SMDS_MeshNode* N2new [6];
595 // replaces nodes in faces
596 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
597 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
602 //=======================================================================
603 //function : findTriangles
604 //purpose : find triangles sharing theNode1-theNode2 link
605 //=======================================================================
607 static bool findTriangles(const SMDS_MeshNode * theNode1,
608 const SMDS_MeshNode * theNode2,
609 const SMDS_MeshElement*& theTria1,
610 const SMDS_MeshElement*& theTria2)
612 if ( !theNode1 || !theNode2 ) return false;
614 theTria1 = theTria2 = 0;
616 set< const SMDS_MeshElement* > emap;
617 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
619 const SMDS_MeshElement* elem = it->next();
620 if ( elem->NbNodes() == 3 )
623 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
625 const SMDS_MeshElement* elem = it->next();
626 if ( emap.find( elem ) != emap.end() )
628 // theTria1 must be element with minimum ID
629 if( theTria1->GetID() < elem->GetID() ) {
642 return ( theTria1 && theTria2 );
645 //=======================================================================
646 //function : InverseDiag
647 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
648 // with ones built on the same 4 nodes but having other common link.
649 // Return false if proper faces not found
650 //=======================================================================
652 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
653 const SMDS_MeshNode * theNode2)
655 myLastCreatedElems.Clear();
656 myLastCreatedNodes.Clear();
658 MESSAGE( "::InverseDiag()" );
660 const SMDS_MeshElement *tr1, *tr2;
661 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
664 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
665 if (!F1) return false;
666 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
667 if (!F2) return false;
668 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
669 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
671 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
672 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
676 // put nodes in array
677 // and find indices of 1,2 and of A in tr1 and of B in tr2
678 int i, iA1 = 0, i1 = 0;
679 const SMDS_MeshNode* aNodes1 [3];
680 SMDS_ElemIteratorPtr it;
681 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
682 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
683 if ( aNodes1[ i ] == theNode1 )
684 iA1 = i; // node A in tr1
685 else if ( aNodes1[ i ] != theNode2 )
689 const SMDS_MeshNode* aNodes2 [3];
690 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
691 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
692 if ( aNodes2[ i ] == theNode2 )
693 iB2 = i; // node B in tr2
694 else if ( aNodes2[ i ] != theNode1 )
698 // nodes 1 and 2 should not be the same
699 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
703 aNodes1[ iA1 ] = aNodes2[ i2 ];
705 aNodes2[ iB2 ] = aNodes1[ i1 ];
707 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
708 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
713 // check case of quadratic faces
714 return InverseDiag(tr1,tr2);
717 //=======================================================================
718 //function : getQuadrangleNodes
719 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
720 // fusion of triangles tr1 and tr2 having shared link on
721 // theNode1 and theNode2
722 //=======================================================================
724 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
725 const SMDS_MeshNode * theNode1,
726 const SMDS_MeshNode * theNode2,
727 const SMDS_MeshElement * tr1,
728 const SMDS_MeshElement * tr2 )
730 if( tr1->NbNodes() != tr2->NbNodes() )
732 // find the 4-th node to insert into tr1
733 const SMDS_MeshNode* n4 = 0;
734 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
736 while ( !n4 && i<3 ) {
737 const SMDS_MeshNode * n = cast2Node( it->next() );
739 bool isDiag = ( n == theNode1 || n == theNode2 );
743 // Make an array of nodes to be in a quadrangle
744 int iNode = 0, iFirstDiag = -1;
745 it = tr1->nodesIterator();
748 const SMDS_MeshNode * n = cast2Node( it->next() );
750 bool isDiag = ( n == theNode1 || n == theNode2 );
752 if ( iFirstDiag < 0 )
754 else if ( iNode - iFirstDiag == 1 )
755 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
757 else if ( n == n4 ) {
758 return false; // tr1 and tr2 should not have all the same nodes
760 theQuadNodes[ iNode++ ] = n;
762 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
763 theQuadNodes[ iNode ] = n4;
768 //=======================================================================
769 //function : DeleteDiag
770 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
771 // with a quadrangle built on the same 4 nodes.
772 // Return false if proper faces not found
773 //=======================================================================
775 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
776 const SMDS_MeshNode * theNode2)
778 myLastCreatedElems.Clear();
779 myLastCreatedNodes.Clear();
781 MESSAGE( "::DeleteDiag()" );
783 const SMDS_MeshElement *tr1, *tr2;
784 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
787 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
788 if (!F1) return false;
789 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
790 if (!F2) return false;
791 SMESHDS_Mesh * aMesh = GetMeshDS();
793 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
794 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
796 const SMDS_MeshNode* aNodes [ 4 ];
797 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
800 const SMDS_MeshElement* newElem = 0;
801 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
802 myLastCreatedElems.Append(newElem);
803 AddToSameGroups( newElem, tr1, aMesh );
804 int aShapeId = tr1->getshapeId();
807 aMesh->SetMeshElementOnShape( newElem, aShapeId );
809 aMesh->RemoveElement( tr1 );
810 aMesh->RemoveElement( tr2 );
815 // check case of quadratic faces
816 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
818 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
822 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
823 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
831 const SMDS_MeshNode* N1 [6];
832 const SMDS_MeshNode* N2 [6];
833 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
835 // now we receive following N1 and N2 (using numeration as above image)
836 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
837 // i.e. first nodes from both arrays determ new diagonal
839 const SMDS_MeshNode* aNodes[8];
849 const SMDS_MeshElement* newElem = 0;
850 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
851 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
852 myLastCreatedElems.Append(newElem);
853 AddToSameGroups( newElem, tr1, aMesh );
854 int aShapeId = tr1->getshapeId();
857 aMesh->SetMeshElementOnShape( newElem, aShapeId );
859 aMesh->RemoveElement( tr1 );
860 aMesh->RemoveElement( tr2 );
862 // remove middle node (9)
863 GetMeshDS()->RemoveNode( N1[4] );
868 //=======================================================================
869 //function : Reorient
870 //purpose : Reverse theElement orientation
871 //=======================================================================
873 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
876 myLastCreatedElems.Clear();
877 myLastCreatedNodes.Clear();
881 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
882 if ( !it || !it->more() )
885 switch ( theElem->GetType() ) {
889 if(!theElem->IsQuadratic()) {
890 int i = theElem->NbNodes();
891 vector<const SMDS_MeshNode*> aNodes( i );
893 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
894 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
897 // quadratic elements
898 if(theElem->GetType()==SMDSAbs_Edge) {
899 vector<const SMDS_MeshNode*> aNodes(3);
900 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
901 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
902 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
903 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
906 int nbn = theElem->NbNodes();
907 vector<const SMDS_MeshNode*> aNodes(nbn);
908 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
910 for(; i<nbn/2; i++) {
911 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
913 for(i=0; i<nbn/2; i++) {
914 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
916 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
920 case SMDSAbs_Volume: {
921 if (theElem->IsPoly()) {
922 // TODO reorient vtk polyhedron
923 MESSAGE("reorient vtk polyhedron ?");
924 const SMDS_VtkVolume* aPolyedre =
925 dynamic_cast<const SMDS_VtkVolume*>( theElem );
927 MESSAGE("Warning: bad volumic element");
931 int nbFaces = aPolyedre->NbFaces();
932 vector<const SMDS_MeshNode *> poly_nodes;
933 vector<int> quantities (nbFaces);
935 // reverse each face of the polyedre
936 for (int iface = 1; iface <= nbFaces; iface++) {
937 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
938 quantities[iface - 1] = nbFaceNodes;
940 for (inode = nbFaceNodes; inode >= 1; inode--) {
941 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
942 poly_nodes.push_back(curNode);
946 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
950 SMDS_VolumeTool vTool;
951 if ( !vTool.Set( theElem ))
954 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
955 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
964 //=======================================================================
965 //function : getBadRate
967 //=======================================================================
969 static double getBadRate (const SMDS_MeshElement* theElem,
970 SMESH::Controls::NumericalFunctorPtr& theCrit)
972 SMESH::Controls::TSequenceOfXYZ P;
973 if ( !theElem || !theCrit->GetPoints( theElem, P ))
975 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
976 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
979 //=======================================================================
980 //function : QuadToTri
981 //purpose : Cut quadrangles into triangles.
982 // theCrit is used to select a diagonal to cut
983 //=======================================================================
985 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
986 SMESH::Controls::NumericalFunctorPtr theCrit)
988 myLastCreatedElems.Clear();
989 myLastCreatedNodes.Clear();
991 MESSAGE( "::QuadToTri()" );
993 if ( !theCrit.get() )
996 SMESHDS_Mesh * aMesh = GetMeshDS();
998 Handle(Geom_Surface) surface;
999 SMESH_MesherHelper helper( *GetMesh() );
1001 TIDSortedElemSet::iterator itElem;
1002 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1003 const SMDS_MeshElement* elem = *itElem;
1004 if ( !elem || elem->GetType() != SMDSAbs_Face )
1006 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1009 // retrieve element nodes
1010 const SMDS_MeshNode* aNodes [8];
1011 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1013 while ( itN->more() )
1014 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1016 // compare two sets of possible triangles
1017 double aBadRate1, aBadRate2; // to what extent a set is bad
1018 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1019 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1020 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1022 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1023 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1024 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1026 int aShapeId = FindShape( elem );
1027 const SMDS_MeshElement* newElem1 = 0;
1028 const SMDS_MeshElement* newElem2 = 0;
1030 if( !elem->IsQuadratic() ) {
1032 // split liner quadrangle
1033 if ( aBadRate1 <= aBadRate2 ) {
1034 // tr1 + tr2 is better
1035 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1036 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1039 // tr3 + tr4 is better
1040 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1041 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1046 // split quadratic quadrangle
1048 // get surface elem is on
1049 if ( aShapeId != helper.GetSubShapeID() ) {
1053 shape = aMesh->IndexToShape( aShapeId );
1054 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1055 TopoDS_Face face = TopoDS::Face( shape );
1056 surface = BRep_Tool::Surface( face );
1057 if ( !surface.IsNull() )
1058 helper.SetSubShape( shape );
1062 const SMDS_MeshNode* aNodes [8];
1063 const SMDS_MeshNode* inFaceNode = 0;
1064 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1066 while ( itN->more() ) {
1067 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1068 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1069 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1071 inFaceNode = aNodes[ i-1 ];
1074 // find middle point for (0,1,2,3)
1075 // and create a node in this point;
1077 if ( surface.IsNull() ) {
1079 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1083 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1086 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1088 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1090 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1091 myLastCreatedNodes.Append(newN);
1093 // create a new element
1094 const SMDS_MeshNode* N[6];
1095 if ( aBadRate1 <= aBadRate2 ) {
1102 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1103 aNodes[6], aNodes[7], newN );
1104 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1105 newN, aNodes[4], aNodes[5] );
1114 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1115 aNodes[7], aNodes[4], newN );
1116 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1117 newN, aNodes[5], aNodes[6] );
1121 // care of a new element
1123 myLastCreatedElems.Append(newElem1);
1124 myLastCreatedElems.Append(newElem2);
1125 AddToSameGroups( newElem1, elem, aMesh );
1126 AddToSameGroups( newElem2, elem, aMesh );
1128 // put a new triangle on the same shape
1131 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1132 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1134 aMesh->RemoveElement( elem );
1139 //=======================================================================
1140 //function : BestSplit
1141 //purpose : Find better diagonal for cutting.
1142 //=======================================================================
1144 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1145 SMESH::Controls::NumericalFunctorPtr theCrit)
1147 myLastCreatedElems.Clear();
1148 myLastCreatedNodes.Clear();
1153 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1156 if( theQuad->NbNodes()==4 ||
1157 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1159 // retrieve element nodes
1160 const SMDS_MeshNode* aNodes [4];
1161 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1163 //while (itN->more())
1165 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1167 // compare two sets of possible triangles
1168 double aBadRate1, aBadRate2; // to what extent a set is bad
1169 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1170 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1171 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1173 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1174 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1175 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1177 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1178 return 1; // diagonal 1-3
1180 return 2; // diagonal 2-4
1187 // Methods of splitting volumes into tetra
1189 const int theHexTo5_1[5*4+1] =
1191 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1193 const int theHexTo5_2[5*4+1] =
1195 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1197 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1199 const int theHexTo6_1[6*4+1] =
1201 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1
1203 const int theHexTo6_2[6*4+1] =
1205 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1
1207 const int theHexTo6_3[6*4+1] =
1209 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1
1211 const int theHexTo6_4[6*4+1] =
1213 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1
1215 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1217 const int thePyraTo2_1[2*4+1] =
1219 0, 1, 2, 4, 0, 2, 3, 4, -1
1221 const int thePyraTo2_2[2*4+1] =
1223 1, 2, 3, 4, 1, 3, 0, 4, -1
1225 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1227 const int thePentaTo3_1[3*4+1] =
1229 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1231 const int thePentaTo3_2[3*4+1] =
1233 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1235 const int thePentaTo3_3[3*4+1] =
1237 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1239 const int thePentaTo3_4[3*4+1] =
1241 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1243 const int thePentaTo3_5[3*4+1] =
1245 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1247 const int thePentaTo3_6[3*4+1] =
1249 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1251 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1252 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1254 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1257 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1258 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1259 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1264 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1265 bool _baryNode; //!< additional node is to be created at cell barycenter
1266 bool _ownConn; //!< to delete _connectivity in destructor
1267 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1269 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1270 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1271 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1272 bool hasFacet( const TTriangleFacet& facet ) const
1274 const int* tetConn = _connectivity;
1275 for ( ; tetConn[0] >= 0; tetConn += 4 )
1276 if (( facet.contains( tetConn[0] ) +
1277 facet.contains( tetConn[1] ) +
1278 facet.contains( tetConn[2] ) +
1279 facet.contains( tetConn[3] )) == 3 )
1285 //=======================================================================
1287 * \brief return TSplitMethod for the given element
1289 //=======================================================================
1291 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1293 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1295 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1296 // an edge and a face barycenter; tertaherdons are based on triangles and
1297 // a volume barycenter
1298 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1300 // Find out how adjacent volumes are split
1302 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1303 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1304 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1306 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1307 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1308 if ( nbNodes < 4 ) continue;
1310 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1311 const int* nInd = vol.GetFaceNodesIndices( iF );
1314 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1315 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1316 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1317 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1321 int iCom = 0; // common node of triangle faces to split into
1322 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1324 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1325 nInd[ iQ * ( (iCom+1)%nbNodes )],
1326 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1327 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1328 nInd[ iQ * ( (iCom+2)%nbNodes )],
1329 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1330 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1332 triaSplits.push_back( t012 );
1333 triaSplits.push_back( t023 );
1338 if ( !triaSplits.empty() )
1339 hasAdjacentSplits = true;
1342 // Among variants of split method select one compliant with adjacent volumes
1344 TSplitMethod method;
1345 if ( !vol.Element()->IsPoly() && !is24TetMode )
1347 int nbVariants = 2, nbTet = 0;
1348 const int** connVariants = 0;
1349 switch ( vol.Element()->GetEntityType() )
1351 case SMDSEntity_Hexa:
1352 case SMDSEntity_Quad_Hexa:
1353 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1354 connVariants = theHexTo5, nbTet = 5;
1356 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1358 case SMDSEntity_Pyramid:
1359 case SMDSEntity_Quad_Pyramid:
1360 connVariants = thePyraTo2; nbTet = 2;
1362 case SMDSEntity_Penta:
1363 case SMDSEntity_Quad_Penta:
1364 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1369 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1371 // check method compliancy with adjacent tetras,
1372 // all found splits must be among facets of tetras described by this method
1373 method = TSplitMethod( nbTet, connVariants[variant] );
1374 if ( hasAdjacentSplits && method._nbTetra > 0 )
1376 bool facetCreated = true;
1377 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1379 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1380 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1381 facetCreated = method.hasFacet( *facet );
1383 if ( !facetCreated )
1384 method = TSplitMethod(0); // incompatible method
1388 if ( method._nbTetra < 1 )
1390 // No standard method is applicable, use a generic solution:
1391 // each facet of a volume is split into triangles and
1392 // each of triangles and a volume barycenter form a tetrahedron.
1394 int* connectivity = new int[ maxTetConnSize + 1 ];
1395 method._connectivity = connectivity;
1396 method._ownConn = true;
1397 method._baryNode = true;
1400 int baryCenInd = vol.NbNodes();
1401 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1403 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1404 const int* nInd = vol.GetFaceNodesIndices( iF );
1405 // find common node of triangle facets of tetra to create
1406 int iCommon = 0; // index in linear numeration
1407 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1408 if ( !triaSplits.empty() )
1411 const TTriangleFacet* facet = &triaSplits.front();
1412 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1413 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1414 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1417 else if ( nbNodes > 3 && !is24TetMode )
1419 // find the best method of splitting into triangles by aspect ratio
1420 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1421 map< double, int > badness2iCommon;
1422 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1423 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1424 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1425 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1427 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1428 nodes[ iQ*((iLast-1)%nbNodes)],
1429 nodes[ iQ*((iLast )%nbNodes)]);
1430 double badness = getBadRate( &tria, aspectRatio );
1431 badness2iCommon.insert( make_pair( badness, iCommon ));
1433 // use iCommon with lowest badness
1434 iCommon = badness2iCommon.begin()->second;
1436 if ( iCommon >= nbNodes )
1437 iCommon = 0; // something wrong
1439 // fill connectivity of tetrahedra based on a current face
1440 int nbTet = nbNodes - 2;
1441 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1443 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1444 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1446 for ( int i = 0; i < nbTet; ++i )
1448 int i1 = i, i2 = (i+1) % nbNodes;
1449 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1450 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1451 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1452 connectivity[ connSize++ ] = faceBaryCenInd;
1453 connectivity[ connSize++ ] = baryCenInd;
1458 for ( int i = 0; i < nbTet; ++i )
1460 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1461 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1462 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1463 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1464 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1465 connectivity[ connSize++ ] = baryCenInd;
1468 method._nbTetra += nbTet;
1470 connectivity[ connSize++ ] = -1;
1474 //================================================================================
1476 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1478 //================================================================================
1480 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1482 // find the tetrahedron including the three nodes of facet
1483 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1484 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1485 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1486 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1487 while ( volIt1->more() )
1489 const SMDS_MeshElement* v = volIt1->next();
1490 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1492 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1493 while ( volIt2->more() )
1494 if ( v != volIt2->next() )
1496 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1497 while ( volIt3->more() )
1498 if ( v == volIt3->next() )
1504 //=======================================================================
1506 * \brief A key of a face of volume
1508 //=======================================================================
1510 struct TVolumeFaceKey: pair< int, pair< int, int> >
1512 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1514 TIDSortedNodeSet sortedNodes;
1515 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1516 int nbNodes = vol.NbFaceNodes( iF );
1517 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1518 for ( int i = 0; i < nbNodes; i += iQ )
1519 sortedNodes.insert( fNodes[i] );
1520 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1521 first = (*(n++))->GetID();
1522 second.first = (*(n++))->GetID();
1523 second.second = (*(n++))->GetID();
1528 //=======================================================================
1529 //function : SplitVolumesIntoTetra
1530 //purpose : Split volumic elements into tetrahedra.
1531 //=======================================================================
1533 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1534 const int theMethodFlags)
1536 // std-like iterator on coordinates of nodes of mesh element
1537 typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1538 NXyzIterator xyzEnd;
1540 SMDS_VolumeTool volTool;
1541 SMESH_MesherHelper helper( *GetMesh());
1543 SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
1544 SMESHDS_SubMesh* fSubMesh = subMesh;
1546 SMESH_SequenceOfElemPtr newNodes, newElems;
1548 // map face of volume to it's baricenrtic node
1549 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1552 TIDSortedElemSet::const_iterator elem = theElems.begin();
1553 for ( ; elem != theElems.end(); ++elem )
1555 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1556 if ( geomType <= SMDSEntity_Quad_Tetra )
1557 continue; // tetra or face or ...
1559 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1561 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1562 if ( splitMethod._nbTetra < 1 ) continue;
1564 // find submesh to add new tetras to
1565 if ( !subMesh || !subMesh->Contains( *elem ))
1567 int shapeID = FindShape( *elem );
1568 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1569 subMesh = GetMeshDS()->MeshElements( shapeID );
1572 if ( (*elem)->IsQuadratic() )
1575 // add quadratic links to the helper
1576 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1578 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1579 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1580 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1582 helper.SetIsQuadratic( true );
1587 helper.SetIsQuadratic( false );
1589 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1590 if ( splitMethod._baryNode )
1592 // make a node at barycenter
1593 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1594 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1595 nodes.push_back( gcNode );
1596 newNodes.Append( gcNode );
1598 if ( !splitMethod._faceBaryNode.empty() )
1600 // make or find baricentric nodes of faces
1601 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1602 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1604 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1605 volFace2BaryNode.insert
1606 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1609 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1610 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1612 nodes.push_back( iF_n->second = f_n->second );
1617 helper.SetElementsOnShape( true );
1618 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1619 const int* tetConn = splitMethod._connectivity;
1620 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1621 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1622 nodes[ tetConn[1] ],
1623 nodes[ tetConn[2] ],
1624 nodes[ tetConn[3] ]));
1626 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1628 // Split faces on sides of the split volume
1630 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1631 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1633 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1634 if ( nbNodes < 4 ) continue;
1636 // find an existing face
1637 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1638 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1639 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1642 helper.SetElementsOnShape( false );
1643 vector< const SMDS_MeshElement* > triangles;
1645 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1646 if ( iF_n != splitMethod._faceBaryNode.end() )
1648 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1650 const SMDS_MeshNode* n1 = fNodes[iN];
1651 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1652 const SMDS_MeshNode *n3 = iF_n->second;
1653 if ( !volTool.IsFaceExternal( iF ))
1655 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1660 // among possible triangles create ones discribed by split method
1661 const int* nInd = volTool.GetFaceNodesIndices( iF );
1662 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1663 int iCom = 0; // common node of triangle faces to split into
1664 list< TTriangleFacet > facets;
1665 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1667 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1668 nInd[ iQ * ( (iCom+1)%nbNodes )],
1669 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1670 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1671 nInd[ iQ * ( (iCom+2)%nbNodes )],
1672 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1673 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1675 facets.push_back( t012 );
1676 facets.push_back( t023 );
1677 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1678 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1679 nInd[ iQ * ((iLast-1)%nbNodes )],
1680 nInd[ iQ * ((iLast )%nbNodes )]));
1684 list< TTriangleFacet >::iterator facet = facets.begin();
1685 for ( ; facet != facets.end(); ++facet )
1687 if ( !volTool.IsFaceExternal( iF ))
1688 swap( facet->_n2, facet->_n3 );
1689 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1690 volNodes[ facet->_n2 ],
1691 volNodes[ facet->_n3 ]));
1694 // find submesh to add new triangles in
1695 if ( !fSubMesh || !fSubMesh->Contains( face ))
1697 int shapeID = FindShape( face );
1698 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1700 for ( int i = 0; i < triangles.size(); ++i )
1702 if ( !triangles.back() ) continue;
1704 fSubMesh->AddElement( triangles.back());
1705 newElems.Append( triangles.back() );
1707 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1708 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1711 } // loop on volume faces to split them into triangles
1713 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1715 } // loop on volumes to split
1717 myLastCreatedNodes = newNodes;
1718 myLastCreatedElems = newElems;
1721 //=======================================================================
1722 //function : AddToSameGroups
1723 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1724 //=======================================================================
1726 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1727 const SMDS_MeshElement* elemInGroups,
1728 SMESHDS_Mesh * aMesh)
1730 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1731 if (!groups.empty()) {
1732 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1733 for ( ; grIt != groups.end(); grIt++ ) {
1734 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1735 if ( group && group->Contains( elemInGroups ))
1736 group->SMDSGroup().Add( elemToAdd );
1742 //=======================================================================
1743 //function : RemoveElemFromGroups
1744 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1745 //=======================================================================
1746 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1747 SMESHDS_Mesh * aMesh)
1749 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1750 if (!groups.empty())
1752 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1753 for (; GrIt != groups.end(); GrIt++)
1755 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1756 if (!grp || grp->IsEmpty()) continue;
1757 grp->SMDSGroup().Remove(removeelem);
1762 //================================================================================
1764 * \brief Replace elemToRm by elemToAdd in the all groups
1766 //================================================================================
1768 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1769 const SMDS_MeshElement* elemToAdd,
1770 SMESHDS_Mesh * aMesh)
1772 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1773 if (!groups.empty()) {
1774 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1775 for ( ; grIt != groups.end(); grIt++ ) {
1776 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1777 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1778 group->SMDSGroup().Add( elemToAdd );
1783 //================================================================================
1785 * \brief Replace elemToRm by elemToAdd in the all groups
1787 //================================================================================
1789 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1790 const vector<const SMDS_MeshElement*>& elemToAdd,
1791 SMESHDS_Mesh * aMesh)
1793 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1794 if (!groups.empty())
1796 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1797 for ( ; grIt != groups.end(); grIt++ ) {
1798 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1799 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1800 for ( int i = 0; i < elemToAdd.size(); ++i )
1801 group->SMDSGroup().Add( elemToAdd[ i ] );
1806 //=======================================================================
1807 //function : QuadToTri
1808 //purpose : Cut quadrangles into triangles.
1809 // theCrit is used to select a diagonal to cut
1810 //=======================================================================
1812 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1813 const bool the13Diag)
1815 myLastCreatedElems.Clear();
1816 myLastCreatedNodes.Clear();
1818 MESSAGE( "::QuadToTri()" );
1820 SMESHDS_Mesh * aMesh = GetMeshDS();
1822 Handle(Geom_Surface) surface;
1823 SMESH_MesherHelper helper( *GetMesh() );
1825 TIDSortedElemSet::iterator itElem;
1826 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1827 const SMDS_MeshElement* elem = *itElem;
1828 if ( !elem || elem->GetType() != SMDSAbs_Face )
1830 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1831 if(!isquad) continue;
1833 if(elem->NbNodes()==4) {
1834 // retrieve element nodes
1835 const SMDS_MeshNode* aNodes [4];
1836 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1838 while ( itN->more() )
1839 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1841 int aShapeId = FindShape( elem );
1842 const SMDS_MeshElement* newElem1 = 0;
1843 const SMDS_MeshElement* newElem2 = 0;
1845 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1846 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1849 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1850 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1852 myLastCreatedElems.Append(newElem1);
1853 myLastCreatedElems.Append(newElem2);
1854 // put a new triangle on the same shape and add to the same groups
1857 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1858 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1860 AddToSameGroups( newElem1, elem, aMesh );
1861 AddToSameGroups( newElem2, elem, aMesh );
1862 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1863 aMesh->RemoveElement( elem );
1866 // Quadratic quadrangle
1868 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1870 // get surface elem is on
1871 int aShapeId = FindShape( elem );
1872 if ( aShapeId != helper.GetSubShapeID() ) {
1876 shape = aMesh->IndexToShape( aShapeId );
1877 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1878 TopoDS_Face face = TopoDS::Face( shape );
1879 surface = BRep_Tool::Surface( face );
1880 if ( !surface.IsNull() )
1881 helper.SetSubShape( shape );
1885 const SMDS_MeshNode* aNodes [8];
1886 const SMDS_MeshNode* inFaceNode = 0;
1887 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1889 while ( itN->more() ) {
1890 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1891 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1892 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1894 inFaceNode = aNodes[ i-1 ];
1898 // find middle point for (0,1,2,3)
1899 // and create a node in this point;
1901 if ( surface.IsNull() ) {
1903 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1907 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1910 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1912 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1914 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1915 myLastCreatedNodes.Append(newN);
1917 // create a new element
1918 const SMDS_MeshElement* newElem1 = 0;
1919 const SMDS_MeshElement* newElem2 = 0;
1920 const SMDS_MeshNode* N[6];
1928 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1929 aNodes[6], aNodes[7], newN );
1930 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1931 newN, aNodes[4], aNodes[5] );
1940 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1941 aNodes[7], aNodes[4], newN );
1942 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1943 newN, aNodes[5], aNodes[6] );
1945 myLastCreatedElems.Append(newElem1);
1946 myLastCreatedElems.Append(newElem2);
1947 // put a new triangle on the same shape and add to the same groups
1950 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1951 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1953 AddToSameGroups( newElem1, elem, aMesh );
1954 AddToSameGroups( newElem2, elem, aMesh );
1955 aMesh->RemoveElement( elem );
1962 //=======================================================================
1963 //function : getAngle
1965 //=======================================================================
1967 double getAngle(const SMDS_MeshElement * tr1,
1968 const SMDS_MeshElement * tr2,
1969 const SMDS_MeshNode * n1,
1970 const SMDS_MeshNode * n2)
1972 double angle = 2*PI; // bad angle
1975 SMESH::Controls::TSequenceOfXYZ P1, P2;
1976 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1977 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1980 if(!tr1->IsQuadratic())
1981 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1983 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1984 if ( N1.SquareMagnitude() <= gp::Resolution() )
1986 if(!tr2->IsQuadratic())
1987 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
1989 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
1990 if ( N2.SquareMagnitude() <= gp::Resolution() )
1993 // find the first diagonal node n1 in the triangles:
1994 // take in account a diagonal link orientation
1995 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
1996 for ( int t = 0; t < 2; t++ ) {
1997 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
1998 int i = 0, iDiag = -1;
1999 while ( it->more()) {
2000 const SMDS_MeshElement *n = it->next();
2001 if ( n == n1 || n == n2 )
2005 if ( i - iDiag == 1 )
2006 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2014 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2017 angle = N1.Angle( N2 );
2022 // =================================================
2023 // class generating a unique ID for a pair of nodes
2024 // and able to return nodes by that ID
2025 // =================================================
2029 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2030 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2033 long GetLinkID (const SMDS_MeshNode * n1,
2034 const SMDS_MeshNode * n2) const
2036 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2039 bool GetNodes (const long theLinkID,
2040 const SMDS_MeshNode* & theNode1,
2041 const SMDS_MeshNode* & theNode2) const
2043 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2044 if ( !theNode1 ) return false;
2045 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2046 if ( !theNode2 ) return false;
2052 const SMESHDS_Mesh* myMesh;
2057 //=======================================================================
2058 //function : TriToQuad
2059 //purpose : Fuse neighbour triangles into quadrangles.
2060 // theCrit is used to select a neighbour to fuse with.
2061 // theMaxAngle is a max angle between element normals at which
2062 // fusion is still performed.
2063 //=======================================================================
2065 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2066 SMESH::Controls::NumericalFunctorPtr theCrit,
2067 const double theMaxAngle)
2069 myLastCreatedElems.Clear();
2070 myLastCreatedNodes.Clear();
2072 MESSAGE( "::TriToQuad()" );
2074 if ( !theCrit.get() )
2077 SMESHDS_Mesh * aMesh = GetMeshDS();
2079 // Prepare data for algo: build
2080 // 1. map of elements with their linkIDs
2081 // 2. map of linkIDs with their elements
2083 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2084 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2085 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2086 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2088 TIDSortedElemSet::iterator itElem;
2089 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2090 const SMDS_MeshElement* elem = *itElem;
2091 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2092 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2093 if(!IsTria) continue;
2095 // retrieve element nodes
2096 const SMDS_MeshNode* aNodes [4];
2097 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2100 aNodes[ i++ ] = cast2Node( itN->next() );
2101 aNodes[ 3 ] = aNodes[ 0 ];
2104 for ( i = 0; i < 3; i++ ) {
2105 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2106 // check if elements sharing a link can be fused
2107 itLE = mapLi_listEl.find( link );
2108 if ( itLE != mapLi_listEl.end() ) {
2109 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2111 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2112 //if ( FindShape( elem ) != FindShape( elem2 ))
2113 // continue; // do not fuse triangles laying on different shapes
2114 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2115 continue; // avoid making badly shaped quads
2116 (*itLE).second.push_back( elem );
2119 mapLi_listEl[ link ].push_back( elem );
2121 mapEl_setLi [ elem ].insert( link );
2124 // Clean the maps from the links shared by a sole element, ie
2125 // links to which only one element is bound in mapLi_listEl
2127 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2128 int nbElems = (*itLE).second.size();
2129 if ( nbElems < 2 ) {
2130 const SMDS_MeshElement* elem = (*itLE).second.front();
2131 SMESH_TLink link = (*itLE).first;
2132 mapEl_setLi[ elem ].erase( link );
2133 if ( mapEl_setLi[ elem ].empty() )
2134 mapEl_setLi.erase( elem );
2138 // Algo: fuse triangles into quadrangles
2140 while ( ! mapEl_setLi.empty() ) {
2141 // Look for the start element:
2142 // the element having the least nb of shared links
2143 const SMDS_MeshElement* startElem = 0;
2145 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2146 int nbLinks = (*itEL).second.size();
2147 if ( nbLinks < minNbLinks ) {
2148 startElem = (*itEL).first;
2149 minNbLinks = nbLinks;
2150 if ( minNbLinks == 1 )
2155 // search elements to fuse starting from startElem or links of elements
2156 // fused earlyer - startLinks
2157 list< SMESH_TLink > startLinks;
2158 while ( startElem || !startLinks.empty() ) {
2159 while ( !startElem && !startLinks.empty() ) {
2160 // Get an element to start, by a link
2161 SMESH_TLink linkId = startLinks.front();
2162 startLinks.pop_front();
2163 itLE = mapLi_listEl.find( linkId );
2164 if ( itLE != mapLi_listEl.end() ) {
2165 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2166 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2167 for ( ; itE != listElem.end() ; itE++ )
2168 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2170 mapLi_listEl.erase( itLE );
2175 // Get candidates to be fused
2176 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2177 const SMESH_TLink *link12, *link13;
2179 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2180 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2181 ASSERT( !setLi.empty() );
2182 set< SMESH_TLink >::iterator itLi;
2183 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2185 const SMESH_TLink & link = (*itLi);
2186 itLE = mapLi_listEl.find( link );
2187 if ( itLE == mapLi_listEl.end() )
2190 const SMDS_MeshElement* elem = (*itLE).second.front();
2192 elem = (*itLE).second.back();
2193 mapLi_listEl.erase( itLE );
2194 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2205 // add other links of elem to list of links to re-start from
2206 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2207 set< SMESH_TLink >::iterator it;
2208 for ( it = links.begin(); it != links.end(); it++ ) {
2209 const SMESH_TLink& link2 = (*it);
2210 if ( link2 != link )
2211 startLinks.push_back( link2 );
2215 // Get nodes of possible quadrangles
2216 const SMDS_MeshNode *n12 [4], *n13 [4];
2217 bool Ok12 = false, Ok13 = false;
2218 const SMDS_MeshNode *linkNode1, *linkNode2;
2220 linkNode1 = link12->first;
2221 linkNode2 = link12->second;
2222 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2226 linkNode1 = link13->first;
2227 linkNode2 = link13->second;
2228 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2232 // Choose a pair to fuse
2233 if ( Ok12 && Ok13 ) {
2234 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2235 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2236 double aBadRate12 = getBadRate( &quad12, theCrit );
2237 double aBadRate13 = getBadRate( &quad13, theCrit );
2238 if ( aBadRate13 < aBadRate12 )
2245 // and remove fused elems and removed links from the maps
2246 mapEl_setLi.erase( tr1 );
2248 mapEl_setLi.erase( tr2 );
2249 mapLi_listEl.erase( *link12 );
2250 if(tr1->NbNodes()==3) {
2251 const SMDS_MeshElement* newElem = 0;
2252 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2253 myLastCreatedElems.Append(newElem);
2254 AddToSameGroups( newElem, tr1, aMesh );
2255 int aShapeId = tr1->getshapeId();
2258 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2260 aMesh->RemoveElement( tr1 );
2261 aMesh->RemoveElement( tr2 );
2264 const SMDS_MeshNode* N1 [6];
2265 const SMDS_MeshNode* N2 [6];
2266 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2267 // now we receive following N1 and N2 (using numeration as above image)
2268 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2269 // i.e. first nodes from both arrays determ new diagonal
2270 const SMDS_MeshNode* aNodes[8];
2279 const SMDS_MeshElement* newElem = 0;
2280 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2281 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2282 myLastCreatedElems.Append(newElem);
2283 AddToSameGroups( newElem, tr1, aMesh );
2284 int aShapeId = tr1->getshapeId();
2287 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2289 aMesh->RemoveElement( tr1 );
2290 aMesh->RemoveElement( tr2 );
2291 // remove middle node (9)
2292 GetMeshDS()->RemoveNode( N1[4] );
2296 mapEl_setLi.erase( tr3 );
2297 mapLi_listEl.erase( *link13 );
2298 if(tr1->NbNodes()==3) {
2299 const SMDS_MeshElement* newElem = 0;
2300 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2301 myLastCreatedElems.Append(newElem);
2302 AddToSameGroups( newElem, tr1, aMesh );
2303 int aShapeId = tr1->getshapeId();
2306 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2308 aMesh->RemoveElement( tr1 );
2309 aMesh->RemoveElement( tr3 );
2312 const SMDS_MeshNode* N1 [6];
2313 const SMDS_MeshNode* N2 [6];
2314 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2315 // now we receive following N1 and N2 (using numeration as above image)
2316 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2317 // i.e. first nodes from both arrays determ new diagonal
2318 const SMDS_MeshNode* aNodes[8];
2327 const SMDS_MeshElement* newElem = 0;
2328 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2329 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2330 myLastCreatedElems.Append(newElem);
2331 AddToSameGroups( newElem, tr1, aMesh );
2332 int aShapeId = tr1->getshapeId();
2335 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2337 aMesh->RemoveElement( tr1 );
2338 aMesh->RemoveElement( tr3 );
2339 // remove middle node (9)
2340 GetMeshDS()->RemoveNode( N1[4] );
2344 // Next element to fuse: the rejected one
2346 startElem = Ok12 ? tr3 : tr2;
2348 } // if ( startElem )
2349 } // while ( startElem || !startLinks.empty() )
2350 } // while ( ! mapEl_setLi.empty() )
2356 /*#define DUMPSO(txt) \
2357 // cout << txt << endl;
2358 //=============================================================================
2362 //=============================================================================
2363 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2367 int tmp = idNodes[ i1 ];
2368 idNodes[ i1 ] = idNodes[ i2 ];
2369 idNodes[ i2 ] = tmp;
2370 gp_Pnt Ptmp = P[ i1 ];
2373 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2376 //=======================================================================
2377 //function : SortQuadNodes
2378 //purpose : Set 4 nodes of a quadrangle face in a good order.
2379 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2381 //=======================================================================
2383 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2388 for ( i = 0; i < 4; i++ ) {
2389 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2391 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2394 gp_Vec V1(P[0], P[1]);
2395 gp_Vec V2(P[0], P[2]);
2396 gp_Vec V3(P[0], P[3]);
2398 gp_Vec Cross1 = V1 ^ V2;
2399 gp_Vec Cross2 = V2 ^ V3;
2402 if (Cross1.Dot(Cross2) < 0)
2407 if (Cross1.Dot(Cross2) < 0)
2411 swap ( i, i + 1, idNodes, P );
2413 // for ( int ii = 0; ii < 4; ii++ ) {
2414 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2415 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2421 //=======================================================================
2422 //function : SortHexaNodes
2423 //purpose : Set 8 nodes of a hexahedron in a good order.
2424 // Return success status
2425 //=======================================================================
2427 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2432 DUMPSO( "INPUT: ========================================");
2433 for ( i = 0; i < 8; i++ ) {
2434 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2435 if ( !n ) return false;
2436 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2437 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2439 DUMPSO( "========================================");
2442 set<int> faceNodes; // ids of bottom face nodes, to be found
2443 set<int> checkedId1; // ids of tried 2-nd nodes
2444 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2445 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2446 int iMin, iLoop1 = 0;
2448 // Loop to try the 2-nd nodes
2450 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2452 // Find not checked 2-nd node
2453 for ( i = 1; i < 8; i++ )
2454 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2455 int id1 = idNodes[i];
2456 swap ( 1, i, idNodes, P );
2457 checkedId1.insert ( id1 );
2461 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2462 // ie that all but meybe one (id3 which is on the same face) nodes
2463 // lay on the same side from the triangle plane.
2465 bool manyInPlane = false; // more than 4 nodes lay in plane
2467 while ( ++iLoop2 < 6 ) {
2469 // get 1-2-3 plane coeffs
2470 Standard_Real A, B, C, D;
2471 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2472 if ( N.SquareMagnitude() > gp::Resolution() )
2474 gp_Pln pln ( P[0], N );
2475 pln.Coefficients( A, B, C, D );
2477 // find the node (iMin) closest to pln
2478 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2480 for ( i = 3; i < 8; i++ ) {
2481 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2482 if ( fabs( dist[i] ) < minDist ) {
2483 minDist = fabs( dist[i] );
2486 if ( fabs( dist[i] ) <= tol )
2487 idInPln.insert( idNodes[i] );
2490 // there should not be more than 4 nodes in bottom plane
2491 if ( idInPln.size() > 1 )
2493 DUMPSO( "### idInPln.size() = " << idInPln.size());
2494 // idInPlane does not contain the first 3 nodes
2495 if ( manyInPlane || idInPln.size() == 5)
2496 return false; // all nodes in one plane
2499 // set the 1-st node to be not in plane
2500 for ( i = 3; i < 8; i++ ) {
2501 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2502 DUMPSO( "### Reset 0-th node");
2503 swap( 0, i, idNodes, P );
2508 // reset to re-check second nodes
2509 leastDist = DBL_MAX;
2513 break; // from iLoop2;
2516 // check that the other 4 nodes are on the same side
2517 bool sameSide = true;
2518 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2519 for ( i = 3; sameSide && i < 8; i++ ) {
2521 sameSide = ( isNeg == dist[i] <= 0.);
2524 // keep best solution
2525 if ( sameSide && minDist < leastDist ) {
2526 leastDist = minDist;
2528 faceNodes.insert( idNodes[ 1 ] );
2529 faceNodes.insert( idNodes[ 2 ] );
2530 faceNodes.insert( idNodes[ iMin ] );
2531 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2532 << " leastDist = " << leastDist);
2533 if ( leastDist <= DBL_MIN )
2538 // set next 3-d node to check
2539 int iNext = 2 + iLoop2;
2541 DUMPSO( "Try 2-nd");
2542 swap ( 2, iNext, idNodes, P );
2544 } // while ( iLoop2 < 6 )
2547 if ( faceNodes.empty() ) return false;
2549 // Put the faceNodes in proper places
2550 for ( i = 4; i < 8; i++ ) {
2551 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2552 // find a place to put
2554 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2556 DUMPSO( "Set faceNodes");
2557 swap ( iTo, i, idNodes, P );
2562 // Set nodes of the found bottom face in good order
2563 DUMPSO( " Found bottom face: ");
2564 i = SortQuadNodes( theMesh, idNodes );
2566 gp_Pnt Ptmp = P[ i ];
2571 // for ( int ii = 0; ii < 4; ii++ ) {
2572 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2573 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2576 // Gravity center of the top and bottom faces
2577 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2578 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2580 // Get direction from the bottom to the top face
2581 gp_Vec upDir ( aGCb, aGCt );
2582 Standard_Real upDirSize = upDir.Magnitude();
2583 if ( upDirSize <= gp::Resolution() ) return false;
2586 // Assure that the bottom face normal points up
2587 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2588 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2589 if ( Nb.Dot( upDir ) < 0 ) {
2590 DUMPSO( "Reverse bottom face");
2591 swap( 1, 3, idNodes, P );
2594 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2595 Standard_Real minDist = DBL_MAX;
2596 for ( i = 4; i < 8; i++ ) {
2597 // projection of P[i] to the plane defined by P[0] and upDir
2598 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2599 Standard_Real sqDist = P[0].SquareDistance( Pp );
2600 if ( sqDist < minDist ) {
2605 DUMPSO( "Set 4-th");
2606 swap ( 4, iMin, idNodes, P );
2608 // Set nodes of the top face in good order
2609 DUMPSO( "Sort top face");
2610 i = SortQuadNodes( theMesh, &idNodes[4] );
2613 gp_Pnt Ptmp = P[ i ];
2618 // Assure that direction of the top face normal is from the bottom face
2619 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2620 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2621 if ( Nt.Dot( upDir ) < 0 ) {
2622 DUMPSO( "Reverse top face");
2623 swap( 5, 7, idNodes, P );
2626 // DUMPSO( "OUTPUT: ========================================");
2627 // for ( i = 0; i < 8; i++ ) {
2628 // float *p = ugrid->GetPoint(idNodes[i]);
2629 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2635 //================================================================================
2637 * \brief Return nodes linked to the given one
2638 * \param theNode - the node
2639 * \param linkedNodes - the found nodes
2640 * \param type - the type of elements to check
2642 * Medium nodes are ignored
2644 //================================================================================
2646 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2647 TIDSortedElemSet & linkedNodes,
2648 SMDSAbs_ElementType type )
2650 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2651 while ( elemIt->more() )
2653 const SMDS_MeshElement* elem = elemIt->next();
2654 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2655 if ( elem->GetType() == SMDSAbs_Volume )
2657 SMDS_VolumeTool vol( elem );
2658 while ( nodeIt->more() ) {
2659 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2660 if ( theNode != n && vol.IsLinked( theNode, n ))
2661 linkedNodes.insert( n );
2666 for ( int i = 0; nodeIt->more(); ++i ) {
2667 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2668 if ( n == theNode ) {
2669 int iBefore = i - 1;
2671 if ( elem->IsQuadratic() ) {
2672 int nb = elem->NbNodes() / 2;
2673 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2674 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2676 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2677 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2684 //=======================================================================
2685 //function : laplacianSmooth
2686 //purpose : pulls theNode toward the center of surrounding nodes directly
2687 // connected to that node along an element edge
2688 //=======================================================================
2690 void laplacianSmooth(const SMDS_MeshNode* theNode,
2691 const Handle(Geom_Surface)& theSurface,
2692 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2694 // find surrounding nodes
2696 TIDSortedElemSet nodeSet;
2697 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2699 // compute new coodrs
2701 double coord[] = { 0., 0., 0. };
2702 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2703 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2704 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2705 if ( theSurface.IsNull() ) { // smooth in 3D
2706 coord[0] += node->X();
2707 coord[1] += node->Y();
2708 coord[2] += node->Z();
2710 else { // smooth in 2D
2711 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2712 gp_XY* uv = theUVMap[ node ];
2713 coord[0] += uv->X();
2714 coord[1] += uv->Y();
2717 int nbNodes = nodeSet.size();
2720 coord[0] /= nbNodes;
2721 coord[1] /= nbNodes;
2723 if ( !theSurface.IsNull() ) {
2724 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2725 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2726 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2732 coord[2] /= nbNodes;
2736 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2739 //=======================================================================
2740 //function : centroidalSmooth
2741 //purpose : pulls theNode toward the element-area-weighted centroid of the
2742 // surrounding elements
2743 //=======================================================================
2745 void centroidalSmooth(const SMDS_MeshNode* theNode,
2746 const Handle(Geom_Surface)& theSurface,
2747 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2749 gp_XYZ aNewXYZ(0.,0.,0.);
2750 SMESH::Controls::Area anAreaFunc;
2751 double totalArea = 0.;
2756 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2757 while ( elemIt->more() )
2759 const SMDS_MeshElement* elem = elemIt->next();
2762 gp_XYZ elemCenter(0.,0.,0.);
2763 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2764 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2765 int nn = elem->NbNodes();
2766 if(elem->IsQuadratic()) nn = nn/2;
2768 //while ( itN->more() ) {
2770 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2772 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2773 aNodePoints.push_back( aP );
2774 if ( !theSurface.IsNull() ) { // smooth in 2D
2775 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2776 gp_XY* uv = theUVMap[ aNode ];
2777 aP.SetCoord( uv->X(), uv->Y(), 0. );
2781 double elemArea = anAreaFunc.GetValue( aNodePoints );
2782 totalArea += elemArea;
2784 aNewXYZ += elemCenter * elemArea;
2786 aNewXYZ /= totalArea;
2787 if ( !theSurface.IsNull() ) {
2788 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2789 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2794 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2797 //=======================================================================
2798 //function : getClosestUV
2799 //purpose : return UV of closest projection
2800 //=======================================================================
2802 static bool getClosestUV (Extrema_GenExtPS& projector,
2803 const gp_Pnt& point,
2806 projector.Perform( point );
2807 if ( projector.IsDone() ) {
2808 double u, v, minVal = DBL_MAX;
2809 for ( int i = projector.NbExt(); i > 0; i-- )
2810 if ( projector.Value( i ) < minVal ) {
2811 minVal = projector.Value( i );
2812 projector.Point( i ).Parameter( u, v );
2814 result.SetCoord( u, v );
2820 //=======================================================================
2822 //purpose : Smooth theElements during theNbIterations or until a worst
2823 // element has aspect ratio <= theTgtAspectRatio.
2824 // Aspect Ratio varies in range [1.0, inf].
2825 // If theElements is empty, the whole mesh is smoothed.
2826 // theFixedNodes contains additionally fixed nodes. Nodes built
2827 // on edges and boundary nodes are always fixed.
2828 //=======================================================================
2830 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2831 set<const SMDS_MeshNode*> & theFixedNodes,
2832 const SmoothMethod theSmoothMethod,
2833 const int theNbIterations,
2834 double theTgtAspectRatio,
2837 myLastCreatedElems.Clear();
2838 myLastCreatedNodes.Clear();
2840 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2842 if ( theTgtAspectRatio < 1.0 )
2843 theTgtAspectRatio = 1.0;
2845 const double disttol = 1.e-16;
2847 SMESH::Controls::AspectRatio aQualityFunc;
2849 SMESHDS_Mesh* aMesh = GetMeshDS();
2851 if ( theElems.empty() ) {
2852 // add all faces to theElems
2853 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2854 while ( fIt->more() ) {
2855 const SMDS_MeshElement* face = fIt->next();
2856 theElems.insert( face );
2859 // get all face ids theElems are on
2860 set< int > faceIdSet;
2861 TIDSortedElemSet::iterator itElem;
2863 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2864 int fId = FindShape( *itElem );
2865 // check that corresponding submesh exists and a shape is face
2867 faceIdSet.find( fId ) == faceIdSet.end() &&
2868 aMesh->MeshElements( fId )) {
2869 TopoDS_Shape F = aMesh->IndexToShape( fId );
2870 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2871 faceIdSet.insert( fId );
2874 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2876 // ===============================================
2877 // smooth elements on each TopoDS_Face separately
2878 // ===============================================
2880 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2881 for ( ; fId != faceIdSet.rend(); ++fId ) {
2882 // get face surface and submesh
2883 Handle(Geom_Surface) surface;
2884 SMESHDS_SubMesh* faceSubMesh = 0;
2886 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2887 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2888 bool isUPeriodic = false, isVPeriodic = false;
2890 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2891 surface = BRep_Tool::Surface( face );
2892 faceSubMesh = aMesh->MeshElements( *fId );
2893 fToler2 = BRep_Tool::Tolerance( face );
2894 fToler2 *= fToler2 * 10.;
2895 isUPeriodic = surface->IsUPeriodic();
2897 vPeriod = surface->UPeriod();
2898 isVPeriodic = surface->IsVPeriodic();
2900 uPeriod = surface->VPeriod();
2901 surface->Bounds( u1, u2, v1, v2 );
2903 // ---------------------------------------------------------
2904 // for elements on a face, find movable and fixed nodes and
2905 // compute UV for them
2906 // ---------------------------------------------------------
2907 bool checkBoundaryNodes = false;
2908 bool isQuadratic = false;
2909 set<const SMDS_MeshNode*> setMovableNodes;
2910 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2911 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2912 list< const SMDS_MeshElement* > elemsOnFace;
2914 Extrema_GenExtPS projector;
2915 GeomAdaptor_Surface surfAdaptor;
2916 if ( !surface.IsNull() ) {
2917 surfAdaptor.Load( surface );
2918 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2920 int nbElemOnFace = 0;
2921 itElem = theElems.begin();
2922 // loop on not yet smoothed elements: look for elems on a face
2923 while ( itElem != theElems.end() ) {
2924 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2925 break; // all elements found
2927 const SMDS_MeshElement* elem = *itElem;
2928 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2929 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2933 elemsOnFace.push_back( elem );
2934 theElems.erase( itElem++ );
2938 isQuadratic = elem->IsQuadratic();
2940 // get movable nodes of elem
2941 const SMDS_MeshNode* node;
2942 SMDS_TypeOfPosition posType;
2943 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2944 int nn = 0, nbn = elem->NbNodes();
2945 if(elem->IsQuadratic())
2947 while ( nn++ < nbn ) {
2948 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2949 const SMDS_PositionPtr& pos = node->GetPosition();
2950 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2951 if (posType != SMDS_TOP_EDGE &&
2952 posType != SMDS_TOP_VERTEX &&
2953 theFixedNodes.find( node ) == theFixedNodes.end())
2955 // check if all faces around the node are on faceSubMesh
2956 // because a node on edge may be bound to face
2957 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2959 if ( faceSubMesh ) {
2960 while ( eIt->more() && all ) {
2961 const SMDS_MeshElement* e = eIt->next();
2962 all = faceSubMesh->Contains( e );
2966 setMovableNodes.insert( node );
2968 checkBoundaryNodes = true;
2970 if ( posType == SMDS_TOP_3DSPACE )
2971 checkBoundaryNodes = true;
2974 if ( surface.IsNull() )
2977 // get nodes to check UV
2978 list< const SMDS_MeshNode* > uvCheckNodes;
2979 itN = elem->nodesIterator();
2980 nn = 0; nbn = elem->NbNodes();
2981 if(elem->IsQuadratic())
2983 while ( nn++ < nbn ) {
2984 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2985 if ( uvMap.find( node ) == uvMap.end() )
2986 uvCheckNodes.push_back( node );
2987 // add nodes of elems sharing node
2988 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2989 // while ( eIt->more() ) {
2990 // const SMDS_MeshElement* e = eIt->next();
2991 // if ( e != elem ) {
2992 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
2993 // while ( nIt->more() ) {
2994 // const SMDS_MeshNode* n =
2995 // static_cast<const SMDS_MeshNode*>( nIt->next() );
2996 // if ( uvMap.find( n ) == uvMap.end() )
2997 // uvCheckNodes.push_back( n );
3003 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3004 for ( ; n != uvCheckNodes.end(); ++n ) {
3007 const SMDS_PositionPtr& pos = node->GetPosition();
3008 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3010 switch ( posType ) {
3011 case SMDS_TOP_FACE: {
3012 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3013 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3016 case SMDS_TOP_EDGE: {
3017 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3018 Handle(Geom2d_Curve) pcurve;
3019 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3020 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3021 if ( !pcurve.IsNull() ) {
3022 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3023 uv = pcurve->Value( u ).XY();
3027 case SMDS_TOP_VERTEX: {
3028 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3029 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3030 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3035 // check existing UV
3036 bool project = true;
3037 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3038 double dist1 = DBL_MAX, dist2 = 0;
3039 if ( posType != SMDS_TOP_3DSPACE ) {
3040 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3041 project = dist1 > fToler2;
3043 if ( project ) { // compute new UV
3045 if ( !getClosestUV( projector, pNode, newUV )) {
3046 MESSAGE("Node Projection Failed " << node);
3050 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3052 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3054 if ( posType != SMDS_TOP_3DSPACE )
3055 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3056 if ( dist2 < dist1 )
3060 // store UV in the map
3061 listUV.push_back( uv );
3062 uvMap.insert( make_pair( node, &listUV.back() ));
3064 } // loop on not yet smoothed elements
3066 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3067 checkBoundaryNodes = true;
3069 // fix nodes on mesh boundary
3071 if ( checkBoundaryNodes ) {
3072 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3073 map< NLink, int >::iterator link_nb;
3074 // put all elements links to linkNbMap
3075 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3076 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3077 const SMDS_MeshElement* elem = (*elemIt);
3078 int nbn = elem->NbNodes();
3079 if(elem->IsQuadratic())
3081 // loop on elem links: insert them in linkNbMap
3082 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3083 for ( int iN = 0; iN < nbn; ++iN ) {
3084 curNode = elem->GetNode( iN );
3086 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3087 else link = make_pair( prevNode , curNode );
3089 link_nb = linkNbMap.find( link );
3090 if ( link_nb == linkNbMap.end() )
3091 linkNbMap.insert( make_pair ( link, 1 ));
3096 // remove nodes that are in links encountered only once from setMovableNodes
3097 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3098 if ( link_nb->second == 1 ) {
3099 setMovableNodes.erase( link_nb->first.first );
3100 setMovableNodes.erase( link_nb->first.second );
3105 // -----------------------------------------------------
3106 // for nodes on seam edge, compute one more UV ( uvMap2 );
3107 // find movable nodes linked to nodes on seam and which
3108 // are to be smoothed using the second UV ( uvMap2 )
3109 // -----------------------------------------------------
3111 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3112 if ( !surface.IsNull() ) {
3113 TopExp_Explorer eExp( face, TopAbs_EDGE );
3114 for ( ; eExp.More(); eExp.Next() ) {
3115 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3116 if ( !BRep_Tool::IsClosed( edge, face ))
3118 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3119 if ( !sm ) continue;
3120 // find out which parameter varies for a node on seam
3123 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3124 if ( pcurve.IsNull() ) continue;
3125 uv1 = pcurve->Value( f );
3127 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3128 if ( pcurve.IsNull() ) continue;
3129 uv2 = pcurve->Value( f );
3130 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3132 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3133 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3135 // get nodes on seam and its vertices
3136 list< const SMDS_MeshNode* > seamNodes;
3137 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3138 while ( nSeamIt->more() ) {
3139 const SMDS_MeshNode* node = nSeamIt->next();
3140 if ( !isQuadratic || !IsMedium( node ))
3141 seamNodes.push_back( node );
3143 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3144 for ( ; vExp.More(); vExp.Next() ) {
3145 sm = aMesh->MeshElements( vExp.Current() );
3147 nSeamIt = sm->GetNodes();
3148 while ( nSeamIt->more() )
3149 seamNodes.push_back( nSeamIt->next() );
3152 // loop on nodes on seam
3153 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3154 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3155 const SMDS_MeshNode* nSeam = *noSeIt;
3156 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3157 if ( n_uv == uvMap.end() )
3160 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3161 // set the second UV
3162 listUV.push_back( *n_uv->second );
3163 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3164 if ( uvMap2.empty() )
3165 uvMap2 = uvMap; // copy the uvMap contents
3166 uvMap2[ nSeam ] = &listUV.back();
3168 // collect movable nodes linked to ones on seam in nodesNearSeam
3169 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3170 while ( eIt->more() ) {
3171 const SMDS_MeshElement* e = eIt->next();
3172 int nbUseMap1 = 0, nbUseMap2 = 0;
3173 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3174 int nn = 0, nbn = e->NbNodes();
3175 if(e->IsQuadratic()) nbn = nbn/2;
3176 while ( nn++ < nbn )
3178 const SMDS_MeshNode* n =
3179 static_cast<const SMDS_MeshNode*>( nIt->next() );
3181 setMovableNodes.find( n ) == setMovableNodes.end() )
3183 // add only nodes being closer to uv2 than to uv1
3184 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3185 0.5 * ( n->Y() + nSeam->Y() ),
3186 0.5 * ( n->Z() + nSeam->Z() ));
3188 getClosestUV( projector, pMid, uv );
3189 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3190 nodesNearSeam.insert( n );
3196 // for centroidalSmooth all element nodes must
3197 // be on one side of a seam
3198 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3199 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3201 while ( nn++ < nbn ) {
3202 const SMDS_MeshNode* n =
3203 static_cast<const SMDS_MeshNode*>( nIt->next() );
3204 setMovableNodes.erase( n );
3208 } // loop on nodes on seam
3209 } // loop on edge of a face
3210 } // if ( !face.IsNull() )
3212 if ( setMovableNodes.empty() ) {
3213 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3214 continue; // goto next face
3222 double maxRatio = -1., maxDisplacement = -1.;
3223 set<const SMDS_MeshNode*>::iterator nodeToMove;
3224 for ( it = 0; it < theNbIterations; it++ ) {
3225 maxDisplacement = 0.;
3226 nodeToMove = setMovableNodes.begin();
3227 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3228 const SMDS_MeshNode* node = (*nodeToMove);
3229 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3232 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3233 if ( theSmoothMethod == LAPLACIAN )
3234 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3236 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3238 // node displacement
3239 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3240 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3241 if ( aDispl > maxDisplacement )
3242 maxDisplacement = aDispl;
3244 // no node movement => exit
3245 //if ( maxDisplacement < 1.e-16 ) {
3246 if ( maxDisplacement < disttol ) {
3247 MESSAGE("-- no node movement --");
3251 // check elements quality
3253 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3254 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3255 const SMDS_MeshElement* elem = (*elemIt);
3256 if ( !elem || elem->GetType() != SMDSAbs_Face )
3258 SMESH::Controls::TSequenceOfXYZ aPoints;
3259 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3260 double aValue = aQualityFunc.GetValue( aPoints );
3261 if ( aValue > maxRatio )
3265 if ( maxRatio <= theTgtAspectRatio ) {
3266 MESSAGE("-- quality achived --");
3269 if (it+1 == theNbIterations) {
3270 MESSAGE("-- Iteration limit exceeded --");
3272 } // smoothing iterations
3274 MESSAGE(" Face id: " << *fId <<
3275 " Nb iterstions: " << it <<
3276 " Displacement: " << maxDisplacement <<
3277 " Aspect Ratio " << maxRatio);
3279 // ---------------------------------------
3280 // new nodes positions are computed,
3281 // record movement in DS and set new UV
3282 // ---------------------------------------
3283 nodeToMove = setMovableNodes.begin();
3284 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3285 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3286 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3287 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3288 if ( node_uv != uvMap.end() ) {
3289 gp_XY* uv = node_uv->second;
3291 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3295 // move medium nodes of quadratic elements
3298 SMESH_MesherHelper helper( *GetMesh() );
3299 if ( !face.IsNull() )
3300 helper.SetSubShape( face );
3301 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3302 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3303 const SMDS_VtkFace* QF =
3304 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3305 if(QF && QF->IsQuadratic()) {
3306 vector<const SMDS_MeshNode*> Ns;
3307 Ns.reserve(QF->NbNodes()+1);
3308 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3309 while ( anIter->more() )
3310 Ns.push_back( cast2Node(anIter->next()) );
3311 Ns.push_back( Ns[0] );
3313 for(int i=0; i<QF->NbNodes(); i=i+2) {
3314 if ( !surface.IsNull() ) {
3315 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3316 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3317 gp_XY uv = ( uv1 + uv2 ) / 2.;
3318 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3319 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3322 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3323 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3324 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3326 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3327 fabs( Ns[i+1]->Y() - y ) > disttol ||
3328 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3329 // we have to move i+1 node
3330 aMesh->MoveNode( Ns[i+1], x, y, z );
3337 } // loop on face ids
3341 //=======================================================================
3342 //function : isReverse
3343 //purpose : Return true if normal of prevNodes is not co-directied with
3344 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3345 // iNotSame is where prevNodes and nextNodes are different
3346 //=======================================================================
3348 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3349 vector<const SMDS_MeshNode*> nextNodes,
3353 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3354 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3356 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3357 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3358 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3359 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3361 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3362 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3363 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3364 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3366 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3368 return (vA ^ vB) * vN < 0.0;
3371 //=======================================================================
3373 * \brief Create elements by sweeping an element
3374 * \param elem - element to sweep
3375 * \param newNodesItVec - nodes generated from each node of the element
3376 * \param newElems - generated elements
3377 * \param nbSteps - number of sweeping steps
3378 * \param srcElements - to append elem for each generated element
3380 //=======================================================================
3382 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3383 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3384 list<const SMDS_MeshElement*>& newElems,
3386 SMESH_SequenceOfElemPtr& srcElements)
3388 //MESSAGE("sweepElement " << nbSteps);
3389 SMESHDS_Mesh* aMesh = GetMeshDS();
3391 // Loop on elem nodes:
3392 // find new nodes and detect same nodes indices
3393 int nbNodes = elem->NbNodes();
3394 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3395 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3396 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3397 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3399 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3400 vector<int> sames(nbNodes);
3401 vector<bool> issimple(nbNodes);
3403 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3404 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3405 const SMDS_MeshNode* node = nnIt->first;
3406 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3407 if ( listNewNodes.empty() ) {
3411 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3413 itNN[ iNode ] = listNewNodes.begin();
3414 prevNod[ iNode ] = node;
3415 nextNod[ iNode ] = listNewNodes.front();
3416 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3417 if ( prevNod[ iNode ] != nextNod [ iNode ])
3418 iNotSameNode = iNode;
3422 sames[nbSame++] = iNode;
3427 //cerr<<" nbSame = "<<nbSame<<endl;
3428 if ( nbSame == nbNodes || nbSame > 2) {
3429 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3430 //INFOS( " Too many same nodes of element " << elem->GetID() );
3434 // if( elem->IsQuadratic() && nbSame>0 ) {
3435 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3439 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3440 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3442 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3443 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3444 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3448 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3449 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3450 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3451 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3453 // check element orientation
3455 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3456 //MESSAGE("Reversed elem " << elem );
3460 std::swap( iBeforeSame, iAfterSame );
3463 // make new elements
3464 const SMDS_MeshElement* lastElem = elem;
3465 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3467 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3468 if(issimple[iNode]) {
3469 nextNod[ iNode ] = *itNN[ iNode ];
3473 if( elem->GetType()==SMDSAbs_Node ) {
3474 // we have to use two nodes
3475 midlNod[ iNode ] = *itNN[ iNode ];
3477 nextNod[ iNode ] = *itNN[ iNode ];
3480 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3481 // we have to use each second node
3483 nextNod[ iNode ] = *itNN[ iNode ];
3487 // we have to use two nodes
3488 midlNod[ iNode ] = *itNN[ iNode ];
3490 nextNod[ iNode ] = *itNN[ iNode ];
3495 SMDS_MeshElement* aNewElem = 0;
3496 if(!elem->IsPoly()) {
3497 switch ( nbNodes ) {
3501 if ( nbSame == 0 ) {
3503 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3505 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3511 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3512 nextNod[ 1 ], nextNod[ 0 ] );
3514 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3515 nextNod[ iNotSameNode ] );
3519 case 3: { // TRIANGLE or quadratic edge
3520 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3522 if ( nbSame == 0 ) // --- pentahedron
3523 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3524 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3526 else if ( nbSame == 1 ) // --- pyramid
3527 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3528 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3529 nextNod[ iSameNode ]);
3531 else // 2 same nodes: --- tetrahedron
3532 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3533 nextNod[ iNotSameNode ]);
3535 else { // quadratic edge
3536 if(nbSame==0) { // quadratic quadrangle
3537 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3538 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3540 else if(nbSame==1) { // quadratic triangle
3542 return; // medium node on axis
3544 else if(sames[0]==0) {
3545 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3546 nextNod[2], midlNod[1], prevNod[2]);
3548 else { // sames[0]==1
3549 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3550 midlNod[0], nextNod[2], prevNod[2]);
3559 case 4: { // QUADRANGLE
3561 if ( nbSame == 0 ) // --- hexahedron
3562 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3563 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3565 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3566 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3567 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3568 nextNod[ iSameNode ]);
3569 newElems.push_back( aNewElem );
3570 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3571 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3572 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3574 else if ( nbSame == 2 ) { // pentahedron
3575 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3576 // iBeforeSame is same too
3577 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3578 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3579 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3581 // iAfterSame is same too
3582 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3583 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3584 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3588 case 6: { // quadratic triangle
3589 // create pentahedron with 15 nodes
3591 if(i0>0) { // reversed case
3592 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3593 nextNod[0], nextNod[2], nextNod[1],
3594 prevNod[5], prevNod[4], prevNod[3],
3595 nextNod[5], nextNod[4], nextNod[3],
3596 midlNod[0], midlNod[2], midlNod[1]);
3598 else { // not reversed case
3599 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3600 nextNod[0], nextNod[1], nextNod[2],
3601 prevNod[3], prevNod[4], prevNod[5],
3602 nextNod[3], nextNod[4], nextNod[5],
3603 midlNod[0], midlNod[1], midlNod[2]);
3606 else if(nbSame==1) {
3607 // 2d order pyramid of 13 nodes
3608 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3609 // int n12,int n23,int n34,int n41,
3610 // int n15,int n25,int n35,int n45, int ID);
3612 int n1,n4,n41,n15,n45;
3613 if(i0>0) { // reversed case
3614 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3615 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3621 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3622 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3627 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3628 nextNod[n4], prevNod[n4], prevNod[n5],
3629 midlNod[n1], nextNod[n41],
3630 midlNod[n4], prevNod[n41],
3631 prevNod[n15], nextNod[n15],
3632 nextNod[n45], prevNod[n45]);
3634 else if(nbSame==2) {
3635 // 2d order tetrahedron of 10 nodes
3636 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3637 // int n12,int n23,int n31,
3638 // int n14,int n24,int n34, int ID);
3639 int n1 = iNotSameNode;
3640 int n2,n3,n12,n23,n31;
3641 if(i0>0) { // reversed case
3642 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3643 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3649 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3650 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3655 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3656 prevNod[n12], prevNod[n23], prevNod[n31],
3657 midlNod[n1], nextNod[n12], nextNod[n31]);
3661 case 8: { // quadratic quadrangle
3663 // create hexahedron with 20 nodes
3664 if(i0>0) { // reversed case
3665 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3666 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3667 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3668 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3669 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3671 else { // not reversed case
3672 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3673 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3674 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3675 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3676 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3679 else if(nbSame==1) {
3680 // --- pyramid + pentahedron - can not be created since it is needed
3681 // additional middle node ot the center of face
3682 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3685 else if(nbSame==2) {
3686 // 2d order Pentahedron with 15 nodes
3687 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3688 // int n12,int n23,int n31,int n45,int n56,int n64,
3689 // int n14,int n25,int n36, int ID);
3691 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3692 // iBeforeSame is same too
3699 // iAfterSame is same too
3705 int n12,n45,n14,n25;
3706 if(i0>0) { //reversed case
3718 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3719 prevNod[n4], prevNod[n5], nextNod[n5],
3720 prevNod[n12], midlNod[n2], nextNod[n12],
3721 prevNod[n45], midlNod[n5], nextNod[n45],
3722 prevNod[n14], prevNod[n25], nextNod[n25]);
3727 // realized for extrusion only
3728 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3729 //vector<int> quantities (nbNodes + 2);
3731 //quantities[0] = nbNodes; // bottom of prism
3732 //for (int inode = 0; inode < nbNodes; inode++) {
3733 // polyedre_nodes[inode] = prevNod[inode];
3736 //quantities[1] = nbNodes; // top of prism
3737 //for (int inode = 0; inode < nbNodes; inode++) {
3738 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3741 //for (int iface = 0; iface < nbNodes; iface++) {
3742 // quantities[iface + 2] = 4;
3743 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3744 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3745 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3746 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3747 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3749 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3756 // realized for extrusion only
3757 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3758 vector<int> quantities (nbNodes + 2);
3760 quantities[0] = nbNodes; // bottom of prism
3761 for (int inode = 0; inode < nbNodes; inode++) {
3762 polyedre_nodes[inode] = prevNod[inode];
3765 quantities[1] = nbNodes; // top of prism
3766 for (int inode = 0; inode < nbNodes; inode++) {
3767 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3770 for (int iface = 0; iface < nbNodes; iface++) {
3771 quantities[iface + 2] = 4;
3772 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3773 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3774 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3775 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3776 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3778 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3782 newElems.push_back( aNewElem );
3783 myLastCreatedElems.Append(aNewElem);
3784 srcElements.Append( elem );
3785 lastElem = aNewElem;
3788 // set new prev nodes
3789 for ( iNode = 0; iNode < nbNodes; iNode++ )
3790 prevNod[ iNode ] = nextNod[ iNode ];
3795 //=======================================================================
3797 * \brief Create 1D and 2D elements around swept elements
3798 * \param mapNewNodes - source nodes and ones generated from them
3799 * \param newElemsMap - source elements and ones generated from them
3800 * \param elemNewNodesMap - nodes generated from each node of each element
3801 * \param elemSet - all swept elements
3802 * \param nbSteps - number of sweeping steps
3803 * \param srcElements - to append elem for each generated element
3805 //=======================================================================
3807 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3808 TElemOfElemListMap & newElemsMap,
3809 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3810 TIDSortedElemSet& elemSet,
3812 SMESH_SequenceOfElemPtr& srcElements)
3814 MESSAGE("makeWalls");
3815 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3816 SMESHDS_Mesh* aMesh = GetMeshDS();
3818 // Find nodes belonging to only one initial element - sweep them to get edges.
3820 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3821 for ( ; nList != mapNewNodes.end(); nList++ ) {
3822 const SMDS_MeshNode* node =
3823 static_cast<const SMDS_MeshNode*>( nList->first );
3824 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3825 int nbInitElems = 0;
3826 const SMDS_MeshElement* el = 0;
3827 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3828 while ( eIt->more() && nbInitElems < 2 ) {
3830 SMDSAbs_ElementType type = el->GetType();
3831 if ( type == SMDSAbs_Volume || type < highType ) continue;
3832 if ( type > highType ) {
3836 if ( elemSet.find(el) != elemSet.end() )
3839 if ( nbInitElems < 2 ) {
3840 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3841 if(!NotCreateEdge) {
3842 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3843 list<const SMDS_MeshElement*> newEdges;
3844 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3849 // Make a ceiling for each element ie an equal element of last new nodes.
3850 // Find free links of faces - make edges and sweep them into faces.
3852 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3853 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3854 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3855 const SMDS_MeshElement* elem = itElem->first;
3856 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3858 if ( elem->GetType() == SMDSAbs_Edge ) {
3859 // create a ceiling edge
3860 if (!elem->IsQuadratic()) {
3861 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3862 vecNewNodes[ 1 ]->second.back())) {
3863 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3864 vecNewNodes[ 1 ]->second.back()));
3865 srcElements.Append( myLastCreatedElems.Last() );
3869 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3870 vecNewNodes[ 1 ]->second.back(),
3871 vecNewNodes[ 2 ]->second.back())) {
3872 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3873 vecNewNodes[ 1 ]->second.back(),
3874 vecNewNodes[ 2 ]->second.back()));
3875 srcElements.Append( myLastCreatedElems.Last() );
3879 if ( elem->GetType() != SMDSAbs_Face )
3882 if(itElem->second.size()==0) continue;
3884 bool hasFreeLinks = false;
3886 TIDSortedElemSet avoidSet;
3887 avoidSet.insert( elem );
3889 set<const SMDS_MeshNode*> aFaceLastNodes;
3890 int iNode, nbNodes = vecNewNodes.size();
3891 if(!elem->IsQuadratic()) {
3892 // loop on the face nodes
3893 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3894 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3895 // look for free links of the face
3896 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3897 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3898 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3899 // check if a link is free
3900 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3901 hasFreeLinks = true;
3902 // make an edge and a ceiling for a new edge
3903 if ( !aMesh->FindEdge( n1, n2 )) {
3904 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3905 srcElements.Append( myLastCreatedElems.Last() );
3907 n1 = vecNewNodes[ iNode ]->second.back();
3908 n2 = vecNewNodes[ iNext ]->second.back();
3909 if ( !aMesh->FindEdge( n1, n2 )) {
3910 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3911 srcElements.Append( myLastCreatedElems.Last() );
3916 else { // elem is quadratic face
3917 int nbn = nbNodes/2;
3918 for ( iNode = 0; iNode < nbn; iNode++ ) {
3919 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3920 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3921 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3922 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3923 // check if a link is free
3924 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3925 hasFreeLinks = true;
3926 // make an edge and a ceiling for a new edge
3928 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3929 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3930 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3931 srcElements.Append( myLastCreatedElems.Last() );
3933 n1 = vecNewNodes[ iNode ]->second.back();
3934 n2 = vecNewNodes[ iNext ]->second.back();
3935 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3936 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3937 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3938 srcElements.Append( myLastCreatedElems.Last() );
3942 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3943 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3947 // sweep free links into faces
3949 if ( hasFreeLinks ) {
3950 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3951 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3953 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3954 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3955 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3956 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3958 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3959 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3961 while ( iVol++ < volNb ) v++;
3962 // find indices of free faces of a volume and their source edges
3963 list< int > freeInd;
3964 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3965 SMDS_VolumeTool vTool( *v );
3966 int iF, nbF = vTool.NbFaces();
3967 for ( iF = 0; iF < nbF; iF ++ ) {
3968 if (vTool.IsFreeFace( iF ) &&
3969 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3970 initNodeSet != faceNodeSet) // except an initial face
3972 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3974 freeInd.push_back( iF );
3975 // find source edge of a free face iF
3976 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3977 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3978 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3979 initNodeSet.begin(), initNodeSet.end(),
3980 commonNodes.begin());
3981 if ( (*v)->IsQuadratic() )
3982 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
3984 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
3986 if ( !srcEdges.back() )
3988 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
3989 << iF << " of volume #" << vTool.ID() << endl;
3994 if ( freeInd.empty() )
3997 // create faces for all steps;
3998 // if such a face has been already created by sweep of edge,
3999 // assure that its orientation is OK
4000 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4002 vTool.SetExternalNormal();
4003 list< int >::iterator ind = freeInd.begin();
4004 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4005 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4007 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4008 int nbn = vTool.NbFaceNodes( *ind );
4010 case 3: { ///// triangle
4011 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4013 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4014 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4016 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4017 aMesh->RemoveElement(f);
4021 case 4: { ///// quadrangle
4022 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4024 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4025 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4027 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4028 aMesh->RemoveElement(f);
4033 if( (*v)->IsQuadratic() ) {
4034 if(nbn==6) { /////// quadratic triangle
4035 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4036 nodes[1], nodes[3], nodes[5] );
4038 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4039 nodes[1], nodes[3], nodes[5]));
4041 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4042 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4043 tmpnodes[0] = nodes[0];
4044 tmpnodes[1] = nodes[2];
4045 tmpnodes[2] = nodes[4];
4046 tmpnodes[3] = nodes[1];
4047 tmpnodes[4] = nodes[3];
4048 tmpnodes[5] = nodes[5];
4049 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4050 nodes[1], nodes[3], nodes[5]));
4051 aMesh->RemoveElement(f);
4054 else { /////// quadratic quadrangle
4055 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4056 nodes[1], nodes[3], nodes[5], nodes[7] );
4058 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4059 nodes[1], nodes[3], nodes[5], nodes[7]));
4061 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4062 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4063 tmpnodes[0] = nodes[0];
4064 tmpnodes[1] = nodes[2];
4065 tmpnodes[2] = nodes[4];
4066 tmpnodes[3] = nodes[6];
4067 tmpnodes[4] = nodes[1];
4068 tmpnodes[5] = nodes[3];
4069 tmpnodes[6] = nodes[5];
4070 tmpnodes[7] = nodes[7];
4071 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4072 nodes[1], nodes[3], nodes[5], nodes[7]));
4073 aMesh->RemoveElement(f);
4077 else { //////// polygon
4078 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4079 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4081 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4082 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4084 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4085 MESSAGE("ChangeElementNodes");
4086 aMesh->ChangeElementNodes( f, nodes, nbn );
4090 while ( srcElements.Length() < myLastCreatedElems.Length() )
4091 srcElements.Append( *srcEdge );
4093 } // loop on free faces
4095 // go to the next volume
4097 while ( iVol++ < nbVolumesByStep ) v++;
4100 } // sweep free links into faces
4102 // Make a ceiling face with a normal external to a volume
4104 SMDS_VolumeTool lastVol( itElem->second.back() );
4106 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4108 lastVol.SetExternalNormal();
4109 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4110 int nbn = lastVol.NbFaceNodes( iF );
4113 if (!hasFreeLinks ||
4114 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4115 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4118 if (!hasFreeLinks ||
4119 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4120 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4123 if(itElem->second.back()->IsQuadratic()) {
4125 if (!hasFreeLinks ||
4126 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4127 nodes[1], nodes[3], nodes[5]) ) {
4128 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4129 nodes[1], nodes[3], nodes[5]));
4133 if (!hasFreeLinks ||
4134 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4135 nodes[1], nodes[3], nodes[5], nodes[7]) )
4136 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4137 nodes[1], nodes[3], nodes[5], nodes[7]));
4141 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4142 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4143 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4147 while ( srcElements.Length() < myLastCreatedElems.Length() )
4148 srcElements.Append( myLastCreatedElems.Last() );
4150 } // loop on swept elements
4153 //=======================================================================
4154 //function : RotationSweep
4156 //=======================================================================
4158 SMESH_MeshEditor::PGroupIDs
4159 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4160 const gp_Ax1& theAxis,
4161 const double theAngle,
4162 const int theNbSteps,
4163 const double theTol,
4164 const bool theMakeGroups,
4165 const bool theMakeWalls)
4167 myLastCreatedElems.Clear();
4168 myLastCreatedNodes.Clear();
4170 // source elements for each generated one
4171 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4173 MESSAGE( "RotationSweep()");
4175 aTrsf.SetRotation( theAxis, theAngle );
4177 aTrsf2.SetRotation( theAxis, theAngle/2. );
4179 gp_Lin aLine( theAxis );
4180 double aSqTol = theTol * theTol;
4182 SMESHDS_Mesh* aMesh = GetMeshDS();
4184 TNodeOfNodeListMap mapNewNodes;
4185 TElemOfVecOfNnlmiMap mapElemNewNodes;
4186 TElemOfElemListMap newElemsMap;
4189 TIDSortedElemSet::iterator itElem;
4190 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4191 const SMDS_MeshElement* elem = *itElem;
4192 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4194 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4195 newNodesItVec.reserve( elem->NbNodes() );
4197 // loop on elem nodes
4198 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4199 while ( itN->more() ) {
4200 // check if a node has been already sweeped
4201 const SMDS_MeshNode* node = cast2Node( itN->next() );
4203 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4205 aXYZ.Coord( coord[0], coord[1], coord[2] );
4206 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4208 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4209 if ( nIt == mapNewNodes.end() ) {
4210 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4211 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4214 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4216 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4217 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4218 const SMDS_MeshNode * newNode = node;
4219 for ( int i = 0; i < theNbSteps; i++ ) {
4221 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4223 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4224 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4225 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4226 myLastCreatedNodes.Append(newNode);
4227 srcNodes.Append( node );
4228 listNewNodes.push_back( newNode );
4229 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4230 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4233 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4235 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4236 myLastCreatedNodes.Append(newNode);
4237 srcNodes.Append( node );
4238 listNewNodes.push_back( newNode );
4241 listNewNodes.push_back( newNode );
4242 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4243 listNewNodes.push_back( newNode );
4250 // if current elem is quadratic and current node is not medium
4251 // we have to check - may be it is needed to insert additional nodes
4252 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4253 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4254 if(listNewNodes.size()==theNbSteps) {
4255 listNewNodes.clear();
4257 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4259 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4260 const SMDS_MeshNode * newNode = node;
4262 for(int i = 0; i<theNbSteps; i++) {
4263 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4264 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4265 cout<<" 3 AddNode: "<<newNode;
4266 myLastCreatedNodes.Append(newNode);
4267 listNewNodes.push_back( newNode );
4268 srcNodes.Append( node );
4269 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4270 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271 cout<<" 4 AddNode: "<<newNode;
4272 myLastCreatedNodes.Append(newNode);
4273 srcNodes.Append( node );
4274 listNewNodes.push_back( newNode );
4278 listNewNodes.push_back( newNode );
4284 newNodesItVec.push_back( nIt );
4286 // make new elements
4287 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4291 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4293 PGroupIDs newGroupIDs;
4294 if ( theMakeGroups )
4295 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4301 //=======================================================================
4302 //function : CreateNode
4304 //=======================================================================
4305 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4308 const double tolnode,
4309 SMESH_SequenceOfNode& aNodes)
4311 myLastCreatedElems.Clear();
4312 myLastCreatedNodes.Clear();
4315 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4317 // try to search in sequence of existing nodes
4318 // if aNodes.Length()>0 we 'nave to use given sequence
4319 // else - use all nodes of mesh
4320 if(aNodes.Length()>0) {
4322 for(i=1; i<=aNodes.Length(); i++) {
4323 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4324 if(P1.Distance(P2)<tolnode)
4325 return aNodes.Value(i);
4329 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4330 while(itn->more()) {
4331 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4332 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4333 if(P1.Distance(P2)<tolnode)
4338 // create new node and return it
4339 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4340 myLastCreatedNodes.Append(NewNode);
4345 //=======================================================================
4346 //function : ExtrusionSweep
4348 //=======================================================================
4350 SMESH_MeshEditor::PGroupIDs
4351 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4352 const gp_Vec& theStep,
4353 const int theNbSteps,
4354 TElemOfElemListMap& newElemsMap,
4355 const bool theMakeGroups,
4357 const double theTolerance)
4359 ExtrusParam aParams;
4360 aParams.myDir = gp_Dir(theStep);
4361 aParams.myNodes.Clear();
4362 aParams.mySteps = new TColStd_HSequenceOfReal;
4364 for(i=1; i<=theNbSteps; i++)
4365 aParams.mySteps->Append(theStep.Magnitude());
4368 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4372 //=======================================================================
4373 //function : ExtrusionSweep
4375 //=======================================================================
4377 SMESH_MeshEditor::PGroupIDs
4378 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4379 ExtrusParam& theParams,
4380 TElemOfElemListMap& newElemsMap,
4381 const bool theMakeGroups,
4383 const double theTolerance)
4385 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4386 myLastCreatedElems.Clear();
4387 myLastCreatedNodes.Clear();
4389 // source elements for each generated one
4390 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4392 SMESHDS_Mesh* aMesh = GetMeshDS();
4394 int nbsteps = theParams.mySteps->Length();
4396 TNodeOfNodeListMap mapNewNodes;
4397 //TNodeOfNodeVecMap mapNewNodes;
4398 TElemOfVecOfNnlmiMap mapElemNewNodes;
4399 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4402 TIDSortedElemSet::iterator itElem;
4403 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4404 // check element type
4405 const SMDS_MeshElement* elem = *itElem;
4406 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4409 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4410 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4411 newNodesItVec.reserve( elem->NbNodes() );
4413 // loop on elem nodes
4414 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4415 while ( itN->more() )
4417 // check if a node has been already sweeped
4418 const SMDS_MeshNode* node = cast2Node( itN->next() );
4419 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4420 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4421 if ( nIt == mapNewNodes.end() ) {
4422 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4423 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4424 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4425 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4426 //vecNewNodes.reserve(nbsteps);
4429 double coord[] = { node->X(), node->Y(), node->Z() };
4430 //int nbsteps = theParams.mySteps->Length();
4431 for ( int i = 0; i < nbsteps; i++ ) {
4432 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4433 // create additional node
4434 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4435 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4436 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4437 if( theFlags & EXTRUSION_FLAG_SEW ) {
4438 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4439 theTolerance, theParams.myNodes);
4440 listNewNodes.push_back( newNode );
4443 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4444 myLastCreatedNodes.Append(newNode);
4445 srcNodes.Append( node );
4446 listNewNodes.push_back( newNode );
4449 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4450 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4451 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4452 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4453 if( theFlags & EXTRUSION_FLAG_SEW ) {
4454 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4455 theTolerance, theParams.myNodes);
4456 listNewNodes.push_back( newNode );
4457 //vecNewNodes[i]=newNode;
4460 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4461 myLastCreatedNodes.Append(newNode);
4462 srcNodes.Append( node );
4463 listNewNodes.push_back( newNode );
4464 //vecNewNodes[i]=newNode;
4469 // if current elem is quadratic and current node is not medium
4470 // we have to check - may be it is needed to insert additional nodes
4471 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4472 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4473 if(listNewNodes.size()==nbsteps) {
4474 listNewNodes.clear();
4475 double coord[] = { node->X(), node->Y(), node->Z() };
4476 for ( int i = 0; i < nbsteps; i++ ) {
4477 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4478 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4479 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4480 if( theFlags & EXTRUSION_FLAG_SEW ) {
4481 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4482 theTolerance, theParams.myNodes);
4483 listNewNodes.push_back( newNode );
4486 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4487 myLastCreatedNodes.Append(newNode);
4488 srcNodes.Append( node );
4489 listNewNodes.push_back( newNode );
4491 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4492 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4493 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4494 if( theFlags & EXTRUSION_FLAG_SEW ) {
4495 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4496 theTolerance, theParams.myNodes);
4497 listNewNodes.push_back( newNode );
4500 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4501 myLastCreatedNodes.Append(newNode);
4502 srcNodes.Append( node );
4503 listNewNodes.push_back( newNode );
4509 newNodesItVec.push_back( nIt );
4511 // make new elements
4512 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4515 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4516 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4518 PGroupIDs newGroupIDs;
4519 if ( theMakeGroups )
4520 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4526 //=======================================================================
4527 //class : SMESH_MeshEditor_PathPoint
4528 //purpose : auxiliary class
4529 //=======================================================================
4530 class SMESH_MeshEditor_PathPoint {
4532 SMESH_MeshEditor_PathPoint() {
4533 myPnt.SetCoord(99., 99., 99.);
4534 myTgt.SetCoord(1.,0.,0.);
4538 void SetPnt(const gp_Pnt& aP3D){
4541 void SetTangent(const gp_Dir& aTgt){
4544 void SetAngle(const double& aBeta){
4547 void SetParameter(const double& aPrm){
4550 const gp_Pnt& Pnt()const{
4553 const gp_Dir& Tangent()const{
4556 double Angle()const{
4559 double Parameter()const{
4571 //=======================================================================
4572 //function : ExtrusionAlongTrack
4574 //=======================================================================
4575 SMESH_MeshEditor::Extrusion_Error
4576 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4577 SMESH_subMesh* theTrack,
4578 const SMDS_MeshNode* theN1,
4579 const bool theHasAngles,
4580 list<double>& theAngles,
4581 const bool theLinearVariation,
4582 const bool theHasRefPoint,
4583 const gp_Pnt& theRefPoint,
4584 const bool theMakeGroups)
4586 MESSAGE("ExtrusionAlongTrack");
4587 myLastCreatedElems.Clear();
4588 myLastCreatedNodes.Clear();
4591 std::list<double> aPrms;
4592 TIDSortedElemSet::iterator itElem;
4595 TopoDS_Edge aTrackEdge;
4596 TopoDS_Vertex aV1, aV2;
4598 SMDS_ElemIteratorPtr aItE;
4599 SMDS_NodeIteratorPtr aItN;
4600 SMDSAbs_ElementType aTypeE;
4602 TNodeOfNodeListMap mapNewNodes;
4605 aNbE = theElements.size();
4608 return EXTR_NO_ELEMENTS;
4610 // 1.1 Track Pattern
4613 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4615 aItE = pSubMeshDS->GetElements();
4616 while ( aItE->more() ) {
4617 const SMDS_MeshElement* pE = aItE->next();
4618 aTypeE = pE->GetType();
4619 // Pattern must contain links only
4620 if ( aTypeE != SMDSAbs_Edge )
4621 return EXTR_PATH_NOT_EDGE;
4624 list<SMESH_MeshEditor_PathPoint> fullList;
4626 const TopoDS_Shape& aS = theTrack->GetSubShape();
4627 // Sub shape for the Pattern must be an Edge or Wire
4628 if( aS.ShapeType() == TopAbs_EDGE ) {
4629 aTrackEdge = TopoDS::Edge( aS );
4630 // the Edge must not be degenerated
4631 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4632 return EXTR_BAD_PATH_SHAPE;
4633 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4634 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4635 const SMDS_MeshNode* aN1 = aItN->next();
4636 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4637 const SMDS_MeshNode* aN2 = aItN->next();
4638 // starting node must be aN1 or aN2
4639 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4640 return EXTR_BAD_STARTING_NODE;
4641 aItN = pSubMeshDS->GetNodes();
4642 while ( aItN->more() ) {
4643 const SMDS_MeshNode* pNode = aItN->next();
4644 const SMDS_EdgePosition* pEPos =
4645 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4646 double aT = pEPos->GetUParameter();
4647 aPrms.push_back( aT );
4649 //Extrusion_Error err =
4650 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4652 else if( aS.ShapeType() == TopAbs_WIRE ) {
4653 list< SMESH_subMesh* > LSM;
4654 TopTools_SequenceOfShape Edges;
4655 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4656 while(itSM->more()) {
4657 SMESH_subMesh* SM = itSM->next();
4659 const TopoDS_Shape& aS = SM->GetSubShape();
4662 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4663 int startNid = theN1->GetID();
4664 TColStd_MapOfInteger UsedNums;
4665 int NbEdges = Edges.Length();
4667 for(; i<=NbEdges; i++) {
4669 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4670 for(; itLSM!=LSM.end(); itLSM++) {
4672 if(UsedNums.Contains(k)) continue;
4673 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4674 SMESH_subMesh* locTrack = *itLSM;
4675 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4676 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4677 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4678 const SMDS_MeshNode* aN1 = aItN->next();
4679 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4680 const SMDS_MeshNode* aN2 = aItN->next();
4681 // starting node must be aN1 or aN2
4682 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4683 // 2. Collect parameters on the track edge
4685 aItN = locMeshDS->GetNodes();
4686 while ( aItN->more() ) {
4687 const SMDS_MeshNode* pNode = aItN->next();
4688 const SMDS_EdgePosition* pEPos =
4689 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4690 double aT = pEPos->GetUParameter();
4691 aPrms.push_back( aT );
4693 list<SMESH_MeshEditor_PathPoint> LPP;
4694 //Extrusion_Error err =
4695 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4696 LLPPs.push_back(LPP);
4698 // update startN for search following egde
4699 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4700 else startNid = aN1->GetID();
4704 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4705 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4706 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4707 for(; itPP!=firstList.end(); itPP++) {
4708 fullList.push_back( *itPP );
4710 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4711 fullList.pop_back();
4713 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4714 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4715 itPP = currList.begin();
4716 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4717 gp_Dir D1 = PP1.Tangent();
4718 gp_Dir D2 = PP2.Tangent();
4719 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4720 (D1.Z()+D2.Z())/2 ) );
4721 PP1.SetTangent(Dnew);
4722 fullList.push_back(PP1);
4724 for(; itPP!=firstList.end(); itPP++) {
4725 fullList.push_back( *itPP );
4727 PP1 = fullList.back();
4728 fullList.pop_back();
4730 // if wire not closed
4731 fullList.push_back(PP1);
4735 return EXTR_BAD_PATH_SHAPE;
4738 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4739 theHasRefPoint, theRefPoint, theMakeGroups);
4743 //=======================================================================
4744 //function : ExtrusionAlongTrack
4746 //=======================================================================
4747 SMESH_MeshEditor::Extrusion_Error
4748 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4749 SMESH_Mesh* theTrack,
4750 const SMDS_MeshNode* theN1,
4751 const bool theHasAngles,
4752 list<double>& theAngles,
4753 const bool theLinearVariation,
4754 const bool theHasRefPoint,
4755 const gp_Pnt& theRefPoint,
4756 const bool theMakeGroups)
4758 myLastCreatedElems.Clear();
4759 myLastCreatedNodes.Clear();
4762 std::list<double> aPrms;
4763 TIDSortedElemSet::iterator itElem;
4766 TopoDS_Edge aTrackEdge;
4767 TopoDS_Vertex aV1, aV2;
4769 SMDS_ElemIteratorPtr aItE;
4770 SMDS_NodeIteratorPtr aItN;
4771 SMDSAbs_ElementType aTypeE;
4773 TNodeOfNodeListMap mapNewNodes;
4776 aNbE = theElements.size();
4779 return EXTR_NO_ELEMENTS;
4781 // 1.1 Track Pattern
4784 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4786 aItE = pMeshDS->elementsIterator();
4787 while ( aItE->more() ) {
4788 const SMDS_MeshElement* pE = aItE->next();
4789 aTypeE = pE->GetType();
4790 // Pattern must contain links only
4791 if ( aTypeE != SMDSAbs_Edge )
4792 return EXTR_PATH_NOT_EDGE;
4795 list<SMESH_MeshEditor_PathPoint> fullList;
4797 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4798 // Sub shape for the Pattern must be an Edge or Wire
4799 if( aS.ShapeType() == TopAbs_EDGE ) {
4800 aTrackEdge = TopoDS::Edge( aS );
4801 // the Edge must not be degenerated
4802 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4803 return EXTR_BAD_PATH_SHAPE;
4804 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4805 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4806 const SMDS_MeshNode* aN1 = aItN->next();
4807 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4808 const SMDS_MeshNode* aN2 = aItN->next();
4809 // starting node must be aN1 or aN2
4810 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4811 return EXTR_BAD_STARTING_NODE;
4812 aItN = pMeshDS->nodesIterator();
4813 while ( aItN->more() ) {
4814 const SMDS_MeshNode* pNode = aItN->next();
4815 if( pNode==aN1 || pNode==aN2 ) continue;
4816 const SMDS_EdgePosition* pEPos =
4817 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4818 double aT = pEPos->GetUParameter();
4819 aPrms.push_back( aT );
4821 //Extrusion_Error err =
4822 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4824 else if( aS.ShapeType() == TopAbs_WIRE ) {
4825 list< SMESH_subMesh* > LSM;
4826 TopTools_SequenceOfShape Edges;
4827 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4828 for(; eExp.More(); eExp.Next()) {
4829 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4830 if( BRep_Tool::Degenerated(E) ) continue;
4831 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4837 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4838 int startNid = theN1->GetID();
4839 TColStd_MapOfInteger UsedNums;
4840 int NbEdges = Edges.Length();
4842 for(; i<=NbEdges; i++) {
4844 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4845 for(; itLSM!=LSM.end(); itLSM++) {
4847 if(UsedNums.Contains(k)) continue;
4848 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4849 SMESH_subMesh* locTrack = *itLSM;
4850 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4851 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4852 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4853 const SMDS_MeshNode* aN1 = aItN->next();
4854 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4855 const SMDS_MeshNode* aN2 = aItN->next();
4856 // starting node must be aN1 or aN2
4857 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4858 // 2. Collect parameters on the track edge
4860 aItN = locMeshDS->GetNodes();
4861 while ( aItN->more() ) {
4862 const SMDS_MeshNode* pNode = aItN->next();
4863 const SMDS_EdgePosition* pEPos =
4864 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4865 double aT = pEPos->GetUParameter();
4866 aPrms.push_back( aT );
4868 list<SMESH_MeshEditor_PathPoint> LPP;
4869 //Extrusion_Error err =
4870 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4871 LLPPs.push_back(LPP);
4873 // update startN for search following egde
4874 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4875 else startNid = aN1->GetID();
4879 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4880 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4881 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4882 for(; itPP!=firstList.end(); itPP++) {
4883 fullList.push_back( *itPP );
4885 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4886 fullList.pop_back();
4888 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4889 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4890 itPP = currList.begin();
4891 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4892 gp_Pnt P1 = PP1.Pnt();
4893 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4894 gp_Pnt P2 = PP2.Pnt();
4895 gp_Dir D1 = PP1.Tangent();
4896 gp_Dir D2 = PP2.Tangent();
4897 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4898 (D1.Z()+D2.Z())/2 ) );
4899 PP1.SetTangent(Dnew);
4900 fullList.push_back(PP1);
4902 for(; itPP!=currList.end(); itPP++) {
4903 fullList.push_back( *itPP );
4905 PP1 = fullList.back();
4906 fullList.pop_back();
4908 // if wire not closed
4909 fullList.push_back(PP1);
4913 return EXTR_BAD_PATH_SHAPE;
4916 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4917 theHasRefPoint, theRefPoint, theMakeGroups);
4921 //=======================================================================
4922 //function : MakeEdgePathPoints
4923 //purpose : auxilary for ExtrusionAlongTrack
4924 //=======================================================================
4925 SMESH_MeshEditor::Extrusion_Error
4926 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4927 const TopoDS_Edge& aTrackEdge,
4929 list<SMESH_MeshEditor_PathPoint>& LPP)
4931 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4933 aTolVec2=aTolVec*aTolVec;
4935 TopoDS_Vertex aV1, aV2;
4936 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4937 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4938 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4939 // 2. Collect parameters on the track edge
4940 aPrms.push_front( aT1 );
4941 aPrms.push_back( aT2 );
4944 if( FirstIsStart ) {
4955 SMESH_MeshEditor_PathPoint aPP;
4956 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4957 std::list<double>::iterator aItD = aPrms.begin();
4958 for(; aItD != aPrms.end(); ++aItD) {
4962 aC3D->D1( aT, aP3D, aVec );
4963 aL2 = aVec.SquareMagnitude();
4964 if ( aL2 < aTolVec2 )
4965 return EXTR_CANT_GET_TANGENT;
4966 gp_Dir aTgt( aVec );
4968 aPP.SetTangent( aTgt );
4969 aPP.SetParameter( aT );
4976 //=======================================================================
4977 //function : MakeExtrElements
4978 //purpose : auxilary for ExtrusionAlongTrack
4979 //=======================================================================
4980 SMESH_MeshEditor::Extrusion_Error
4981 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4982 list<SMESH_MeshEditor_PathPoint>& fullList,
4983 const bool theHasAngles,
4984 list<double>& theAngles,
4985 const bool theLinearVariation,
4986 const bool theHasRefPoint,
4987 const gp_Pnt& theRefPoint,
4988 const bool theMakeGroups)
4990 MESSAGE("MakeExtrElements");
4991 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
4992 int aNbTP = fullList.size();
4993 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
4995 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
4996 LinearAngleVariation(aNbTP-1, theAngles);
4998 vector<double> aAngles( aNbTP );
5000 for(; j<aNbTP; ++j) {
5003 if ( theHasAngles ) {
5005 std::list<double>::iterator aItD = theAngles.begin();
5006 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5008 aAngles[j] = anAngle;
5011 // fill vector of path points with angles
5012 //aPPs.resize(fullList.size());
5014 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5015 for(; itPP!=fullList.end(); itPP++) {
5017 SMESH_MeshEditor_PathPoint PP = *itPP;
5018 PP.SetAngle(aAngles[j]);
5022 TNodeOfNodeListMap mapNewNodes;
5023 TElemOfVecOfNnlmiMap mapElemNewNodes;
5024 TElemOfElemListMap newElemsMap;
5025 TIDSortedElemSet::iterator itElem;
5028 SMDSAbs_ElementType aTypeE;
5029 // source elements for each generated one
5030 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5032 // 3. Center of rotation aV0
5033 gp_Pnt aV0 = theRefPoint;
5035 if ( !theHasRefPoint ) {
5037 aGC.SetCoord( 0.,0.,0. );
5039 itElem = theElements.begin();
5040 for ( ; itElem != theElements.end(); itElem++ ) {
5041 const SMDS_MeshElement* elem = *itElem;
5043 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5044 while ( itN->more() ) {
5045 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5050 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5051 list<const SMDS_MeshNode*> aLNx;
5052 mapNewNodes[node] = aLNx;
5054 gp_XYZ aXYZ( aX, aY, aZ );
5062 } // if (!theHasRefPoint) {
5063 mapNewNodes.clear();
5065 // 4. Processing the elements
5066 SMESHDS_Mesh* aMesh = GetMeshDS();
5068 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5069 // check element type
5070 const SMDS_MeshElement* elem = *itElem;
5071 aTypeE = elem->GetType();
5072 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5075 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5076 newNodesItVec.reserve( elem->NbNodes() );
5078 // loop on elem nodes
5080 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5081 while ( itN->more() )
5084 // check if a node has been already processed
5085 const SMDS_MeshNode* node =
5086 static_cast<const SMDS_MeshNode*>( itN->next() );
5087 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5088 if ( nIt == mapNewNodes.end() ) {
5089 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5090 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5093 aX = node->X(); aY = node->Y(); aZ = node->Z();
5095 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5096 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5097 gp_Ax1 anAx1, anAxT1T0;
5098 gp_Dir aDT1x, aDT0x, aDT1T0;
5103 aPN0.SetCoord(aX, aY, aZ);
5105 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5107 aDT0x= aPP0.Tangent();
5108 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5110 for ( j = 1; j < aNbTP; ++j ) {
5111 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5113 aDT1x = aPP1.Tangent();
5114 aAngle1x = aPP1.Angle();
5116 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5118 gp_Vec aV01x( aP0x, aP1x );
5119 aTrsf.SetTranslation( aV01x );
5122 aV1x = aV0x.Transformed( aTrsf );
5123 aPN1 = aPN0.Transformed( aTrsf );
5125 // rotation 1 [ T1,T0 ]
5126 aAngleT1T0=-aDT1x.Angle( aDT0x );
5127 if (fabs(aAngleT1T0) > aTolAng) {
5129 anAxT1T0.SetLocation( aV1x );
5130 anAxT1T0.SetDirection( aDT1T0 );
5131 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5133 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5137 if ( theHasAngles ) {
5138 anAx1.SetLocation( aV1x );
5139 anAx1.SetDirection( aDT1x );
5140 aTrsfRot.SetRotation( anAx1, aAngle1x );
5142 aPN1 = aPN1.Transformed( aTrsfRot );
5146 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5147 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5148 // create additional node
5149 double x = ( aPN1.X() + aPN0.X() )/2.;
5150 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5151 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5152 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5153 myLastCreatedNodes.Append(newNode);
5154 srcNodes.Append( node );
5155 listNewNodes.push_back( newNode );
5160 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5161 myLastCreatedNodes.Append(newNode);
5162 srcNodes.Append( node );
5163 listNewNodes.push_back( newNode );
5173 // if current elem is quadratic and current node is not medium
5174 // we have to check - may be it is needed to insert additional nodes
5175 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5176 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5177 if(listNewNodes.size()==aNbTP-1) {
5178 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5179 gp_XYZ P(node->X(), node->Y(), node->Z());
5180 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5182 for(i=0; i<aNbTP-1; i++) {
5183 const SMDS_MeshNode* N = *it;
5184 double x = ( N->X() + P.X() )/2.;
5185 double y = ( N->Y() + P.Y() )/2.;
5186 double z = ( N->Z() + P.Z() )/2.;
5187 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5188 srcNodes.Append( node );
5189 myLastCreatedNodes.Append(newN);
5192 P = gp_XYZ(N->X(),N->Y(),N->Z());
5194 listNewNodes.clear();
5195 for(i=0; i<2*(aNbTP-1); i++) {
5196 listNewNodes.push_back(aNodes[i]);
5202 newNodesItVec.push_back( nIt );
5204 // make new elements
5205 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5206 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5207 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5210 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5212 if ( theMakeGroups )
5213 generateGroups( srcNodes, srcElems, "extruded");
5219 //=======================================================================
5220 //function : LinearAngleVariation
5221 //purpose : auxilary for ExtrusionAlongTrack
5222 //=======================================================================
5223 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5224 list<double>& Angles)
5226 int nbAngles = Angles.size();
5227 if( nbSteps > nbAngles ) {
5228 vector<double> theAngles(nbAngles);
5229 list<double>::iterator it = Angles.begin();
5231 for(; it!=Angles.end(); it++) {
5233 theAngles[i] = (*it);
5236 double rAn2St = double( nbAngles ) / double( nbSteps );
5237 double angPrev = 0, angle;
5238 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5239 double angCur = rAn2St * ( iSt+1 );
5240 double angCurFloor = floor( angCur );
5241 double angPrevFloor = floor( angPrev );
5242 if ( angPrevFloor == angCurFloor )
5243 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5245 int iP = int( angPrevFloor );
5246 double angPrevCeil = ceil(angPrev);
5247 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5249 int iC = int( angCurFloor );
5250 if ( iC < nbAngles )
5251 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5253 iP = int( angPrevCeil );
5255 angle += theAngles[ iC ];
5257 res.push_back(angle);
5262 for(; it!=res.end(); it++)
5263 Angles.push_back( *it );
5268 //================================================================================
5270 * \brief Move or copy theElements applying theTrsf to their nodes
5271 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5272 * \param theTrsf - transformation to apply
5273 * \param theCopy - if true, create translated copies of theElems
5274 * \param theMakeGroups - if true and theCopy, create translated groups
5275 * \param theTargetMesh - mesh to copy translated elements into
5276 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5278 //================================================================================
5280 SMESH_MeshEditor::PGroupIDs
5281 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5282 const gp_Trsf& theTrsf,
5284 const bool theMakeGroups,
5285 SMESH_Mesh* theTargetMesh)
5287 myLastCreatedElems.Clear();
5288 myLastCreatedNodes.Clear();
5290 bool needReverse = false;
5291 string groupPostfix;
5292 switch ( theTrsf.Form() ) {
5297 groupPostfix = "mirrored";
5300 groupPostfix = "rotated";
5302 case gp_Translation:
5303 groupPostfix = "translated";
5306 case gp_CompoundTrsf: // different scale by axis
5307 groupPostfix = "scaled";
5310 needReverse = false;
5311 groupPostfix = "transformed";
5314 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5315 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5316 SMESHDS_Mesh* aMesh = GetMeshDS();
5319 // map old node to new one
5320 TNodeNodeMap nodeMap;
5322 // elements sharing moved nodes; those of them which have all
5323 // nodes mirrored but are not in theElems are to be reversed
5324 TIDSortedElemSet inverseElemSet;
5326 // source elements for each generated one
5327 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5329 // // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5330 // list<SMDS_MeshNode> orphanCopy; // copies of orphan nodes
5331 // vector<const SMDS_MeshNode*> orphanNode; // original orphan nodes
5333 // if ( theElems.empty() ) // transform the whole mesh
5335 // // add all elements
5336 // SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5337 // while ( eIt->more() ) theElems.insert( eIt->next() );
5338 // // add orphan nodes
5339 // SMDS_MeshElementIDFactory idFactory;
5340 // SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5341 // while ( nIt->more() )
5343 // const SMDS_MeshNode* node = nIt->next();
5344 // if ( node->NbInverseElements() == 0 && !theElems.insert( node ).second )
5346 // // node was not inserted into theElems because an element with the same ID
5347 // // is already there. As a work around we insert a copy of node with
5348 // // an ID = -<index in orphanNode>
5349 // orphanCopy.push_back( *node ); // copy node
5350 // SMDS_MeshNode* nodeCopy = &orphanCopy.back();
5351 // int uniqueID = -orphanNode.size();
5352 // orphanNode.push_back( node );
5353 // idFactory.BindID( uniqueID, nodeCopy );
5354 // theElems.insert( nodeCopy );
5358 // loop on theElems to transorm nodes
5359 TIDSortedElemSet::iterator itElem;
5360 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5361 const SMDS_MeshElement* elem = *itElem;
5365 // loop on elem nodes
5366 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5367 while ( itN->more() ) {
5369 const SMDS_MeshNode* node = cast2Node( itN->next() );
5370 // if ( node->GetID() < 0 )
5371 // node = orphanNode[ -node->GetID() ];
5372 // check if a node has been already transformed
5373 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5374 nodeMap.insert( make_pair ( node, node ));
5375 if ( !n2n_isnew.second )
5379 coord[0] = node->X();
5380 coord[1] = node->Y();
5381 coord[2] = node->Z();
5382 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5383 if ( theTargetMesh ) {
5384 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5385 n2n_isnew.first->second = newNode;
5386 myLastCreatedNodes.Append(newNode);
5387 srcNodes.Append( node );
5389 else if ( theCopy ) {
5390 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5391 n2n_isnew.first->second = newNode;
5392 myLastCreatedNodes.Append(newNode);
5393 srcNodes.Append( node );
5396 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5397 // node position on shape becomes invalid
5398 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5399 ( SMDS_SpacePosition::originSpacePosition() );
5402 // keep inverse elements
5403 if ( !theCopy && !theTargetMesh && needReverse ) {
5404 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5405 while ( invElemIt->more() ) {
5406 const SMDS_MeshElement* iel = invElemIt->next();
5407 inverseElemSet.insert( iel );
5413 // either create new elements or reverse mirrored ones
5414 if ( !theCopy && !needReverse && !theTargetMesh )
5417 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5418 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5419 theElems.insert( *invElemIt );
5421 // replicate or reverse elements
5422 // TODO revoir ordre reverse vtk
5424 REV_TETRA = 0, // = nbNodes - 4
5425 REV_PYRAMID = 1, // = nbNodes - 4
5426 REV_PENTA = 2, // = nbNodes - 4
5428 REV_HEXA = 4, // = nbNodes - 4
5432 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5433 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5434 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5435 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5436 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5437 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5440 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5442 const SMDS_MeshElement* elem = *itElem;
5443 if ( !elem || elem->GetType() == SMDSAbs_Node )
5446 int nbNodes = elem->NbNodes();
5447 int elemType = elem->GetType();
5449 if (elem->IsPoly()) {
5450 // Polygon or Polyhedral Volume
5451 switch ( elemType ) {
5454 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5456 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5457 while (itN->more()) {
5458 const SMDS_MeshNode* node =
5459 static_cast<const SMDS_MeshNode*>(itN->next());
5460 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5461 if (nodeMapIt == nodeMap.end())
5462 break; // not all nodes transformed
5464 // reverse mirrored faces and volumes
5465 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5467 poly_nodes[iNode] = (*nodeMapIt).second;
5471 if ( iNode != nbNodes )
5472 continue; // not all nodes transformed
5474 if ( theTargetMesh ) {
5475 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5476 srcElems.Append( elem );
5478 else if ( theCopy ) {
5479 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5480 srcElems.Append( elem );
5483 aMesh->ChangePolygonNodes(elem, poly_nodes);
5487 case SMDSAbs_Volume:
5489 // ATTENTION: Reversing is not yet done!!!
5490 const SMDS_VtkVolume* aPolyedre =
5491 dynamic_cast<const SMDS_VtkVolume*>( elem );
5493 MESSAGE("Warning: bad volumic element");
5497 vector<const SMDS_MeshNode*> poly_nodes;
5498 vector<int> quantities;
5500 bool allTransformed = true;
5501 int nbFaces = aPolyedre->NbFaces();
5502 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5503 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5504 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5505 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5506 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5507 if (nodeMapIt == nodeMap.end()) {
5508 allTransformed = false; // not all nodes transformed
5510 poly_nodes.push_back((*nodeMapIt).second);
5513 quantities.push_back(nbFaceNodes);
5515 if ( !allTransformed )
5516 continue; // not all nodes transformed
5518 if ( theTargetMesh ) {
5519 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5520 srcElems.Append( elem );
5522 else if ( theCopy ) {
5523 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5524 srcElems.Append( elem );
5527 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5537 int* i = index[ FORWARD ];
5538 if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5539 if ( elemType == SMDSAbs_Face )
5540 i = index[ REV_FACE ];
5542 i = index[ nbNodes - 4 ];
5544 if(elem->IsQuadratic()) {
5545 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5548 if(nbNodes==3) { // quadratic edge
5549 static int anIds[] = {1,0,2};
5552 else if(nbNodes==6) { // quadratic triangle
5553 static int anIds[] = {0,2,1,5,4,3};
5556 else if(nbNodes==8) { // quadratic quadrangle
5557 static int anIds[] = {0,3,2,1,7,6,5,4};
5560 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5561 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5564 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5565 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5568 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5569 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5572 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5573 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5579 // find transformed nodes
5580 vector<const SMDS_MeshNode*> nodes(nbNodes);
5582 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5583 while ( itN->more() ) {
5584 const SMDS_MeshNode* node =
5585 static_cast<const SMDS_MeshNode*>( itN->next() );
5586 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5587 if ( nodeMapIt == nodeMap.end() )
5588 break; // not all nodes transformed
5589 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5591 if ( iNode != nbNodes )
5592 continue; // not all nodes transformed
5594 if ( theTargetMesh ) {
5595 if ( SMDS_MeshElement* copy =
5596 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5597 myLastCreatedElems.Append( copy );
5598 srcElems.Append( elem );
5601 else if ( theCopy ) {
5602 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5603 srcElems.Append( elem );
5606 // reverse element as it was reversed by transformation
5608 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5612 PGroupIDs newGroupIDs;
5614 if ( theMakeGroups && theCopy ||
5615 theMakeGroups && theTargetMesh )
5616 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5622 ////=======================================================================
5623 ////function : Scale
5625 ////=======================================================================
5627 //SMESH_MeshEditor::PGroupIDs
5628 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5629 // const gp_Pnt& thePoint,
5630 // const std::list<double>& theScaleFact,
5631 // const bool theCopy,
5632 // const bool theMakeGroups,
5633 // SMESH_Mesh* theTargetMesh)
5635 // MESSAGE("Scale");
5636 // myLastCreatedElems.Clear();
5637 // myLastCreatedNodes.Clear();
5639 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5640 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5641 // SMESHDS_Mesh* aMesh = GetMeshDS();
5643 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5644 // std::list<double>::const_iterator itS = theScaleFact.begin();
5646 // if(theScaleFact.size()==1) {
5650 // if(theScaleFact.size()==2) {
5655 // if(theScaleFact.size()>2) {
5662 // // map old node to new one
5663 // TNodeNodeMap nodeMap;
5665 // // elements sharing moved nodes; those of them which have all
5666 // // nodes mirrored but are not in theElems are to be reversed
5667 // TIDSortedElemSet inverseElemSet;
5669 // // source elements for each generated one
5670 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5672 // // loop on theElems
5673 // TIDSortedElemSet::iterator itElem;
5674 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5675 // const SMDS_MeshElement* elem = *itElem;
5679 // // loop on elem nodes
5680 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5681 // while ( itN->more() ) {
5683 // // check if a node has been already transformed
5684 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5685 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5686 // nodeMap.insert( make_pair ( node, node ));
5687 // if ( !n2n_isnew.second )
5690 // //double coord[3];
5691 // //coord[0] = node->X();
5692 // //coord[1] = node->Y();
5693 // //coord[2] = node->Z();
5694 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5695 // double dx = (node->X() - thePoint.X()) * scaleX;
5696 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5697 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5698 // if ( theTargetMesh ) {
5699 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5700 // const SMDS_MeshNode * newNode =
5701 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5702 // n2n_isnew.first->second = newNode;
5703 // myLastCreatedNodes.Append(newNode);
5704 // srcNodes.Append( node );
5706 // else if ( theCopy ) {
5707 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5708 // const SMDS_MeshNode * newNode =
5709 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5710 // n2n_isnew.first->second = newNode;
5711 // myLastCreatedNodes.Append(newNode);
5712 // srcNodes.Append( node );
5715 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5716 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5717 // // node position on shape becomes invalid
5718 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5719 // ( SMDS_SpacePosition::originSpacePosition() );
5722 // // keep inverse elements
5723 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5724 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5725 // // while ( invElemIt->more() ) {
5726 // // const SMDS_MeshElement* iel = invElemIt->next();
5727 // // inverseElemSet.insert( iel );
5733 // // either create new elements or reverse mirrored ones
5734 // //if ( !theCopy && !needReverse && !theTargetMesh )
5735 // if ( !theCopy && !theTargetMesh )
5736 // return PGroupIDs();
5738 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5739 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5740 // theElems.insert( *invElemIt );
5742 // // replicate or reverse elements
5745 // REV_TETRA = 0, // = nbNodes - 4
5746 // REV_PYRAMID = 1, // = nbNodes - 4
5747 // REV_PENTA = 2, // = nbNodes - 4
5749 // REV_HEXA = 4, // = nbNodes - 4
5752 // int index[][8] = {
5753 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5754 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5755 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5756 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5757 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5758 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5761 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5763 // const SMDS_MeshElement* elem = *itElem;
5764 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5767 // int nbNodes = elem->NbNodes();
5768 // int elemType = elem->GetType();
5770 // if (elem->IsPoly()) {
5771 // // Polygon or Polyhedral Volume
5772 // switch ( elemType ) {
5773 // case SMDSAbs_Face:
5775 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5777 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5778 // while (itN->more()) {
5779 // const SMDS_MeshNode* node =
5780 // static_cast<const SMDS_MeshNode*>(itN->next());
5781 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5782 // if (nodeMapIt == nodeMap.end())
5783 // break; // not all nodes transformed
5784 // //if (needReverse) {
5785 // // // reverse mirrored faces and volumes
5786 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5788 // poly_nodes[iNode] = (*nodeMapIt).second;
5792 // if ( iNode != nbNodes )
5793 // continue; // not all nodes transformed
5795 // if ( theTargetMesh ) {
5796 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5797 // srcElems.Append( elem );
5799 // else if ( theCopy ) {
5800 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5801 // srcElems.Append( elem );
5804 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5808 // case SMDSAbs_Volume:
5810 // // ATTENTION: Reversing is not yet done!!!
5811 // const SMDS_VtkVolume* aPolyedre =
5812 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5813 // if (!aPolyedre) {
5814 // MESSAGE("Warning: bad volumic element");
5818 // vector<const SMDS_MeshNode*> poly_nodes;
5819 // vector<int> quantities;
5821 // bool allTransformed = true;
5822 // int nbFaces = aPolyedre->NbFaces();
5823 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5824 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5825 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5826 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5827 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5828 // if (nodeMapIt == nodeMap.end()) {
5829 // allTransformed = false; // not all nodes transformed
5831 // poly_nodes.push_back((*nodeMapIt).second);
5834 // quantities.push_back(nbFaceNodes);
5836 // if ( !allTransformed )
5837 // continue; // not all nodes transformed
5839 // if ( theTargetMesh ) {
5840 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5841 // srcElems.Append( elem );
5843 // else if ( theCopy ) {
5844 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5845 // srcElems.Append( elem );
5848 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5857 // // Regular elements
5858 // int* i = index[ FORWARD ];
5859 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5860 // // if ( elemType == SMDSAbs_Face )
5861 // // i = index[ REV_FACE ];
5863 // // i = index[ nbNodes - 4 ];
5865 // if(elem->IsQuadratic()) {
5866 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5868 // //if(needReverse) {
5869 // // if(nbNodes==3) { // quadratic edge
5870 // // static int anIds[] = {1,0,2};
5873 // // else if(nbNodes==6) { // quadratic triangle
5874 // // static int anIds[] = {0,2,1,5,4,3};
5877 // // else if(nbNodes==8) { // quadratic quadrangle
5878 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5881 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5882 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5885 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5886 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5889 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5890 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5893 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5894 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5900 // // find transformed nodes
5901 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5903 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5904 // while ( itN->more() ) {
5905 // const SMDS_MeshNode* node =
5906 // static_cast<const SMDS_MeshNode*>( itN->next() );
5907 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5908 // if ( nodeMapIt == nodeMap.end() )
5909 // break; // not all nodes transformed
5910 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5912 // if ( iNode != nbNodes )
5913 // continue; // not all nodes transformed
5915 // if ( theTargetMesh ) {
5916 // if ( SMDS_MeshElement* copy =
5917 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5918 // myLastCreatedElems.Append( copy );
5919 // srcElems.Append( elem );
5922 // else if ( theCopy ) {
5923 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5924 // myLastCreatedElems.Append( copy );
5925 // srcElems.Append( elem );
5929 // // reverse element as it was reversed by transformation
5930 // if ( nbNodes > 2 )
5931 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5935 // PGroupIDs newGroupIDs;
5937 // if ( theMakeGroups && theCopy ||
5938 // theMakeGroups && theTargetMesh ) {
5939 // string groupPostfix = "scaled";
5940 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5943 // return newGroupIDs;
5947 //=======================================================================
5949 * \brief Create groups of elements made during transformation
5950 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5951 * \param elemGens - elements making corresponding myLastCreatedElems
5952 * \param postfix - to append to names of new groups
5954 //=======================================================================
5956 SMESH_MeshEditor::PGroupIDs
5957 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5958 const SMESH_SequenceOfElemPtr& elemGens,
5959 const std::string& postfix,
5960 SMESH_Mesh* targetMesh)
5962 PGroupIDs newGroupIDs( new list<int> );
5963 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5965 // Sort existing groups by types and collect their names
5967 // to store an old group and a generated new one
5968 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5969 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5971 set< string > groupNames;
5973 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5974 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5975 while ( groupIt->more() ) {
5976 SMESH_Group * group = groupIt->next();
5977 if ( !group ) continue;
5978 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5979 if ( !groupDS || groupDS->IsEmpty() ) continue;
5980 groupNames.insert( group->GetName() );
5981 groupDS->SetStoreName( group->GetName() );
5982 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
5987 // loop on nodes and elements
5988 for ( int isNodes = 0; isNodes < 2; ++isNodes )
5990 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
5991 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
5992 if ( gens.Length() != elems.Length() )
5993 throw SALOME_Exception(LOCALIZED("invalid args"));
5995 // loop on created elements
5996 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
5998 const SMDS_MeshElement* sourceElem = gens( iElem );
5999 if ( !sourceElem ) {
6000 MESSAGE("generateGroups(): NULL source element");
6003 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6004 if ( groupsOldNew.empty() ) {
6005 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6006 ++iElem; // skip all elements made by sourceElem
6009 // collect all elements made by sourceElem
6010 list< const SMDS_MeshElement* > resultElems;
6011 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6012 if ( resElem != sourceElem )
6013 resultElems.push_back( resElem );
6014 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6015 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6016 if ( resElem != sourceElem )
6017 resultElems.push_back( resElem );
6018 // do not generate element groups from node ones
6019 if ( sourceElem->GetType() == SMDSAbs_Node &&
6020 elems( iElem )->GetType() != SMDSAbs_Node )
6023 // add resultElems to groups made by ones the sourceElem belongs to
6024 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6025 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6027 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6028 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6030 SMDS_MeshGroup* & newGroup = gOldNew->second;
6031 if ( !newGroup )// create a new group
6034 string name = oldGroup->GetStoreName();
6035 if ( !targetMesh ) {
6039 while ( !groupNames.insert( name ).second ) // name exists
6045 TCollection_AsciiString nbStr(nb+1);
6046 name.resize( name.rfind('_')+1 );
6047 name += nbStr.ToCString();
6054 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6056 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6057 newGroup = & groupDS->SMDSGroup();
6058 newGroupIDs->push_back( id );
6061 // fill in a new group
6062 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6063 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6064 newGroup->Add( *resElemIt );
6067 } // loop on created elements
6068 }// loop on nodes and elements
6073 //================================================================================
6075 * \brief Return list of group of nodes close to each other within theTolerance
6076 * Search among theNodes or in the whole mesh if theNodes is empty using
6077 * an Octree algorithm
6079 //================================================================================
6081 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6082 const double theTolerance,
6083 TListOfListOfNodes & theGroupsOfNodes)
6085 myLastCreatedElems.Clear();
6086 myLastCreatedNodes.Clear();
6088 if ( theNodes.empty() )
6089 { // get all nodes in the mesh
6090 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6091 while ( nIt->more() )
6092 theNodes.insert( theNodes.end(),nIt->next());
6095 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6099 //=======================================================================
6101 * \brief Implementation of search for the node closest to point
6103 //=======================================================================
6105 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6107 //---------------------------------------------------------------------
6109 * \brief Constructor
6111 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6113 myMesh = ( SMESHDS_Mesh* ) theMesh;
6115 TIDSortedNodeSet nodes;
6117 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6118 while ( nIt->more() )
6119 nodes.insert( nodes.end(), nIt->next() );
6121 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6123 // get max size of a leaf box
6124 SMESH_OctreeNode* tree = myOctreeNode;
6125 while ( !tree->isLeaf() )
6127 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6131 myHalfLeafSize = tree->maxSize() / 2.;
6134 //---------------------------------------------------------------------
6136 * \brief Move node and update myOctreeNode accordingly
6138 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6140 myOctreeNode->UpdateByMoveNode( node, toPnt );
6141 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6144 //---------------------------------------------------------------------
6146 * \brief Do it's job
6148 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6150 map<double, const SMDS_MeshNode*> dist2Nodes;
6151 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6152 if ( !dist2Nodes.empty() )
6153 return dist2Nodes.begin()->second;
6154 list<const SMDS_MeshNode*> nodes;
6155 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6157 double minSqDist = DBL_MAX;
6158 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6160 // sort leafs by their distance from thePnt
6161 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6162 TDistTreeMap treeMap;
6163 list< SMESH_OctreeNode* > treeList;
6164 list< SMESH_OctreeNode* >::iterator trIt;
6165 treeList.push_back( myOctreeNode );
6167 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6168 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6169 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6171 SMESH_OctreeNode* tree = *trIt;
6172 if ( !tree->isLeaf() ) // put children to the queue
6174 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6175 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6176 while ( cIt->more() )
6177 treeList.push_back( cIt->next() );
6179 else if ( tree->NbNodes() ) // put a tree to the treeMap
6181 const Bnd_B3d& box = tree->getBox();
6182 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6183 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6184 if ( !it_in.second ) // not unique distance to box center
6185 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6188 // find distance after which there is no sense to check tree's
6189 double sqLimit = DBL_MAX;
6190 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6191 if ( treeMap.size() > 5 ) {
6192 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6193 const Bnd_B3d& box = closestTree->getBox();
6194 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6195 sqLimit = limit * limit;
6197 // get all nodes from trees
6198 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6199 if ( sqDist_tree->first > sqLimit )
6201 SMESH_OctreeNode* tree = sqDist_tree->second;
6202 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6205 // find closest among nodes
6206 minSqDist = DBL_MAX;
6207 const SMDS_MeshNode* closestNode = 0;
6208 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6209 for ( ; nIt != nodes.end(); ++nIt ) {
6210 double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
6211 if ( minSqDist > sqDist ) {
6219 //---------------------------------------------------------------------
6223 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6225 //---------------------------------------------------------------------
6227 * \brief Return the node tree
6229 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6232 SMESH_OctreeNode* myOctreeNode;
6233 SMESHDS_Mesh* myMesh;
6234 double myHalfLeafSize; // max size of a leaf box
6237 //=======================================================================
6239 * \brief Return SMESH_NodeSearcher
6241 //=======================================================================
6243 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6245 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6248 // ========================================================================
6249 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6251 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6252 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6253 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6255 //=======================================================================
6257 * \brief Octal tree of bounding boxes of elements
6259 //=======================================================================
6261 class ElementBndBoxTree : public SMESH_Octree
6265 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
6266 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6267 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6268 ~ElementBndBoxTree();
6271 ElementBndBoxTree() {}
6272 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6273 void buildChildrenData();
6274 Bnd_B3d* buildRootBox();
6276 //!< Bounding box of element
6277 struct ElementBox : public Bnd_B3d
6279 const SMDS_MeshElement* _element;
6280 int _refCount; // an ElementBox can be included in several tree branches
6281 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6283 vector< ElementBox* > _elements;
6286 //================================================================================
6288 * \brief ElementBndBoxTree creation
6290 //================================================================================
6292 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
6293 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6295 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6296 _elements.reserve( nbElems );
6298 SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
6299 while ( elemIt->more() )
6300 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6302 if ( _elements.size() > MaxNbElemsInLeaf )
6308 //================================================================================
6312 //================================================================================
6314 ElementBndBoxTree::~ElementBndBoxTree()
6316 for ( int i = 0; i < _elements.size(); ++i )
6317 if ( --_elements[i]->_refCount <= 0 )
6318 delete _elements[i];
6321 //================================================================================
6323 * \brief Return the maximal box
6325 //================================================================================
6327 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6329 Bnd_B3d* box = new Bnd_B3d;
6330 for ( int i = 0; i < _elements.size(); ++i )
6331 box->Add( *_elements[i] );
6335 //================================================================================
6337 * \brief Redistrubute element boxes among children
6339 //================================================================================
6341 void ElementBndBoxTree::buildChildrenData()
6343 for ( int i = 0; i < _elements.size(); ++i )
6345 for (int j = 0; j < 8; j++)
6347 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6349 _elements[i]->_refCount++;
6350 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6353 _elements[i]->_refCount--;
6357 for (int j = 0; j < 8; j++)
6359 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6360 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6361 child->myIsLeaf = true;
6363 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6364 child->_elements.resize( child->_elements.size() ); // compact
6368 //================================================================================
6370 * \brief Return elements which can include the point
6372 //================================================================================
6374 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6375 TIDSortedElemSet& foundElems)
6377 if ( level() && getBox().IsOut( point.XYZ() ))
6382 for ( int i = 0; i < _elements.size(); ++i )
6383 if ( !_elements[i]->IsOut( point.XYZ() ))
6384 foundElems.insert( _elements[i]->_element );
6388 for (int i = 0; i < 8; i++)
6389 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6393 //================================================================================
6395 * \brief Return elements which can be intersected by the line
6397 //================================================================================
6399 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6400 TIDSortedElemSet& foundElems)
6402 if ( level() && getBox().IsOut( line ))
6407 for ( int i = 0; i < _elements.size(); ++i )
6408 if ( !_elements[i]->IsOut( line ))
6409 foundElems.insert( _elements[i]->_element );
6413 for (int i = 0; i < 8; i++)
6414 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6418 //================================================================================
6420 * \brief Construct the element box
6422 //================================================================================
6424 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6428 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6429 while ( nIt->more() )
6430 Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
6431 Enlarge( tolerance );
6436 //=======================================================================
6438 * \brief Implementation of search for the elements by point and
6439 * of classification of point in 2D mesh
6441 //=======================================================================
6443 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6445 SMESHDS_Mesh* _mesh;
6446 ElementBndBoxTree* _ebbTree;
6447 SMESH_NodeSearcherImpl* _nodeSearcher;
6448 SMDSAbs_ElementType _elementType;
6450 bool _outerFacesFound;
6451 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6453 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
6454 : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
6455 ~SMESH_ElementSearcherImpl()
6457 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6458 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6460 virtual int FindElementsByPoint(const gp_Pnt& point,
6461 SMDSAbs_ElementType type,
6462 vector< const SMDS_MeshElement* >& foundElements);
6463 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6465 void GetElementsNearLine( const gp_Ax1& line,
6466 SMDSAbs_ElementType type,
6467 vector< const SMDS_MeshElement* >& foundElems);
6468 double getTolerance();
6469 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6470 const double tolerance, double & param);
6471 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6472 bool isOuterBoundary(const SMDS_MeshElement* face) const
6474 return _outerFaces.empty() || _outerFaces.count(face);
6476 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6478 const SMDS_MeshElement* _face;
6480 bool _coincides; //!< the line lays in face plane
6481 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6482 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6484 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6487 TIDSortedElemSet _faces;
6488 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6489 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6493 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6495 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6496 << ", _coincides="<<i._coincides << ")";
6499 //=======================================================================
6501 * \brief define tolerance for search
6503 //=======================================================================
6505 double SMESH_ElementSearcherImpl::getTolerance()
6507 if ( _tolerance < 0 )
6509 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6512 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6514 double boxSize = _nodeSearcher->getTree()->maxSize();
6515 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6517 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6519 double boxSize = _ebbTree->maxSize();
6520 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6522 if ( _tolerance == 0 )
6524 // define tolerance by size of a most complex element
6525 int complexType = SMDSAbs_Volume;
6526 while ( complexType > SMDSAbs_All &&
6527 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6529 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6531 if ( complexType == int( SMDSAbs_Node ))
6533 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6535 if ( meshInfo.NbNodes() > 2 )
6536 elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6540 SMDS_ElemIteratorPtr elemIt =
6541 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6542 const SMDS_MeshElement* elem = elemIt->next();
6543 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6544 SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
6545 while ( nodeIt->more() )
6547 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6548 elemSize = max( dist, elemSize );
6551 _tolerance = 1e-4 * elemSize;
6557 //================================================================================
6559 * \brief Find intersection of the line and an edge of face and return parameter on line
6561 //================================================================================
6563 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6564 const SMDS_MeshElement* face,
6571 GeomAPI_ExtremaCurveCurve anExtCC;
6572 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6574 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6575 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6577 GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
6578 SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6579 anExtCC.Init( lineCurve, edge);
6580 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6582 Quantity_Parameter pl, pe;
6583 anExtCC.LowerDistanceParameters( pl, pe );
6585 if ( ++nbInts == 2 )
6589 if ( nbInts > 0 ) param /= nbInts;
6592 //================================================================================
6594 * \brief Find all faces belonging to the outer boundary of mesh
6596 //================================================================================
6598 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6600 if ( _outerFacesFound ) return;
6602 // Collect all outer faces by passing from one outer face to another via their links
6603 // and BTW find out if there are internal faces at all.
6605 // checked links and links where outer boundary meets internal one
6606 set< SMESH_TLink > visitedLinks, seamLinks;
6608 // links to treat with already visited faces sharing them
6609 list < TFaceLink > startLinks;
6611 // load startLinks with the first outerFace
6612 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6613 _outerFaces.insert( outerFace );
6615 TIDSortedElemSet emptySet;
6616 while ( !startLinks.empty() )
6618 const SMESH_TLink& link = startLinks.front()._link;
6619 TIDSortedElemSet& faces = startLinks.front()._faces;
6621 outerFace = *faces.begin();
6622 // find other faces sharing the link
6623 const SMDS_MeshElement* f;
6624 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6627 // select another outer face among the found
6628 const SMDS_MeshElement* outerFace2 = 0;
6629 if ( faces.size() == 2 )
6631 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6633 else if ( faces.size() > 2 )
6635 seamLinks.insert( link );
6637 // link direction within the outerFace
6638 gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
6639 SMESH_MeshEditor::TNodeXYZ( link.node2()));
6640 int i1 = outerFace->GetNodeIndex( link.node1() );
6641 int i2 = outerFace->GetNodeIndex( link.node2() );
6642 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6643 if ( rev ) n1n2.Reverse();
6645 gp_XYZ ofNorm, fNorm;
6646 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6648 // direction from the link inside outerFace
6649 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6650 // sort all other faces by angle with the dirInOF
6651 map< double, const SMDS_MeshElement* > angle2Face;
6652 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6653 for ( ; face != faces.end(); ++face )
6655 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6657 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6658 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6659 if ( angle < 0 ) angle += 2*PI;
6660 angle2Face.insert( make_pair( angle, *face ));
6662 if ( !angle2Face.empty() )
6663 outerFace2 = angle2Face.begin()->second;
6666 // store the found outer face and add its links to continue seaching from
6669 _outerFaces.insert( outerFace );
6670 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6671 for ( int i = 0; i < nbNodes; ++i )
6673 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6674 if ( visitedLinks.insert( link2 ).second )
6675 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6678 startLinks.pop_front();
6680 _outerFacesFound = true;
6682 if ( !seamLinks.empty() )
6684 // There are internal boundaries touching the outher one,
6685 // find all faces of internal boundaries in order to find
6686 // faces of boundaries of holes, if any.
6691 _outerFaces.clear();
6695 //=======================================================================
6697 * \brief Find elements of given type where the given point is IN or ON.
6698 * Returns nb of found elements and elements them-selves.
6700 * 'ALL' type means elements of any type excluding nodes and 0D elements
6702 //=======================================================================
6704 int SMESH_ElementSearcherImpl::
6705 FindElementsByPoint(const gp_Pnt& point,
6706 SMDSAbs_ElementType type,
6707 vector< const SMDS_MeshElement* >& foundElements)
6709 foundElements.clear();
6711 double tolerance = getTolerance();
6713 // =================================================================================
6714 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6716 if ( !_nodeSearcher )
6717 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6719 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6720 if ( !closeNode ) return foundElements.size();
6722 if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
6723 return foundElements.size(); // to far from any node
6725 if ( type == SMDSAbs_Node )
6727 foundElements.push_back( closeNode );
6731 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6732 while ( elemIt->more() )
6733 foundElements.push_back( elemIt->next() );
6736 // =================================================================================
6737 else // elements more complex than 0D
6739 if ( !_ebbTree || _elementType != type )
6741 if ( _ebbTree ) delete _ebbTree;
6742 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
6744 TIDSortedElemSet suspectElems;
6745 _ebbTree->getElementsNearPoint( point, suspectElems );
6746 TIDSortedElemSet::iterator elem = suspectElems.begin();
6747 for ( ; elem != suspectElems.end(); ++elem )
6748 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6749 foundElements.push_back( *elem );
6751 return foundElements.size();
6754 //================================================================================
6756 * \brief Classify the given point in the closed 2D mesh
6758 //================================================================================
6760 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6762 double tolerance = getTolerance();
6763 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6765 if ( _ebbTree ) delete _ebbTree;
6766 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
6768 // Algo: analyse transition of a line starting at the point through mesh boundary;
6769 // try three lines parallel to axis of the coordinate system and perform rough
6770 // analysis. If solution is not clear perform thorough analysis.
6772 const int nbAxes = 3;
6773 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6774 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6775 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6776 multimap< int, int > nbInt2Axis; // to find the simplest case
6777 for ( int axis = 0; axis < nbAxes; ++axis )
6779 gp_Ax1 lineAxis( point, axisDir[axis]);
6780 gp_Lin line ( lineAxis );
6782 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6783 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6785 // Intersect faces with the line
6787 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6788 TIDSortedElemSet::iterator face = suspectFaces.begin();
6789 for ( ; face != suspectFaces.end(); ++face )
6793 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6794 gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
6796 // perform intersection
6797 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6798 if ( !intersection.IsDone() )
6800 if ( intersection.IsInQuadric() )
6802 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6804 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6806 gp_Pnt intersectionPoint = intersection.Point(1);
6807 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6808 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6811 // Analyse intersections roughly
6813 int nbInter = u2inters.size();
6817 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6818 if ( nbInter == 1 ) // not closed mesh
6819 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6821 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6824 if ( (f<0) == (l<0) )
6827 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6828 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6829 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6832 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6834 if ( _outerFacesFound ) break; // pass to thorough analysis
6836 } // three attempts - loop on CS axes
6838 // Analyse intersections thoroughly.
6839 // We make two loops maximum, on the first one we only exclude touching intersections,
6840 // on the second, if situation is still unclear, we gather and use information on
6841 // position of faces (internal or outer). If faces position is already gathered,
6842 // we make the second loop right away.
6844 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6846 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6847 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6849 int axis = nb_axis->second;
6850 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6852 gp_Ax1 lineAxis( point, axisDir[axis]);
6853 gp_Lin line ( lineAxis );
6855 // add tangent intersections to u2inters
6857 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6858 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6859 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6860 u2inters.insert(make_pair( param, *tgtInt ));
6861 tangentInters[ axis ].clear();
6863 // Count intersections before and after the point excluding touching ones.
6864 // If hasPositionInfo we count intersections of outer boundary only
6866 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6867 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6868 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6869 bool ok = ! u_int1->second._coincides;
6870 while ( ok && u_int1 != u2inters.end() )
6872 double u = u_int1->first;
6873 bool touchingInt = false;
6874 if ( ++u_int2 != u2inters.end() )
6876 // skip intersections at the same point (if the line passes through edge or node)
6878 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6884 // skip tangent intersections
6886 const SMDS_MeshElement* prevFace = u_int1->second._face;
6887 while ( ok && u_int2->second._coincides )
6889 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6895 ok = ( u_int2 != u2inters.end() );
6900 // skip intersections at the same point after tangent intersections
6903 double u2 = u_int2->first;
6905 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6911 // decide if we skipped a touching intersection
6912 if ( nbSamePnt + nbTgt > 0 )
6914 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6915 map< double, TInters >::iterator u_int = u_int1;
6916 for ( ; u_int != u_int2; ++u_int )
6918 if ( u_int->second._coincides ) continue;
6919 double dot = u_int->second._faceNorm * line.Direction();
6920 if ( dot > maxDot ) maxDot = dot;
6921 if ( dot < minDot ) minDot = dot;
6923 touchingInt = ( minDot*maxDot < 0 );
6928 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6939 u_int1 = u_int2; // to next intersection
6941 } // loop on intersections with one line
6945 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6948 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6951 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6952 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6954 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6957 if ( (f<0) == (l<0) )
6960 if ( hasPositionInfo )
6961 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6963 } // loop on intersections of the tree lines - thorough analysis
6965 if ( !hasPositionInfo )
6967 // gather info on faces position - is face in the outer boundary or not
6968 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6969 findOuterBoundary( u2inters.begin()->second._face );
6972 } // two attempts - with and w/o faces position info in the mesh
6974 return TopAbs_UNKNOWN;
6977 //=======================================================================
6979 * \brief Return elements possibly intersecting the line
6981 //=======================================================================
6983 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
6984 SMDSAbs_ElementType type,
6985 vector< const SMDS_MeshElement* >& foundElems)
6987 if ( !_ebbTree || _elementType != type )
6989 if ( _ebbTree ) delete _ebbTree;
6990 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
6992 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
6993 _ebbTree->getElementsNearLine( line, suspectFaces );
6994 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
6997 //=======================================================================
6999 * \brief Return SMESH_ElementSearcher
7001 //=======================================================================
7003 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7005 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7008 //=======================================================================
7010 * \brief Return true if the point is IN or ON of the element
7012 //=======================================================================
7014 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7016 if ( element->GetType() == SMDSAbs_Volume)
7018 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7021 // get ordered nodes
7023 vector< gp_XYZ > xyz;
7024 vector<const SMDS_MeshNode*> nodeList;
7026 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7027 if ( element->IsQuadratic() )
7028 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7029 nodeIt = f->interlacedNodesElemIterator();
7030 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7031 nodeIt = e->interlacedNodesElemIterator();
7033 while ( nodeIt->more() )
7035 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7036 xyz.push_back( TNodeXYZ(node) );
7037 nodeList.push_back(node);
7040 int i, nbNodes = element->NbNodes();
7042 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7044 // compute face normal
7045 gp_Vec faceNorm(0,0,0);
7046 xyz.push_back( xyz.front() );
7047 nodeList.push_back( nodeList.front() );
7048 for ( i = 0; i < nbNodes; ++i )
7050 gp_Vec edge1( xyz[i+1], xyz[i]);
7051 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7052 faceNorm += edge1 ^ edge2;
7054 double normSize = faceNorm.Magnitude();
7055 if ( normSize <= tol )
7057 // degenerated face: point is out if it is out of all face edges
7058 for ( i = 0; i < nbNodes; ++i )
7060 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7061 if ( !isOut( &edge, point, tol ))
7066 faceNorm /= normSize;
7068 // check if the point lays on face plane
7069 gp_Vec n2p( xyz[0], point );
7070 if ( fabs( n2p * faceNorm ) > tol )
7071 return true; // not on face plane
7073 // check if point is out of face boundary:
7074 // define it by closest transition of a ray point->infinity through face boundary
7075 // on the face plane.
7076 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7077 // to find intersections of the ray with the boundary.
7079 gp_Vec plnNorm = ray ^ faceNorm;
7080 normSize = plnNorm.Magnitude();
7081 if ( normSize <= tol ) return false; // point coincides with the first node
7082 plnNorm /= normSize;
7083 // for each node of the face, compute its signed distance to the plane
7084 vector<double> dist( nbNodes + 1);
7085 for ( i = 0; i < nbNodes; ++i )
7087 gp_Vec n2p( xyz[i], point );
7088 dist[i] = n2p * plnNorm;
7090 dist.back() = dist.front();
7091 // find the closest intersection
7093 double rClosest, distClosest = 1e100;;
7095 for ( i = 0; i < nbNodes; ++i )
7098 if ( fabs( dist[i]) < tol )
7100 else if ( fabs( dist[i+1]) < tol )
7102 else if ( dist[i] * dist[i+1] < 0 )
7103 r = dist[i] / ( dist[i] - dist[i+1] );
7105 continue; // no intersection
7106 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7107 gp_Vec p2int ( point, pInt);
7108 if ( p2int * ray > -tol ) // right half-space
7110 double intDist = p2int.SquareMagnitude();
7111 if ( intDist < distClosest )
7116 distClosest = intDist;
7121 return true; // no intesections - out
7123 // analyse transition
7124 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7125 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7126 gp_Vec p2int ( point, pClosest );
7127 bool out = (edgeNorm * p2int) < -tol;
7128 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7131 // ray pass through a face node; analyze transition through an adjacent edge
7132 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7133 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7134 gp_Vec edgeAdjacent( p1, p2 );
7135 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7136 bool out2 = (edgeNorm2 * p2int) < -tol;
7138 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7139 return covexCorner ? (out || out2) : (out && out2);
7141 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7143 // point is out of edge if it is NOT ON any straight part of edge
7144 // (we consider quadratic edge as being composed of two straight parts)
7145 for ( i = 1; i < nbNodes; ++i )
7147 gp_Vec edge( xyz[i-1], xyz[i]);
7148 gp_Vec n1p ( xyz[i-1], point);
7149 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7152 gp_Vec n2p( xyz[i], point );
7153 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7155 return false; // point is ON this part
7159 // Node or 0D element -------------------------------------------------------------------------
7161 gp_Vec n2p ( xyz[0], point );
7162 return n2p.Magnitude() <= tol;
7167 //=======================================================================
7168 //function : SimplifyFace
7170 //=======================================================================
7171 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7172 vector<const SMDS_MeshNode *>& poly_nodes,
7173 vector<int>& quantities) const
7175 int nbNodes = faceNodes.size();
7180 set<const SMDS_MeshNode*> nodeSet;
7182 // get simple seq of nodes
7183 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7184 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7185 int iSimple = 0, nbUnique = 0;
7187 simpleNodes[iSimple++] = faceNodes[0];
7189 for (int iCur = 1; iCur < nbNodes; iCur++) {
7190 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7191 simpleNodes[iSimple++] = faceNodes[iCur];
7192 if (nodeSet.insert( faceNodes[iCur] ).second)
7196 int nbSimple = iSimple;
7197 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7207 bool foundLoop = (nbSimple > nbUnique);
7210 set<const SMDS_MeshNode*> loopSet;
7211 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7212 const SMDS_MeshNode* n = simpleNodes[iSimple];
7213 if (!loopSet.insert( n ).second) {
7217 int iC = 0, curLast = iSimple;
7218 for (; iC < curLast; iC++) {
7219 if (simpleNodes[iC] == n) break;
7221 int loopLen = curLast - iC;
7223 // create sub-element
7225 quantities.push_back(loopLen);
7226 for (; iC < curLast; iC++) {
7227 poly_nodes.push_back(simpleNodes[iC]);
7230 // shift the rest nodes (place from the first loop position)
7231 for (iC = curLast + 1; iC < nbSimple; iC++) {
7232 simpleNodes[iC - loopLen] = simpleNodes[iC];
7234 nbSimple -= loopLen;
7237 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7238 } // while (foundLoop)
7242 quantities.push_back(iSimple);
7243 for (int i = 0; i < iSimple; i++)
7244 poly_nodes.push_back(simpleNodes[i]);
7250 //=======================================================================
7251 //function : MergeNodes
7252 //purpose : In each group, the cdr of nodes are substituted by the first one
7254 //=======================================================================
7256 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7258 MESSAGE("MergeNodes");
7259 myLastCreatedElems.Clear();
7260 myLastCreatedNodes.Clear();
7262 SMESHDS_Mesh* aMesh = GetMeshDS();
7264 TNodeNodeMap nodeNodeMap; // node to replace - new node
7265 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7266 list< int > rmElemIds, rmNodeIds;
7268 // Fill nodeNodeMap and elems
7270 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7271 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7272 list<const SMDS_MeshNode*>& nodes = *grIt;
7273 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7274 const SMDS_MeshNode* nToKeep = *nIt;
7275 //MESSAGE("node to keep " << nToKeep->GetID());
7276 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7277 const SMDS_MeshNode* nToRemove = *nIt;
7278 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7279 if ( nToRemove != nToKeep ) {
7280 //MESSAGE(" node to remove " << nToRemove->GetID());
7281 rmNodeIds.push_back( nToRemove->GetID() );
7282 AddToSameGroups( nToKeep, nToRemove, aMesh );
7285 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7286 while ( invElemIt->more() ) {
7287 const SMDS_MeshElement* elem = invElemIt->next();
7292 // Change element nodes or remove an element
7294 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7295 for ( ; eIt != elems.end(); eIt++ ) {
7296 const SMDS_MeshElement* elem = *eIt;
7297 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7298 int nbNodes = elem->NbNodes();
7299 int aShapeId = FindShape( elem );
7301 set<const SMDS_MeshNode*> nodeSet;
7302 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7303 int iUnique = 0, iCur = 0, nbRepl = 0;
7304 vector<int> iRepl( nbNodes );
7306 // get new seq of nodes
7307 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7308 while ( itN->more() ) {
7309 const SMDS_MeshNode* n =
7310 static_cast<const SMDS_MeshNode*>( itN->next() );
7312 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7313 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7315 // BUG 0020185: begin
7317 bool stopRecur = false;
7318 set<const SMDS_MeshNode*> nodesRecur;
7319 nodesRecur.insert(n);
7320 while (!stopRecur) {
7321 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7322 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7323 n = (*nnIt_i).second;
7324 if (!nodesRecur.insert(n).second) {
7325 // error: recursive dependancy
7334 iRepl[ nbRepl++ ] = iCur;
7336 curNodes[ iCur ] = n;
7337 bool isUnique = nodeSet.insert( n ).second;
7339 uniqueNodes[ iUnique++ ] = n;
7343 // Analyse element topology after replacement
7346 int nbUniqueNodes = nodeSet.size();
7347 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7348 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7349 // Polygons and Polyhedral volumes
7350 if (elem->IsPoly()) {
7352 if (elem->GetType() == SMDSAbs_Face) {
7354 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7356 for (; inode < nbNodes; inode++) {
7357 face_nodes[inode] = curNodes[inode];
7360 vector<const SMDS_MeshNode *> polygons_nodes;
7361 vector<int> quantities;
7362 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7366 for (int iface = 0; iface < nbNew - 1; iface++) {
7367 int nbNodes = quantities[iface];
7368 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7369 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7370 poly_nodes[ii] = polygons_nodes[inode];
7372 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7373 myLastCreatedElems.Append(newElem);
7375 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7378 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7379 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7380 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7382 if (nbNew > 0) quid = nbNew - 1;
7383 vector<int> newquant(quantities.begin()+quid, quantities.end());
7384 const SMDS_MeshElement* newElem = 0;
7385 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7386 myLastCreatedElems.Append(newElem);
7387 if ( aShapeId && newElem )
7388 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7389 rmElemIds.push_back(elem->GetID());
7392 rmElemIds.push_back(elem->GetID());
7396 else if (elem->GetType() == SMDSAbs_Volume) {
7397 // Polyhedral volume
7398 if (nbUniqueNodes < 4) {
7399 rmElemIds.push_back(elem->GetID());
7402 // each face has to be analyzed in order to check volume validity
7403 const SMDS_VtkVolume* aPolyedre =
7404 dynamic_cast<const SMDS_VtkVolume*>( elem );
7406 int nbFaces = aPolyedre->NbFaces();
7408 vector<const SMDS_MeshNode *> poly_nodes;
7409 vector<int> quantities;
7411 for (int iface = 1; iface <= nbFaces; iface++) {
7412 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7413 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7415 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7416 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7417 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7418 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7419 faceNode = (*nnIt).second;
7421 faceNodes[inode - 1] = faceNode;
7424 SimplifyFace(faceNodes, poly_nodes, quantities);
7427 if (quantities.size() > 3) {
7428 // to be done: remove coincident faces
7431 if (quantities.size() > 3)
7433 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7434 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7435 const SMDS_MeshElement* newElem = 0;
7436 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7437 myLastCreatedElems.Append(newElem);
7438 if ( aShapeId && newElem )
7439 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7440 rmElemIds.push_back(elem->GetID());
7444 rmElemIds.push_back(elem->GetID());
7455 // TODO not all the possible cases are solved. Find something more generic?
7456 switch ( nbNodes ) {
7457 case 2: ///////////////////////////////////// EDGE
7458 isOk = false; break;
7459 case 3: ///////////////////////////////////// TRIANGLE
7460 isOk = false; break;
7462 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7464 else { //////////////////////////////////// QUADRANGLE
7465 if ( nbUniqueNodes < 3 )
7467 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7468 isOk = false; // opposite nodes stick
7469 //MESSAGE("isOk " << isOk);
7472 case 6: ///////////////////////////////////// PENTAHEDRON
7473 if ( nbUniqueNodes == 4 ) {
7474 // ---------------------------------> tetrahedron
7476 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7477 // all top nodes stick: reverse a bottom
7478 uniqueNodes[ 0 ] = curNodes [ 1 ];
7479 uniqueNodes[ 1 ] = curNodes [ 0 ];
7481 else if (nbRepl == 3 &&
7482 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7483 // all bottom nodes stick: set a top before
7484 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7485 uniqueNodes[ 0 ] = curNodes [ 3 ];
7486 uniqueNodes[ 1 ] = curNodes [ 4 ];
7487 uniqueNodes[ 2 ] = curNodes [ 5 ];
7489 else if (nbRepl == 4 &&
7490 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7491 // a lateral face turns into a line: reverse a bottom
7492 uniqueNodes[ 0 ] = curNodes [ 1 ];
7493 uniqueNodes[ 1 ] = curNodes [ 0 ];
7498 else if ( nbUniqueNodes == 5 ) {
7499 // PENTAHEDRON --------------------> 2 tetrahedrons
7500 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7501 // a bottom node sticks with a linked top one
7503 SMDS_MeshElement* newElem =
7504 aMesh->AddVolume(curNodes[ 3 ],
7507 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7508 myLastCreatedElems.Append(newElem);
7510 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7511 // 2. : reverse a bottom
7512 uniqueNodes[ 0 ] = curNodes [ 1 ];
7513 uniqueNodes[ 1 ] = curNodes [ 0 ];
7523 if(elem->IsQuadratic()) { // Quadratic quadrangle
7535 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7538 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7540 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7541 uniqueNodes[0] = curNodes[0];
7542 uniqueNodes[1] = curNodes[2];
7543 uniqueNodes[2] = curNodes[3];
7544 uniqueNodes[3] = curNodes[5];
7545 uniqueNodes[4] = curNodes[6];
7546 uniqueNodes[5] = curNodes[7];
7549 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7550 uniqueNodes[0] = curNodes[0];
7551 uniqueNodes[1] = curNodes[1];
7552 uniqueNodes[2] = curNodes[2];
7553 uniqueNodes[3] = curNodes[4];
7554 uniqueNodes[4] = curNodes[5];
7555 uniqueNodes[5] = curNodes[6];
7558 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7559 uniqueNodes[0] = curNodes[1];
7560 uniqueNodes[1] = curNodes[2];
7561 uniqueNodes[2] = curNodes[3];
7562 uniqueNodes[3] = curNodes[5];
7563 uniqueNodes[4] = curNodes[6];
7564 uniqueNodes[5] = curNodes[0];
7567 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7568 uniqueNodes[0] = curNodes[0];
7569 uniqueNodes[1] = curNodes[1];
7570 uniqueNodes[2] = curNodes[3];
7571 uniqueNodes[3] = curNodes[4];
7572 uniqueNodes[4] = curNodes[6];
7573 uniqueNodes[5] = curNodes[7];
7576 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7577 uniqueNodes[0] = curNodes[0];
7578 uniqueNodes[1] = curNodes[2];
7579 uniqueNodes[2] = curNodes[3];
7580 uniqueNodes[3] = curNodes[1];
7581 uniqueNodes[4] = curNodes[6];
7582 uniqueNodes[5] = curNodes[7];
7585 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7586 uniqueNodes[0] = curNodes[0];
7587 uniqueNodes[1] = curNodes[1];
7588 uniqueNodes[2] = curNodes[2];
7589 uniqueNodes[3] = curNodes[4];
7590 uniqueNodes[4] = curNodes[5];
7591 uniqueNodes[5] = curNodes[7];
7594 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7595 uniqueNodes[0] = curNodes[0];
7596 uniqueNodes[1] = curNodes[1];
7597 uniqueNodes[2] = curNodes[3];
7598 uniqueNodes[3] = curNodes[4];
7599 uniqueNodes[4] = curNodes[2];
7600 uniqueNodes[5] = curNodes[7];
7603 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7604 uniqueNodes[0] = curNodes[0];
7605 uniqueNodes[1] = curNodes[1];
7606 uniqueNodes[2] = curNodes[2];
7607 uniqueNodes[3] = curNodes[4];
7608 uniqueNodes[4] = curNodes[5];
7609 uniqueNodes[5] = curNodes[3];
7614 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7617 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7621 //////////////////////////////////// HEXAHEDRON
7623 SMDS_VolumeTool hexa (elem);
7624 hexa.SetExternalNormal();
7625 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7626 //////////////////////// ---> tetrahedron
7627 for ( int iFace = 0; iFace < 6; iFace++ ) {
7628 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7629 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7630 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7631 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7632 // one face turns into a point ...
7633 int iOppFace = hexa.GetOppFaceIndex( iFace );
7634 ind = hexa.GetFaceNodesIndices( iOppFace );
7636 iUnique = 2; // reverse a tetrahedron bottom
7637 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7638 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7640 else if ( iUnique >= 0 )
7641 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7643 if ( nbStick == 1 ) {
7644 // ... and the opposite one - into a triangle.
7646 ind = hexa.GetFaceNodesIndices( iFace );
7647 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7654 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7655 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7656 for ( int iFace = 0; iFace < 6; iFace++ ) {
7657 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7658 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7659 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7660 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7661 // one face turns into a point ...
7662 int iOppFace = hexa.GetOppFaceIndex( iFace );
7663 ind = hexa.GetFaceNodesIndices( iOppFace );
7665 iUnique = 2; // reverse a tetrahedron 1 bottom
7666 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7667 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7669 else if ( iUnique >= 0 )
7670 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7672 if ( nbStick == 0 ) {
7673 // ... and the opposite one is a quadrangle
7675 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7676 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7679 SMDS_MeshElement* newElem =
7680 aMesh->AddVolume(curNodes[ind[ 0 ]],
7683 curNodes[indTop[ 0 ]]);
7684 myLastCreatedElems.Append(newElem);
7686 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7693 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7694 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7695 // find indices of quad and tri faces
7696 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7697 for ( iFace = 0; iFace < 6; iFace++ ) {
7698 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7700 for ( iCur = 0; iCur < 4; iCur++ )
7701 nodeSet.insert( curNodes[ind[ iCur ]] );
7702 nbUniqueNodes = nodeSet.size();
7703 if ( nbUniqueNodes == 3 )
7704 iTriFace[ nbTri++ ] = iFace;
7705 else if ( nbUniqueNodes == 4 )
7706 iQuadFace[ nbQuad++ ] = iFace;
7708 if (nbQuad == 2 && nbTri == 4 &&
7709 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7710 // 2 opposite quadrangles stuck with a diagonal;
7711 // sample groups of merged indices: (0-4)(2-6)
7712 // --------------------------------------------> 2 tetrahedrons
7713 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7714 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7715 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7716 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7717 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7718 // stuck with 0-2 diagonal
7726 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7727 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7728 // stuck with 1-3 diagonal
7740 uniqueNodes[ 0 ] = curNodes [ i0 ];
7741 uniqueNodes[ 1 ] = curNodes [ i1d ];
7742 uniqueNodes[ 2 ] = curNodes [ i3d ];
7743 uniqueNodes[ 3 ] = curNodes [ i0t ];
7746 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7750 myLastCreatedElems.Append(newElem);
7752 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7755 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7756 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7757 // --------------------------------------------> prism
7758 // find 2 opposite triangles
7760 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7761 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7762 // find indices of kept and replaced nodes
7763 // and fill unique nodes of 2 opposite triangles
7764 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7765 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7766 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7767 // fill unique nodes
7770 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7771 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7772 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7774 // iCur of a linked node of the opposite face (make normals co-directed):
7775 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7776 // check that correspondent corners of triangles are linked
7777 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7780 uniqueNodes[ iUnique ] = n;
7781 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7790 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7796 } // switch ( nbNodes )
7798 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7801 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7802 // Change nodes of polyedre
7803 const SMDS_VtkVolume* aPolyedre =
7804 dynamic_cast<const SMDS_VtkVolume*>( elem );
7806 int nbFaces = aPolyedre->NbFaces();
7808 vector<const SMDS_MeshNode *> poly_nodes;
7809 vector<int> quantities (nbFaces);
7811 for (int iface = 1; iface <= nbFaces; iface++) {
7812 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7813 quantities[iface - 1] = nbFaceNodes;
7815 for (inode = 1; inode <= nbFaceNodes; inode++) {
7816 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7818 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7819 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7820 curNode = (*nnIt).second;
7822 poly_nodes.push_back(curNode);
7825 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7829 int elemId = elem->GetID();
7830 //MESSAGE("Change regular element or polygon " << elemId);
7831 SMDSAbs_ElementType etyp = elem->GetType();
7832 uniqueNodes.resize(nbUniqueNodes);
7833 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, false);
7836 myLastCreatedElems.Append(newElem);
7838 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7840 aMesh->RemoveElement(elem);
7844 // Remove invalid regular element or invalid polygon
7845 //MESSAGE("Remove invalid " << elem->GetID());
7846 rmElemIds.push_back( elem->GetID() );
7849 } // loop on elements
7851 // Remove bad elements, then equal nodes (order important)
7853 Remove( rmElemIds, false );
7854 Remove( rmNodeIds, true );
7859 // ========================================================
7860 // class : SortableElement
7861 // purpose : allow sorting elements basing on their nodes
7862 // ========================================================
7863 class SortableElement : public set <const SMDS_MeshElement*>
7867 SortableElement( const SMDS_MeshElement* theElem )
7870 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7871 while ( nodeIt->more() )
7872 this->insert( nodeIt->next() );
7875 const SMDS_MeshElement* Get() const
7878 void Set(const SMDS_MeshElement* e) const
7883 mutable const SMDS_MeshElement* myElem;
7886 //=======================================================================
7887 //function : FindEqualElements
7888 //purpose : Return list of group of elements built on the same nodes.
7889 // Search among theElements or in the whole mesh if theElements is empty
7890 //=======================================================================
7891 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7892 TListOfListOfElementsID & theGroupsOfElementsID)
7894 myLastCreatedElems.Clear();
7895 myLastCreatedNodes.Clear();
7897 typedef set<const SMDS_MeshElement*> TElemsSet;
7898 typedef map< SortableElement, int > TMapOfNodeSet;
7899 typedef list<int> TGroupOfElems;
7902 if ( theElements.empty() )
7903 { // get all elements in the mesh
7904 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7905 while ( eIt->more() )
7906 elems.insert( elems.end(), eIt->next());
7909 elems = theElements;
7911 vector< TGroupOfElems > arrayOfGroups;
7912 TGroupOfElems groupOfElems;
7913 TMapOfNodeSet mapOfNodeSet;
7915 TElemsSet::iterator elemIt = elems.begin();
7916 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7917 const SMDS_MeshElement* curElem = *elemIt;
7918 SortableElement SE(curElem);
7921 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7922 if( !(pp.second) ) {
7923 TMapOfNodeSet::iterator& itSE = pp.first;
7924 ind = (*itSE).second;
7925 arrayOfGroups[ind].push_back(curElem->GetID());
7928 groupOfElems.clear();
7929 groupOfElems.push_back(curElem->GetID());
7930 arrayOfGroups.push_back(groupOfElems);
7935 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7936 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7937 groupOfElems = *groupIt;
7938 if ( groupOfElems.size() > 1 ) {
7939 groupOfElems.sort();
7940 theGroupsOfElementsID.push_back(groupOfElems);
7945 //=======================================================================
7946 //function : MergeElements
7947 //purpose : In each given group, substitute all elements by the first one.
7948 //=======================================================================
7950 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7952 myLastCreatedElems.Clear();
7953 myLastCreatedNodes.Clear();
7955 typedef list<int> TListOfIDs;
7956 TListOfIDs rmElemIds; // IDs of elems to remove
7958 SMESHDS_Mesh* aMesh = GetMeshDS();
7960 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7961 while ( groupsIt != theGroupsOfElementsID.end() ) {
7962 TListOfIDs& aGroupOfElemID = *groupsIt;
7963 aGroupOfElemID.sort();
7964 int elemIDToKeep = aGroupOfElemID.front();
7965 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
7966 aGroupOfElemID.pop_front();
7967 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
7968 while ( idIt != aGroupOfElemID.end() ) {
7969 int elemIDToRemove = *idIt;
7970 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
7971 // add the kept element in groups of removed one (PAL15188)
7972 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
7973 rmElemIds.push_back( elemIDToRemove );
7979 Remove( rmElemIds, false );
7982 //=======================================================================
7983 //function : MergeEqualElements
7984 //purpose : Remove all but one of elements built on the same nodes.
7985 //=======================================================================
7987 void SMESH_MeshEditor::MergeEqualElements()
7989 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
7990 to merge equal elements in the whole mesh */
7991 TListOfListOfElementsID aGroupsOfElementsID;
7992 FindEqualElements(aMeshElements, aGroupsOfElementsID);
7993 MergeElements(aGroupsOfElementsID);
7996 //=======================================================================
7997 //function : FindFaceInSet
7998 //purpose : Return a face having linked nodes n1 and n2 and which is
7999 // - not in avoidSet,
8000 // - in elemSet provided that !elemSet.empty()
8001 // i1 and i2 optionally returns indices of n1 and n2
8002 //=======================================================================
8004 const SMDS_MeshElement*
8005 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8006 const SMDS_MeshNode* n2,
8007 const TIDSortedElemSet& elemSet,
8008 const TIDSortedElemSet& avoidSet,
8014 const SMDS_MeshElement* face = 0;
8016 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8017 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8018 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8020 //MESSAGE("in while ( invElemIt->more() && !face )");
8021 const SMDS_MeshElement* elem = invElemIt->next();
8022 if (avoidSet.count( elem ))
8024 if ( !elemSet.empty() && !elemSet.count( elem ))
8027 i1 = elem->GetNodeIndex( n1 );
8028 // find a n2 linked to n1
8029 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8030 for ( int di = -1; di < 2 && !face; di += 2 )
8032 i2 = (i1+di+nbN) % nbN;
8033 if ( elem->GetNode( i2 ) == n2 )
8036 if ( !face && elem->IsQuadratic())
8038 // analysis for quadratic elements using all nodes
8039 const SMDS_VtkFace* F =
8040 dynamic_cast<const SMDS_VtkFace*>(elem);
8041 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8042 // use special nodes iterator
8043 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8044 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8045 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8047 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8048 if ( n1 == prevN && n2 == n )
8052 else if ( n2 == prevN && n1 == n )
8054 face = elem; swap( i1, i2 );
8060 if ( n1ind ) *n1ind = i1;
8061 if ( n2ind ) *n2ind = i2;
8065 //=======================================================================
8066 //function : findAdjacentFace
8068 //=======================================================================
8070 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8071 const SMDS_MeshNode* n2,
8072 const SMDS_MeshElement* elem)
8074 TIDSortedElemSet elemSet, avoidSet;
8076 avoidSet.insert ( elem );
8077 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8080 //=======================================================================
8081 //function : FindFreeBorder
8083 //=======================================================================
8085 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8087 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8088 const SMDS_MeshNode* theSecondNode,
8089 const SMDS_MeshNode* theLastNode,
8090 list< const SMDS_MeshNode* > & theNodes,
8091 list< const SMDS_MeshElement* >& theFaces)
8093 if ( !theFirstNode || !theSecondNode )
8095 // find border face between theFirstNode and theSecondNode
8096 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8100 theFaces.push_back( curElem );
8101 theNodes.push_back( theFirstNode );
8102 theNodes.push_back( theSecondNode );
8104 //vector<const SMDS_MeshNode*> nodes;
8105 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8106 TIDSortedElemSet foundElems;
8107 bool needTheLast = ( theLastNode != 0 );
8109 while ( nStart != theLastNode ) {
8110 if ( nStart == theFirstNode )
8111 return !needTheLast;
8113 // find all free border faces sharing form nStart
8115 list< const SMDS_MeshElement* > curElemList;
8116 list< const SMDS_MeshNode* > nStartList;
8117 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8118 while ( invElemIt->more() ) {
8119 const SMDS_MeshElement* e = invElemIt->next();
8120 if ( e == curElem || foundElems.insert( e ).second ) {
8122 int iNode = 0, nbNodes = e->NbNodes();
8123 //const SMDS_MeshNode* nodes[nbNodes+1];
8124 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8126 if(e->IsQuadratic()) {
8127 const SMDS_VtkFace* F =
8128 dynamic_cast<const SMDS_VtkFace*>(e);
8129 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8130 // use special nodes iterator
8131 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8132 while( anIter->more() ) {
8133 nodes[ iNode++ ] = cast2Node(anIter->next());
8137 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8138 while ( nIt->more() )
8139 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8141 nodes[ iNode ] = nodes[ 0 ];
8143 for ( iNode = 0; iNode < nbNodes; iNode++ )
8144 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8145 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8146 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8148 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8149 curElemList.push_back( e );
8153 // analyse the found
8155 int nbNewBorders = curElemList.size();
8156 if ( nbNewBorders == 0 ) {
8157 // no free border furthermore
8158 return !needTheLast;
8160 else if ( nbNewBorders == 1 ) {
8161 // one more element found
8163 nStart = nStartList.front();
8164 curElem = curElemList.front();
8165 theFaces.push_back( curElem );
8166 theNodes.push_back( nStart );
8169 // several continuations found
8170 list< const SMDS_MeshElement* >::iterator curElemIt;
8171 list< const SMDS_MeshNode* >::iterator nStartIt;
8172 // check if one of them reached the last node
8173 if ( needTheLast ) {
8174 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8175 curElemIt!= curElemList.end();
8176 curElemIt++, nStartIt++ )
8177 if ( *nStartIt == theLastNode ) {
8178 theFaces.push_back( *curElemIt );
8179 theNodes.push_back( *nStartIt );
8183 // find the best free border by the continuations
8184 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8185 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8186 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8187 curElemIt!= curElemList.end();
8188 curElemIt++, nStartIt++ )
8190 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8191 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8192 // find one more free border
8193 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8197 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8198 // choice: clear a worse one
8199 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8200 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8201 contNodes[ iWorse ].clear();
8202 contFaces[ iWorse ].clear();
8205 if ( contNodes[0].empty() && contNodes[1].empty() )
8208 // append the best free border
8209 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8210 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8211 theNodes.pop_back(); // remove nIgnore
8212 theNodes.pop_back(); // remove nStart
8213 theFaces.pop_back(); // remove curElem
8214 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8215 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8216 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8217 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8220 } // several continuations found
8221 } // while ( nStart != theLastNode )
8226 //=======================================================================
8227 //function : CheckFreeBorderNodes
8228 //purpose : Return true if the tree nodes are on a free border
8229 //=======================================================================
8231 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8232 const SMDS_MeshNode* theNode2,
8233 const SMDS_MeshNode* theNode3)
8235 list< const SMDS_MeshNode* > nodes;
8236 list< const SMDS_MeshElement* > faces;
8237 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8240 //=======================================================================
8241 //function : SewFreeBorder
8243 //=======================================================================
8245 SMESH_MeshEditor::Sew_Error
8246 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8247 const SMDS_MeshNode* theBordSecondNode,
8248 const SMDS_MeshNode* theBordLastNode,
8249 const SMDS_MeshNode* theSideFirstNode,
8250 const SMDS_MeshNode* theSideSecondNode,
8251 const SMDS_MeshNode* theSideThirdNode,
8252 const bool theSideIsFreeBorder,
8253 const bool toCreatePolygons,
8254 const bool toCreatePolyedrs)
8256 myLastCreatedElems.Clear();
8257 myLastCreatedNodes.Clear();
8259 MESSAGE("::SewFreeBorder()");
8260 Sew_Error aResult = SEW_OK;
8262 // ====================================
8263 // find side nodes and elements
8264 // ====================================
8266 list< const SMDS_MeshNode* > nSide[ 2 ];
8267 list< const SMDS_MeshElement* > eSide[ 2 ];
8268 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8269 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8273 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8274 nSide[0], eSide[0])) {
8275 MESSAGE(" Free Border 1 not found " );
8276 aResult = SEW_BORDER1_NOT_FOUND;
8278 if (theSideIsFreeBorder) {
8281 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8282 nSide[1], eSide[1])) {
8283 MESSAGE(" Free Border 2 not found " );
8284 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8287 if ( aResult != SEW_OK )
8290 if (!theSideIsFreeBorder) {
8294 // -------------------------------------------------------------------------
8296 // 1. If nodes to merge are not coincident, move nodes of the free border
8297 // from the coord sys defined by the direction from the first to last
8298 // nodes of the border to the correspondent sys of the side 2
8299 // 2. On the side 2, find the links most co-directed with the correspondent
8300 // links of the free border
8301 // -------------------------------------------------------------------------
8303 // 1. Since sewing may break if there are volumes to split on the side 2,
8304 // we wont move nodes but just compute new coordinates for them
8305 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8306 TNodeXYZMap nBordXYZ;
8307 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8308 list< const SMDS_MeshNode* >::iterator nBordIt;
8310 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8311 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8312 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8313 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8314 double tol2 = 1.e-8;
8315 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8316 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8317 // Need node movement.
8319 // find X and Z axes to create trsf
8320 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8322 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8324 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8327 gp_Ax3 toBordAx( Pb1, Zb, X );
8328 gp_Ax3 fromSideAx( Ps1, Zs, X );
8329 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8331 gp_Trsf toBordSys, fromSide2Sys;
8332 toBordSys.SetTransformation( toBordAx );
8333 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8334 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8337 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8338 const SMDS_MeshNode* n = *nBordIt;
8339 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8340 toBordSys.Transforms( xyz );
8341 fromSide2Sys.Transforms( xyz );
8342 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8346 // just insert nodes XYZ in the nBordXYZ map
8347 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8348 const SMDS_MeshNode* n = *nBordIt;
8349 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8353 // 2. On the side 2, find the links most co-directed with the correspondent
8354 // links of the free border
8356 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8357 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8358 sideNodes.push_back( theSideFirstNode );
8360 bool hasVolumes = false;
8361 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8362 set<long> foundSideLinkIDs, checkedLinkIDs;
8363 SMDS_VolumeTool volume;
8364 //const SMDS_MeshNode* faceNodes[ 4 ];
8366 const SMDS_MeshNode* sideNode;
8367 const SMDS_MeshElement* sideElem;
8368 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8369 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8370 nBordIt = bordNodes.begin();
8372 // border node position and border link direction to compare with
8373 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8374 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8375 // choose next side node by link direction or by closeness to
8376 // the current border node:
8377 bool searchByDir = ( *nBordIt != theBordLastNode );
8379 // find the next node on the Side 2
8381 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8383 checkedLinkIDs.clear();
8384 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8386 // loop on inverse elements of current node (prevSideNode) on the Side 2
8387 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8388 while ( invElemIt->more() )
8390 const SMDS_MeshElement* elem = invElemIt->next();
8391 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8392 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8393 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8394 bool isVolume = volume.Set( elem );
8395 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8396 if ( isVolume ) // --volume
8398 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8399 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8400 if(elem->IsQuadratic()) {
8401 const SMDS_VtkFace* F =
8402 dynamic_cast<const SMDS_VtkFace*>(elem);
8403 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8404 // use special nodes iterator
8405 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8406 while( anIter->more() ) {
8407 nodes[ iNode ] = cast2Node(anIter->next());
8408 if ( nodes[ iNode++ ] == prevSideNode )
8409 iPrevNode = iNode - 1;
8413 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8414 while ( nIt->more() ) {
8415 nodes[ iNode ] = cast2Node( nIt->next() );
8416 if ( nodes[ iNode++ ] == prevSideNode )
8417 iPrevNode = iNode - 1;
8420 // there are 2 links to check
8425 // loop on links, to be precise, on the second node of links
8426 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8427 const SMDS_MeshNode* n = nodes[ iNode ];
8429 if ( !volume.IsLinked( n, prevSideNode ))
8433 if ( iNode ) // a node before prevSideNode
8434 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8435 else // a node after prevSideNode
8436 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8438 // check if this link was already used
8439 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8440 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8441 if (!isJustChecked &&
8442 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8444 // test a link geometrically
8445 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8446 bool linkIsBetter = false;
8447 double dot = 0.0, dist = 0.0;
8448 if ( searchByDir ) { // choose most co-directed link
8449 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8450 linkIsBetter = ( dot > maxDot );
8452 else { // choose link with the node closest to bordPos
8453 dist = ( nextXYZ - bordPos ).SquareModulus();
8454 linkIsBetter = ( dist < minDist );
8456 if ( linkIsBetter ) {
8465 } // loop on inverse elements of prevSideNode
8468 MESSAGE(" Cant find path by links of the Side 2 ");
8469 return SEW_BAD_SIDE_NODES;
8471 sideNodes.push_back( sideNode );
8472 sideElems.push_back( sideElem );
8473 foundSideLinkIDs.insert ( linkID );
8474 prevSideNode = sideNode;
8476 if ( *nBordIt == theBordLastNode )
8477 searchByDir = false;
8479 // find the next border link to compare with
8480 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8481 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8482 // move to next border node if sideNode is before forward border node (bordPos)
8483 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8484 prevBordNode = *nBordIt;
8486 bordPos = nBordXYZ[ *nBordIt ];
8487 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8488 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8492 while ( sideNode != theSideSecondNode );
8494 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8495 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8496 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8498 } // end nodes search on the side 2
8500 // ============================
8501 // sew the border to the side 2
8502 // ============================
8504 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8505 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8507 TListOfListOfNodes nodeGroupsToMerge;
8508 if ( nbNodes[0] == nbNodes[1] ||
8509 ( theSideIsFreeBorder && !theSideThirdNode)) {
8511 // all nodes are to be merged
8513 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8514 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8515 nIt[0]++, nIt[1]++ )
8517 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8518 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8519 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8524 // insert new nodes into the border and the side to get equal nb of segments
8526 // get normalized parameters of nodes on the borders
8527 //double param[ 2 ][ maxNbNodes ];
8529 param[0] = new double [ maxNbNodes ];
8530 param[1] = new double [ maxNbNodes ];
8532 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8533 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8534 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8535 const SMDS_MeshNode* nPrev = *nIt;
8536 double bordLength = 0;
8537 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8538 const SMDS_MeshNode* nCur = *nIt;
8539 gp_XYZ segment (nCur->X() - nPrev->X(),
8540 nCur->Y() - nPrev->Y(),
8541 nCur->Z() - nPrev->Z());
8542 double segmentLen = segment.Modulus();
8543 bordLength += segmentLen;
8544 param[ iBord ][ iNode ] = bordLength;
8547 // normalize within [0,1]
8548 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8549 param[ iBord ][ iNode ] /= bordLength;
8553 // loop on border segments
8554 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8555 int i[ 2 ] = { 0, 0 };
8556 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8557 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8559 TElemOfNodeListMap insertMap;
8560 TElemOfNodeListMap::iterator insertMapIt;
8562 // key: elem to insert nodes into
8563 // value: 2 nodes to insert between + nodes to be inserted
8565 bool next[ 2 ] = { false, false };
8567 // find min adjacent segment length after sewing
8568 double nextParam = 10., prevParam = 0;
8569 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8570 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8571 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8572 if ( i[ iBord ] > 0 )
8573 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8575 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8576 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8577 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8579 // choose to insert or to merge nodes
8580 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8581 if ( Abs( du ) <= minSegLen * 0.2 ) {
8584 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8585 const SMDS_MeshNode* n0 = *nIt[0];
8586 const SMDS_MeshNode* n1 = *nIt[1];
8587 nodeGroupsToMerge.back().push_back( n1 );
8588 nodeGroupsToMerge.back().push_back( n0 );
8589 // position of node of the border changes due to merge
8590 param[ 0 ][ i[0] ] += du;
8591 // move n1 for the sake of elem shape evaluation during insertion.
8592 // n1 will be removed by MergeNodes() anyway
8593 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8594 next[0] = next[1] = true;
8599 int intoBord = ( du < 0 ) ? 0 : 1;
8600 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8601 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8602 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8603 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8604 if ( intoBord == 1 ) {
8605 // move node of the border to be on a link of elem of the side
8606 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8607 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8608 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8609 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8610 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8612 insertMapIt = insertMap.find( elem );
8613 bool notFound = ( insertMapIt == insertMap.end() );
8614 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8616 // insert into another link of the same element:
8617 // 1. perform insertion into the other link of the elem
8618 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8619 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8620 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8621 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8622 // 2. perform insertion into the link of adjacent faces
8624 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8626 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8630 if (toCreatePolyedrs) {
8631 // perform insertion into the links of adjacent volumes
8632 UpdateVolumes(n12, n22, nodeList);
8634 // 3. find an element appeared on n1 and n2 after the insertion
8635 insertMap.erase( elem );
8636 elem = findAdjacentFace( n1, n2, 0 );
8638 if ( notFound || otherLink ) {
8639 // add element and nodes of the side into the insertMap
8640 insertMapIt = insertMap.insert
8641 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8642 (*insertMapIt).second.push_back( n1 );
8643 (*insertMapIt).second.push_back( n2 );
8645 // add node to be inserted into elem
8646 (*insertMapIt).second.push_back( nIns );
8647 next[ 1 - intoBord ] = true;
8650 // go to the next segment
8651 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8652 if ( next[ iBord ] ) {
8653 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8655 nPrev[ iBord ] = *nIt[ iBord ];
8656 nIt[ iBord ]++; i[ iBord ]++;
8660 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8662 // perform insertion of nodes into elements
8664 for (insertMapIt = insertMap.begin();
8665 insertMapIt != insertMap.end();
8668 const SMDS_MeshElement* elem = (*insertMapIt).first;
8669 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8670 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8671 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8673 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8675 if ( !theSideIsFreeBorder ) {
8676 // look for and insert nodes into the faces adjacent to elem
8678 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8680 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8685 if (toCreatePolyedrs) {
8686 // perform insertion into the links of adjacent volumes
8687 UpdateVolumes(n1, n2, nodeList);
8693 } // end: insert new nodes
8695 MergeNodes ( nodeGroupsToMerge );
8700 //=======================================================================
8701 //function : InsertNodesIntoLink
8702 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8703 // and theBetweenNode2 and split theElement
8704 //=======================================================================
8706 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8707 const SMDS_MeshNode* theBetweenNode1,
8708 const SMDS_MeshNode* theBetweenNode2,
8709 list<const SMDS_MeshNode*>& theNodesToInsert,
8710 const bool toCreatePoly)
8712 if ( theFace->GetType() != SMDSAbs_Face ) return;
8714 // find indices of 2 link nodes and of the rest nodes
8715 int iNode = 0, il1, il2, i3, i4;
8716 il1 = il2 = i3 = i4 = -1;
8717 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8718 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8720 if(theFace->IsQuadratic()) {
8721 const SMDS_VtkFace* F =
8722 dynamic_cast<const SMDS_VtkFace*>(theFace);
8723 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8724 // use special nodes iterator
8725 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8726 while( anIter->more() ) {
8727 const SMDS_MeshNode* n = cast2Node(anIter->next());
8728 if ( n == theBetweenNode1 )
8730 else if ( n == theBetweenNode2 )
8736 nodes[ iNode++ ] = n;
8740 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8741 while ( nodeIt->more() ) {
8742 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8743 if ( n == theBetweenNode1 )
8745 else if ( n == theBetweenNode2 )
8751 nodes[ iNode++ ] = n;
8754 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8757 // arrange link nodes to go one after another regarding the face orientation
8758 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8759 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8764 aNodesToInsert.reverse();
8766 // check that not link nodes of a quadrangles are in good order
8767 int nbFaceNodes = theFace->NbNodes();
8768 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8774 if (toCreatePoly || theFace->IsPoly()) {
8777 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8779 // add nodes of face up to first node of link
8782 if(theFace->IsQuadratic()) {
8783 const SMDS_VtkFace* F =
8784 dynamic_cast<const SMDS_VtkFace*>(theFace);
8785 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8786 // use special nodes iterator
8787 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8788 while( anIter->more() && !isFLN ) {
8789 const SMDS_MeshNode* n = cast2Node(anIter->next());
8790 poly_nodes[iNode++] = n;
8791 if (n == nodes[il1]) {
8795 // add nodes to insert
8796 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8797 for (; nIt != aNodesToInsert.end(); nIt++) {
8798 poly_nodes[iNode++] = *nIt;
8800 // add nodes of face starting from last node of link
8801 while ( anIter->more() ) {
8802 poly_nodes[iNode++] = cast2Node(anIter->next());
8806 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8807 while ( nodeIt->more() && !isFLN ) {
8808 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8809 poly_nodes[iNode++] = n;
8810 if (n == nodes[il1]) {
8814 // add nodes to insert
8815 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8816 for (; nIt != aNodesToInsert.end(); nIt++) {
8817 poly_nodes[iNode++] = *nIt;
8819 // add nodes of face starting from last node of link
8820 while ( nodeIt->more() ) {
8821 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8822 poly_nodes[iNode++] = n;
8826 // edit or replace the face
8827 SMESHDS_Mesh *aMesh = GetMeshDS();
8829 if (theFace->IsPoly()) {
8830 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8833 int aShapeId = FindShape( theFace );
8835 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8836 myLastCreatedElems.Append(newElem);
8837 if ( aShapeId && newElem )
8838 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8840 aMesh->RemoveElement(theFace);
8845 SMESHDS_Mesh *aMesh = GetMeshDS();
8846 if( !theFace->IsQuadratic() ) {
8848 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8849 int nbLinkNodes = 2 + aNodesToInsert.size();
8850 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8851 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8852 linkNodes[ 0 ] = nodes[ il1 ];
8853 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8854 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8855 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8856 linkNodes[ iNode++ ] = *nIt;
8858 // decide how to split a quadrangle: compare possible variants
8859 // and choose which of splits to be a quadrangle
8860 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8861 if ( nbFaceNodes == 3 ) {
8862 iBestQuad = nbSplits;
8865 else if ( nbFaceNodes == 4 ) {
8866 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8867 double aBestRate = DBL_MAX;
8868 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8870 double aBadRate = 0;
8871 // evaluate elements quality
8872 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8873 if ( iSplit == iQuad ) {
8874 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8878 aBadRate += getBadRate( &quad, aCrit );
8881 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8883 nodes[ iSplit < iQuad ? i4 : i3 ]);
8884 aBadRate += getBadRate( &tria, aCrit );
8888 if ( aBadRate < aBestRate ) {
8890 aBestRate = aBadRate;
8895 // create new elements
8896 int aShapeId = FindShape( theFace );
8899 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8900 SMDS_MeshElement* newElem = 0;
8901 if ( iSplit == iBestQuad )
8902 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8907 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8909 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8910 myLastCreatedElems.Append(newElem);
8911 if ( aShapeId && newElem )
8912 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8915 // change nodes of theFace
8916 const SMDS_MeshNode* newNodes[ 4 ];
8917 newNodes[ 0 ] = linkNodes[ i1 ];
8918 newNodes[ 1 ] = linkNodes[ i2 ];
8919 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8920 newNodes[ 3 ] = nodes[ i4 ];
8921 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8922 const SMDS_MeshElement* newElem = 0;
8923 if (iSplit == iBestQuad)
8924 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8926 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8927 myLastCreatedElems.Append(newElem);
8928 if ( aShapeId && newElem )
8929 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8930 } // end if(!theFace->IsQuadratic())
8931 else { // theFace is quadratic
8932 // we have to split theFace on simple triangles and one simple quadrangle
8934 int nbshift = tmp*2;
8935 // shift nodes in nodes[] by nbshift
8937 for(i=0; i<nbshift; i++) {
8938 const SMDS_MeshNode* n = nodes[0];
8939 for(j=0; j<nbFaceNodes-1; j++) {
8940 nodes[j] = nodes[j+1];
8942 nodes[nbFaceNodes-1] = n;
8944 il1 = il1 - nbshift;
8945 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8946 // n0 n1 n2 n0 n1 n2
8947 // +-----+-----+ +-----+-----+
8956 // create new elements
8957 int aShapeId = FindShape( theFace );
8960 if(nbFaceNodes==6) { // quadratic triangle
8961 SMDS_MeshElement* newElem =
8962 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8963 myLastCreatedElems.Append(newElem);
8964 if ( aShapeId && newElem )
8965 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8966 if(theFace->IsMediumNode(nodes[il1])) {
8967 // create quadrangle
8968 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
8969 myLastCreatedElems.Append(newElem);
8970 if ( aShapeId && newElem )
8971 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8977 // create quadrangle
8978 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
8979 myLastCreatedElems.Append(newElem);
8980 if ( aShapeId && newElem )
8981 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8987 else { // nbFaceNodes==8 - quadratic quadrangle
8988 SMDS_MeshElement* newElem =
8989 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8990 myLastCreatedElems.Append(newElem);
8991 if ( aShapeId && newElem )
8992 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8993 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
8994 myLastCreatedElems.Append(newElem);
8995 if ( aShapeId && newElem )
8996 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8997 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
8998 myLastCreatedElems.Append(newElem);
8999 if ( aShapeId && newElem )
9000 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9001 if(theFace->IsMediumNode(nodes[il1])) {
9002 // create quadrangle
9003 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9004 myLastCreatedElems.Append(newElem);
9005 if ( aShapeId && newElem )
9006 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9012 // create quadrangle
9013 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9014 myLastCreatedElems.Append(newElem);
9015 if ( aShapeId && newElem )
9016 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9022 // create needed triangles using n1,n2,n3 and inserted nodes
9023 int nbn = 2 + aNodesToInsert.size();
9024 //const SMDS_MeshNode* aNodes[nbn];
9025 vector<const SMDS_MeshNode*> aNodes(nbn);
9026 aNodes[0] = nodes[n1];
9027 aNodes[nbn-1] = nodes[n2];
9028 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9029 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9030 aNodes[iNode++] = *nIt;
9032 for(i=1; i<nbn; i++) {
9033 SMDS_MeshElement* newElem =
9034 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9035 myLastCreatedElems.Append(newElem);
9036 if ( aShapeId && newElem )
9037 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9041 aMesh->RemoveElement(theFace);
9044 //=======================================================================
9045 //function : UpdateVolumes
9047 //=======================================================================
9048 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9049 const SMDS_MeshNode* theBetweenNode2,
9050 list<const SMDS_MeshNode*>& theNodesToInsert)
9052 myLastCreatedElems.Clear();
9053 myLastCreatedNodes.Clear();
9055 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9056 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9057 const SMDS_MeshElement* elem = invElemIt->next();
9059 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9060 SMDS_VolumeTool aVolume (elem);
9061 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9064 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9065 int iface, nbFaces = aVolume.NbFaces();
9066 vector<const SMDS_MeshNode *> poly_nodes;
9067 vector<int> quantities (nbFaces);
9069 for (iface = 0; iface < nbFaces; iface++) {
9070 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9071 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9072 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9074 for (int inode = 0; inode < nbFaceNodes; inode++) {
9075 poly_nodes.push_back(faceNodes[inode]);
9077 if (nbInserted == 0) {
9078 if (faceNodes[inode] == theBetweenNode1) {
9079 if (faceNodes[inode + 1] == theBetweenNode2) {
9080 nbInserted = theNodesToInsert.size();
9082 // add nodes to insert
9083 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9084 for (; nIt != theNodesToInsert.end(); nIt++) {
9085 poly_nodes.push_back(*nIt);
9089 else if (faceNodes[inode] == theBetweenNode2) {
9090 if (faceNodes[inode + 1] == theBetweenNode1) {
9091 nbInserted = theNodesToInsert.size();
9093 // add nodes to insert in reversed order
9094 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9096 for (; nIt != theNodesToInsert.begin(); nIt--) {
9097 poly_nodes.push_back(*nIt);
9099 poly_nodes.push_back(*nIt);
9106 quantities[iface] = nbFaceNodes + nbInserted;
9109 // Replace or update the volume
9110 SMESHDS_Mesh *aMesh = GetMeshDS();
9112 if (elem->IsPoly()) {
9113 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9117 int aShapeId = FindShape( elem );
9119 SMDS_MeshElement* newElem =
9120 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9121 myLastCreatedElems.Append(newElem);
9122 if (aShapeId && newElem)
9123 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9125 aMesh->RemoveElement(elem);
9130 //=======================================================================
9132 * \brief Convert elements contained in a submesh to quadratic
9133 * \retval int - nb of checked elements
9135 //=======================================================================
9137 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9138 SMESH_MesherHelper& theHelper,
9139 const bool theForce3d)
9142 if( !theSm ) return nbElem;
9144 vector<int> nbNodeInFaces;
9145 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9146 while(ElemItr->more())
9149 const SMDS_MeshElement* elem = ElemItr->next();
9150 if( !elem || elem->IsQuadratic() ) continue;
9152 int id = elem->GetID();
9153 //MESSAGE("elem " << id);
9154 id = 0; // get a free number for new elements
9155 int nbNodes = elem->NbNodes();
9156 SMDSAbs_ElementType aType = elem->GetType();
9158 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9159 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9160 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9162 const SMDS_MeshElement* NewElem = 0;
9168 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9176 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9179 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9182 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9187 case SMDSAbs_Volume :
9192 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9195 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9198 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9201 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9202 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9205 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9212 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9214 theSm->AddElement( NewElem );
9216 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9218 // if (!GetMeshDS()->isCompacted())
9219 // GetMeshDS()->compactMesh();
9223 //=======================================================================
9224 //function : ConvertToQuadratic
9226 //=======================================================================
9227 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9229 SMESHDS_Mesh* meshDS = GetMeshDS();
9231 SMESH_MesherHelper aHelper(*myMesh);
9232 aHelper.SetIsQuadratic( true );
9234 int nbCheckedElems = 0;
9235 if ( myMesh->HasShapeToMesh() )
9237 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9239 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9240 while ( smIt->more() ) {
9241 SMESH_subMesh* sm = smIt->next();
9242 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9243 aHelper.SetSubShape( sm->GetSubShape() );
9244 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9249 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9250 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9252 SMESHDS_SubMesh *smDS = 0;
9253 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9254 while(aEdgeItr->more())
9256 const SMDS_MeshEdge* edge = aEdgeItr->next();
9257 if(edge && !edge->IsQuadratic())
9259 int id = edge->GetID();
9260 //MESSAGE("edge->GetID() " << id);
9261 const SMDS_MeshNode* n1 = edge->GetNode(0);
9262 const SMDS_MeshNode* n2 = edge->GetNode(1);
9264 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9266 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9267 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9270 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9271 while(aFaceItr->more())
9273 const SMDS_MeshFace* face = aFaceItr->next();
9274 if(!face || face->IsQuadratic() ) continue;
9276 int id = face->GetID();
9277 int nbNodes = face->NbNodes();
9278 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9280 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9282 SMDS_MeshFace * NewFace = 0;
9286 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9289 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9292 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9294 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9296 vector<int> nbNodeInFaces;
9297 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9298 while(aVolumeItr->more())
9300 const SMDS_MeshVolume* volume = aVolumeItr->next();
9301 if(!volume || volume->IsQuadratic() ) continue;
9303 int id = volume->GetID();
9304 int nbNodes = volume->NbNodes();
9305 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9306 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9307 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9309 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9311 SMDS_MeshVolume * NewVolume = 0;
9315 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9316 nodes[3], id, theForce3d );
9319 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9320 nodes[3], nodes[4], id, theForce3d);
9323 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9324 nodes[3], nodes[4], nodes[5], id, theForce3d);
9327 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9328 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9331 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9333 ReplaceElemInGroups(volume, NewVolume, meshDS);
9337 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9338 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9339 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9340 aHelper.FixQuadraticElements();
9342 if (!GetMeshDS()->isCompacted())
9343 GetMeshDS()->compactMesh();
9346 //=======================================================================
9348 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9349 * \retval int - nb of checked elements
9351 //=======================================================================
9353 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9354 SMDS_ElemIteratorPtr theItr,
9355 const int theShapeID)
9358 SMESHDS_Mesh* meshDS = GetMeshDS();
9359 const bool notFromGroups = false;
9361 while( theItr->more() )
9363 const SMDS_MeshElement* elem = theItr->next();
9365 if( elem && elem->IsQuadratic())
9367 int id = elem->GetID();
9368 int nbNodes = elem->NbNodes();
9369 vector<const SMDS_MeshNode *> nodes, mediumNodes;
9370 nodes.reserve( nbNodes );
9371 mediumNodes.reserve( nbNodes );
9373 for(int i = 0; i < nbNodes; i++)
9375 const SMDS_MeshNode* n = elem->GetNode(i);
9377 if( elem->IsMediumNode( n ) )
9378 mediumNodes.push_back( n );
9380 nodes.push_back( n );
9382 if( nodes.empty() ) continue;
9383 SMDSAbs_ElementType aType = elem->GetType();
9385 //remove old quadratic element
9386 meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
9388 SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
9389 ReplaceElemInGroups(elem, NewElem, meshDS);
9390 if( theSm && NewElem )
9391 theSm->AddElement( NewElem );
9393 // remove medium nodes
9394 vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
9395 for ( ; nIt != mediumNodes.end(); ++nIt ) {
9396 const SMDS_MeshNode* n = *nIt;
9397 if ( n->NbInverseElements() == 0 ) {
9398 if ( n->getshapeId() != theShapeID )
9399 meshDS->RemoveFreeNode( n, meshDS->MeshElements
9400 ( n->getshapeId() ));
9402 meshDS->RemoveFreeNode( n, theSm );
9410 //=======================================================================
9411 //function : ConvertFromQuadratic
9413 //=======================================================================
9414 bool SMESH_MeshEditor::ConvertFromQuadratic()
9416 int nbCheckedElems = 0;
9417 if ( myMesh->HasShapeToMesh() )
9419 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9421 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9422 while ( smIt->more() ) {
9423 SMESH_subMesh* sm = smIt->next();
9424 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9425 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9431 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9432 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9434 SMESHDS_SubMesh *aSM = 0;
9435 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9441 //=======================================================================
9442 //function : SewSideElements
9444 //=======================================================================
9446 SMESH_MeshEditor::Sew_Error
9447 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9448 TIDSortedElemSet& theSide2,
9449 const SMDS_MeshNode* theFirstNode1,
9450 const SMDS_MeshNode* theFirstNode2,
9451 const SMDS_MeshNode* theSecondNode1,
9452 const SMDS_MeshNode* theSecondNode2)
9454 myLastCreatedElems.Clear();
9455 myLastCreatedNodes.Clear();
9457 MESSAGE ("::::SewSideElements()");
9458 if ( theSide1.size() != theSide2.size() )
9459 return SEW_DIFF_NB_OF_ELEMENTS;
9461 Sew_Error aResult = SEW_OK;
9463 // 1. Build set of faces representing each side
9464 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9465 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9467 // =======================================================================
9468 // 1. Build set of faces representing each side:
9469 // =======================================================================
9470 // a. build set of nodes belonging to faces
9471 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9472 // c. create temporary faces representing side of volumes if correspondent
9473 // face does not exist
9475 SMESHDS_Mesh* aMesh = GetMeshDS();
9476 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9477 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9478 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9479 set<const SMDS_MeshElement*> volSet1, volSet2;
9480 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9481 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9482 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9483 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9484 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9485 int iSide, iFace, iNode;
9487 list<const SMDS_MeshElement* > tempFaceList;
9488 for ( iSide = 0; iSide < 2; iSide++ ) {
9489 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9490 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9491 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9492 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9493 set<const SMDS_MeshElement*>::iterator vIt;
9494 TIDSortedElemSet::iterator eIt;
9495 set<const SMDS_MeshNode*>::iterator nIt;
9497 // check that given nodes belong to given elements
9498 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9499 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9500 int firstIndex = -1, secondIndex = -1;
9501 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9502 const SMDS_MeshElement* elem = *eIt;
9503 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9504 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9505 if ( firstIndex > -1 && secondIndex > -1 ) break;
9507 if ( firstIndex < 0 || secondIndex < 0 ) {
9508 // we can simply return until temporary faces created
9509 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9512 // -----------------------------------------------------------
9513 // 1a. Collect nodes of existing faces
9514 // and build set of face nodes in order to detect missing
9515 // faces corresponding to sides of volumes
9516 // -----------------------------------------------------------
9518 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9520 // loop on the given element of a side
9521 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9522 //const SMDS_MeshElement* elem = *eIt;
9523 const SMDS_MeshElement* elem = *eIt;
9524 if ( elem->GetType() == SMDSAbs_Face ) {
9525 faceSet->insert( elem );
9526 set <const SMDS_MeshNode*> faceNodeSet;
9527 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9528 while ( nodeIt->more() ) {
9529 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9530 nodeSet->insert( n );
9531 faceNodeSet.insert( n );
9533 setOfFaceNodeSet.insert( faceNodeSet );
9535 else if ( elem->GetType() == SMDSAbs_Volume )
9536 volSet->insert( elem );
9538 // ------------------------------------------------------------------------------
9539 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9540 // ------------------------------------------------------------------------------
9542 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9543 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9544 while ( fIt->more() ) { // loop on faces sharing a node
9545 const SMDS_MeshElement* f = fIt->next();
9546 if ( faceSet->find( f ) == faceSet->end() ) {
9547 // check if all nodes are in nodeSet and
9548 // complete setOfFaceNodeSet if they are
9549 set <const SMDS_MeshNode*> faceNodeSet;
9550 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9551 bool allInSet = true;
9552 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9553 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9554 if ( nodeSet->find( n ) == nodeSet->end() )
9557 faceNodeSet.insert( n );
9560 faceSet->insert( f );
9561 setOfFaceNodeSet.insert( faceNodeSet );
9567 // -------------------------------------------------------------------------
9568 // 1c. Create temporary faces representing sides of volumes if correspondent
9569 // face does not exist
9570 // -------------------------------------------------------------------------
9572 if ( !volSet->empty() ) {
9573 //int nodeSetSize = nodeSet->size();
9575 // loop on given volumes
9576 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9577 SMDS_VolumeTool vol (*vIt);
9578 // loop on volume faces: find free faces
9579 // --------------------------------------
9580 list<const SMDS_MeshElement* > freeFaceList;
9581 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9582 if ( !vol.IsFreeFace( iFace ))
9584 // check if there is already a face with same nodes in a face set
9585 const SMDS_MeshElement* aFreeFace = 0;
9586 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9587 int nbNodes = vol.NbFaceNodes( iFace );
9588 set <const SMDS_MeshNode*> faceNodeSet;
9589 vol.GetFaceNodes( iFace, faceNodeSet );
9590 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9592 // no such a face is given but it still can exist, check it
9593 if ( nbNodes == 3 ) {
9594 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9596 else if ( nbNodes == 4 ) {
9597 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9600 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9601 aFreeFace = aMesh->FindFace(poly_nodes);
9605 // create a temporary face
9606 if ( nbNodes == 3 ) {
9607 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9608 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9610 else if ( nbNodes == 4 ) {
9611 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9612 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9615 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9616 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9617 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9621 freeFaceList.push_back( aFreeFace );
9622 tempFaceList.push_back( aFreeFace );
9625 } // loop on faces of a volume
9627 // choose one of several free faces
9628 // --------------------------------------
9629 if ( freeFaceList.size() > 1 ) {
9630 // choose a face having max nb of nodes shared by other elems of a side
9631 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9632 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9633 while ( fIt != freeFaceList.end() ) { // loop on free faces
9634 int nbSharedNodes = 0;
9635 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9636 while ( nodeIt->more() ) { // loop on free face nodes
9637 const SMDS_MeshNode* n =
9638 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9639 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9640 while ( invElemIt->more() ) {
9641 const SMDS_MeshElement* e = invElemIt->next();
9642 if ( faceSet->find( e ) != faceSet->end() )
9644 if ( elemSet->find( e ) != elemSet->end() )
9648 if ( nbSharedNodes >= maxNbNodes ) {
9649 maxNbNodes = nbSharedNodes;
9653 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9655 if ( freeFaceList.size() > 1 )
9657 // could not choose one face, use another way
9658 // choose a face most close to the bary center of the opposite side
9659 gp_XYZ aBC( 0., 0., 0. );
9660 set <const SMDS_MeshNode*> addedNodes;
9661 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9662 eIt = elemSet2->begin();
9663 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9664 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9665 while ( nodeIt->more() ) { // loop on free face nodes
9666 const SMDS_MeshNode* n =
9667 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9668 if ( addedNodes.insert( n ).second )
9669 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9672 aBC /= addedNodes.size();
9673 double minDist = DBL_MAX;
9674 fIt = freeFaceList.begin();
9675 while ( fIt != freeFaceList.end() ) { // loop on free faces
9677 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9678 while ( nodeIt->more() ) { // loop on free face nodes
9679 const SMDS_MeshNode* n =
9680 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9681 gp_XYZ p( n->X(),n->Y(),n->Z() );
9682 dist += ( aBC - p ).SquareModulus();
9684 if ( dist < minDist ) {
9686 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9689 fIt = freeFaceList.erase( fIt++ );
9692 } // choose one of several free faces of a volume
9694 if ( freeFaceList.size() == 1 ) {
9695 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9696 faceSet->insert( aFreeFace );
9697 // complete a node set with nodes of a found free face
9698 // for ( iNode = 0; iNode < ; iNode++ )
9699 // nodeSet->insert( fNodes[ iNode ] );
9702 } // loop on volumes of a side
9704 // // complete a set of faces if new nodes in a nodeSet appeared
9705 // // ----------------------------------------------------------
9706 // if ( nodeSetSize != nodeSet->size() ) {
9707 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9708 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9709 // while ( fIt->more() ) { // loop on faces sharing a node
9710 // const SMDS_MeshElement* f = fIt->next();
9711 // if ( faceSet->find( f ) == faceSet->end() ) {
9712 // // check if all nodes are in nodeSet and
9713 // // complete setOfFaceNodeSet if they are
9714 // set <const SMDS_MeshNode*> faceNodeSet;
9715 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9716 // bool allInSet = true;
9717 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9718 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9719 // if ( nodeSet->find( n ) == nodeSet->end() )
9720 // allInSet = false;
9722 // faceNodeSet.insert( n );
9724 // if ( allInSet ) {
9725 // faceSet->insert( f );
9726 // setOfFaceNodeSet.insert( faceNodeSet );
9732 } // Create temporary faces, if there are volumes given
9735 if ( faceSet1.size() != faceSet2.size() ) {
9736 // delete temporary faces: they are in reverseElements of actual nodes
9737 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9738 // while ( tmpFaceIt->more() )
9739 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9740 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9741 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9742 // aMesh->RemoveElement(*tmpFaceIt);
9743 MESSAGE("Diff nb of faces");
9744 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9747 // ============================================================
9748 // 2. Find nodes to merge:
9749 // bind a node to remove to a node to put instead
9750 // ============================================================
9752 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
9753 if ( theFirstNode1 != theFirstNode2 )
9754 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
9755 if ( theSecondNode1 != theSecondNode2 )
9756 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
9758 LinkID_Gen aLinkID_Gen( GetMeshDS() );
9759 set< long > linkIdSet; // links to process
9760 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
9762 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
9763 list< NLink > linkList[2];
9764 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
9765 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
9766 // loop on links in linkList; find faces by links and append links
9767 // of the found faces to linkList
9768 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
9769 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
9770 NLink link[] = { *linkIt[0], *linkIt[1] };
9771 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
9772 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
9775 // by links, find faces in the face sets,
9776 // and find indices of link nodes in the found faces;
9777 // in a face set, there is only one or no face sharing a link
9778 // ---------------------------------------------------------------
9780 const SMDS_MeshElement* face[] = { 0, 0 };
9781 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
9782 vector<const SMDS_MeshNode*> fnodes1(9);
9783 vector<const SMDS_MeshNode*> fnodes2(9);
9784 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
9785 vector<const SMDS_MeshNode*> notLinkNodes1(6);
9786 vector<const SMDS_MeshNode*> notLinkNodes2(6);
9787 int iLinkNode[2][2];
9788 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9789 const SMDS_MeshNode* n1 = link[iSide].first;
9790 const SMDS_MeshNode* n2 = link[iSide].second;
9791 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9792 set< const SMDS_MeshElement* > fMap;
9793 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
9794 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
9795 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
9796 while ( fIt->more() ) { // loop on faces sharing a node
9797 const SMDS_MeshElement* f = fIt->next();
9798 if (faceSet->find( f ) != faceSet->end() && // f is in face set
9799 ! fMap.insert( f ).second ) // f encounters twice
9801 if ( face[ iSide ] ) {
9802 MESSAGE( "2 faces per link " );
9803 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
9807 faceSet->erase( f );
9808 // get face nodes and find ones of a link
9813 fnodes1.resize(f->NbNodes()+1);
9814 notLinkNodes1.resize(f->NbNodes()-2);
9817 fnodes2.resize(f->NbNodes()+1);
9818 notLinkNodes2.resize(f->NbNodes()-2);
9821 if(!f->IsQuadratic()) {
9822 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
9823 while ( nIt->more() ) {
9824 const SMDS_MeshNode* n =
9825 static_cast<const SMDS_MeshNode*>( nIt->next() );
9827 iLinkNode[ iSide ][ 0 ] = iNode;
9829 else if ( n == n2 ) {
9830 iLinkNode[ iSide ][ 1 ] = iNode;
9832 //else if ( notLinkNodes[ iSide ][ 0 ] )
9833 // notLinkNodes[ iSide ][ 1 ] = n;
9835 // notLinkNodes[ iSide ][ 0 ] = n;
9839 notLinkNodes1[nbl] = n;
9840 //notLinkNodes1.push_back(n);
9842 notLinkNodes2[nbl] = n;
9843 //notLinkNodes2.push_back(n);
9845 //faceNodes[ iSide ][ iNode++ ] = n;
9847 fnodes1[iNode++] = n;
9850 fnodes2[iNode++] = n;
9854 else { // f->IsQuadratic()
9855 const SMDS_VtkFace* F =
9856 dynamic_cast<const SMDS_VtkFace*>(f);
9857 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9858 // use special nodes iterator
9859 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9860 while ( anIter->more() ) {
9861 const SMDS_MeshNode* n =
9862 static_cast<const SMDS_MeshNode*>( anIter->next() );
9864 iLinkNode[ iSide ][ 0 ] = iNode;
9866 else if ( n == n2 ) {
9867 iLinkNode[ iSide ][ 1 ] = iNode;
9872 notLinkNodes1[nbl] = n;
9875 notLinkNodes2[nbl] = n;
9879 fnodes1[iNode++] = n;
9882 fnodes2[iNode++] = n;
9886 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
9888 fnodes1[iNode] = fnodes1[0];
9891 fnodes2[iNode] = fnodes1[0];
9898 // check similarity of elements of the sides
9899 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
9900 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
9901 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
9902 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
9905 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9907 break; // do not return because it s necessary to remove tmp faces
9910 // set nodes to merge
9911 // -------------------
9913 if ( face[0] && face[1] ) {
9914 int nbNodes = face[0]->NbNodes();
9915 if ( nbNodes != face[1]->NbNodes() ) {
9916 MESSAGE("Diff nb of face nodes");
9917 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9918 break; // do not return because it s necessary to remove tmp faces
9920 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
9921 if ( nbNodes == 3 ) {
9922 //nReplaceMap.insert( TNodeNodeMap::value_type
9923 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9924 nReplaceMap.insert( TNodeNodeMap::value_type
9925 ( notLinkNodes1[0], notLinkNodes2[0] ));
9928 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
9929 // analyse link orientation in faces
9930 int i1 = iLinkNode[ iSide ][ 0 ];
9931 int i2 = iLinkNode[ iSide ][ 1 ];
9932 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
9933 // if notLinkNodes are the first and the last ones, then
9934 // their order does not correspond to the link orientation
9935 if (( i1 == 1 && i2 == 2 ) ||
9936 ( i1 == 2 && i2 == 1 ))
9937 reverse[ iSide ] = !reverse[ iSide ];
9939 if ( reverse[0] == reverse[1] ) {
9940 //nReplaceMap.insert( TNodeNodeMap::value_type
9941 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
9942 //nReplaceMap.insert( TNodeNodeMap::value_type
9943 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
9944 for(int nn=0; nn<nbNodes-2; nn++) {
9945 nReplaceMap.insert( TNodeNodeMap::value_type
9946 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
9950 //nReplaceMap.insert( TNodeNodeMap::value_type
9951 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
9952 //nReplaceMap.insert( TNodeNodeMap::value_type
9953 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
9954 for(int nn=0; nn<nbNodes-2; nn++) {
9955 nReplaceMap.insert( TNodeNodeMap::value_type
9956 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
9961 // add other links of the faces to linkList
9962 // -----------------------------------------
9964 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
9965 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
9966 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
9967 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
9968 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
9969 if ( !iter_isnew.second ) { // already in a set: no need to process
9970 linkIdSet.erase( iter_isnew.first );
9972 else // new in set == encountered for the first time: add
9974 //const SMDS_MeshNode* n1 = nodes[ iNode ];
9975 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
9976 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
9977 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
9978 linkList[0].push_back ( NLink( n1, n2 ));
9979 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
9983 } // loop on link lists
9985 if ( aResult == SEW_OK &&
9986 ( linkIt[0] != linkList[0].end() ||
9987 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
9988 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
9989 " " << (faceSetPtr[1]->empty()));
9990 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9993 // ====================================================================
9994 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9995 // ====================================================================
9997 // delete temporary faces: they are in reverseElements of actual nodes
9998 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9999 // while ( tmpFaceIt->more() )
10000 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10001 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10002 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10003 // aMesh->RemoveElement(*tmpFaceIt);
10005 if ( aResult != SEW_OK)
10008 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10009 // loop on nodes replacement map
10010 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10011 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10012 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10013 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10014 nodeIDsToRemove.push_back( nToRemove->GetID() );
10015 // loop on elements sharing nToRemove
10016 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10017 while ( invElemIt->more() ) {
10018 const SMDS_MeshElement* e = invElemIt->next();
10019 // get a new suite of nodes: make replacement
10020 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10021 vector< const SMDS_MeshNode*> nodes( nbNodes );
10022 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10023 while ( nIt->more() ) {
10024 const SMDS_MeshNode* n =
10025 static_cast<const SMDS_MeshNode*>( nIt->next() );
10026 nnIt = nReplaceMap.find( n );
10027 if ( nnIt != nReplaceMap.end() ) {
10029 n = (*nnIt).second;
10033 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10034 // elemIDsToRemove.push_back( e->GetID() );
10038 SMDSAbs_ElementType etyp = e->GetType();
10039 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10042 myLastCreatedElems.Append(newElem);
10043 AddToSameGroups(newElem, e, aMesh);
10044 int aShapeId = e->getshapeId();
10047 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10050 aMesh->RemoveElement(e);
10055 Remove( nodeIDsToRemove, true );
10060 //================================================================================
10062 * \brief Find corresponding nodes in two sets of faces
10063 * \param theSide1 - first face set
10064 * \param theSide2 - second first face
10065 * \param theFirstNode1 - a boundary node of set 1
10066 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10067 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10068 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10069 * \param nReplaceMap - output map of corresponding nodes
10070 * \retval bool - is a success or not
10072 //================================================================================
10075 //#define DEBUG_MATCHING_NODES
10078 SMESH_MeshEditor::Sew_Error
10079 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10080 set<const SMDS_MeshElement*>& theSide2,
10081 const SMDS_MeshNode* theFirstNode1,
10082 const SMDS_MeshNode* theFirstNode2,
10083 const SMDS_MeshNode* theSecondNode1,
10084 const SMDS_MeshNode* theSecondNode2,
10085 TNodeNodeMap & nReplaceMap)
10087 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10089 nReplaceMap.clear();
10090 if ( theFirstNode1 != theFirstNode2 )
10091 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10092 if ( theSecondNode1 != theSecondNode2 )
10093 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10095 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10096 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10098 list< NLink > linkList[2];
10099 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10100 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10102 // loop on links in linkList; find faces by links and append links
10103 // of the found faces to linkList
10104 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10105 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10106 NLink link[] = { *linkIt[0], *linkIt[1] };
10107 if ( linkSet.find( link[0] ) == linkSet.end() )
10110 // by links, find faces in the face sets,
10111 // and find indices of link nodes in the found faces;
10112 // in a face set, there is only one or no face sharing a link
10113 // ---------------------------------------------------------------
10115 const SMDS_MeshElement* face[] = { 0, 0 };
10116 list<const SMDS_MeshNode*> notLinkNodes[2];
10117 //bool reverse[] = { false, false }; // order of notLinkNodes
10119 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10121 const SMDS_MeshNode* n1 = link[iSide].first;
10122 const SMDS_MeshNode* n2 = link[iSide].second;
10123 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10124 set< const SMDS_MeshElement* > facesOfNode1;
10125 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10127 // during a loop of the first node, we find all faces around n1,
10128 // during a loop of the second node, we find one face sharing both n1 and n2
10129 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10130 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10131 while ( fIt->more() ) { // loop on faces sharing a node
10132 const SMDS_MeshElement* f = fIt->next();
10133 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10134 ! facesOfNode1.insert( f ).second ) // f encounters twice
10136 if ( face[ iSide ] ) {
10137 MESSAGE( "2 faces per link " );
10138 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10141 faceSet->erase( f );
10143 // get not link nodes
10144 int nbN = f->NbNodes();
10145 if ( f->IsQuadratic() )
10147 nbNodes[ iSide ] = nbN;
10148 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10149 int i1 = f->GetNodeIndex( n1 );
10150 int i2 = f->GetNodeIndex( n2 );
10151 int iEnd = nbN, iBeg = -1, iDelta = 1;
10152 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10154 std::swap( iEnd, iBeg ); iDelta = -1;
10159 if ( i == iEnd ) i = iBeg + iDelta;
10160 if ( i == i1 ) break;
10161 nodes.push_back ( f->GetNode( i ) );
10167 // check similarity of elements of the sides
10168 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10169 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10170 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10171 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10174 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10178 // set nodes to merge
10179 // -------------------
10181 if ( face[0] && face[1] ) {
10182 if ( nbNodes[0] != nbNodes[1] ) {
10183 MESSAGE("Diff nb of face nodes");
10184 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10186 #ifdef DEBUG_MATCHING_NODES
10187 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10188 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10189 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10191 int nbN = nbNodes[0];
10193 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10194 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10195 for ( int i = 0 ; i < nbN - 2; ++i ) {
10196 #ifdef DEBUG_MATCHING_NODES
10197 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10199 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10203 // add other links of the face 1 to linkList
10204 // -----------------------------------------
10206 const SMDS_MeshElement* f0 = face[0];
10207 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10208 for ( int i = 0; i < nbN; i++ )
10210 const SMDS_MeshNode* n2 = f0->GetNode( i );
10211 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10212 linkSet.insert( SMESH_TLink( n1, n2 ));
10213 if ( !iter_isnew.second ) { // already in a set: no need to process
10214 linkSet.erase( iter_isnew.first );
10216 else // new in set == encountered for the first time: add
10218 #ifdef DEBUG_MATCHING_NODES
10219 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10220 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10222 linkList[0].push_back ( NLink( n1, n2 ));
10223 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10228 } // loop on link lists
10233 //================================================================================
10235 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10236 \param theElems - the list of elements (edges or faces) to be replicated
10237 The nodes for duplication could be found from these elements
10238 \param theNodesNot - list of nodes to NOT replicate
10239 \param theAffectedElems - the list of elements (cells and edges) to which the
10240 replicated nodes should be associated to.
10241 \return TRUE if operation has been completed successfully, FALSE otherwise
10243 //================================================================================
10245 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10246 const TIDSortedElemSet& theNodesNot,
10247 const TIDSortedElemSet& theAffectedElems )
10249 myLastCreatedElems.Clear();
10250 myLastCreatedNodes.Clear();
10252 if ( theElems.size() == 0 )
10255 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10260 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10261 // duplicate elements and nodes
10262 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10263 // replce nodes by duplications
10264 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10268 //================================================================================
10270 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10271 \param theMeshDS - mesh instance
10272 \param theElems - the elements replicated or modified (nodes should be changed)
10273 \param theNodesNot - nodes to NOT replicate
10274 \param theNodeNodeMap - relation of old node to new created node
10275 \param theIsDoubleElem - flag os to replicate element or modify
10276 \return TRUE if operation has been completed successfully, FALSE otherwise
10278 //================================================================================
10280 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10281 const TIDSortedElemSet& theElems,
10282 const TIDSortedElemSet& theNodesNot,
10283 std::map< const SMDS_MeshNode*,
10284 const SMDS_MeshNode* >& theNodeNodeMap,
10285 const bool theIsDoubleElem )
10287 MESSAGE("doubleNodes");
10288 // iterate on through element and duplicate them (by nodes duplication)
10290 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10291 for ( ; elemItr != theElems.end(); ++elemItr )
10293 const SMDS_MeshElement* anElem = *elemItr;
10297 bool isDuplicate = false;
10298 // duplicate nodes to duplicate element
10299 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10300 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10302 while ( anIter->more() )
10305 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10306 SMDS_MeshNode* aNewNode = aCurrNode;
10307 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10308 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10309 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10312 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10313 theNodeNodeMap[ aCurrNode ] = aNewNode;
10314 myLastCreatedNodes.Append( aNewNode );
10316 isDuplicate |= (aCurrNode != aNewNode);
10317 newNodes[ ind++ ] = aNewNode;
10319 if ( !isDuplicate )
10322 if ( theIsDoubleElem )
10323 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10326 MESSAGE("ChangeElementNodes");
10327 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10334 //================================================================================
10336 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10337 \param theNodes - identifiers of nodes to be doubled
10338 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10339 nodes. If list of element identifiers is empty then nodes are doubled but
10340 they not assigned to elements
10341 \return TRUE if operation has been completed successfully, FALSE otherwise
10343 //================================================================================
10345 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10346 const std::list< int >& theListOfModifiedElems )
10348 MESSAGE("DoubleNodes");
10349 myLastCreatedElems.Clear();
10350 myLastCreatedNodes.Clear();
10352 if ( theListOfNodes.size() == 0 )
10355 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10359 // iterate through nodes and duplicate them
10361 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10363 std::list< int >::const_iterator aNodeIter;
10364 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10366 int aCurr = *aNodeIter;
10367 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10373 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10376 anOldNodeToNewNode[ aNode ] = aNewNode;
10377 myLastCreatedNodes.Append( aNewNode );
10381 // Create map of new nodes for modified elements
10383 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10385 std::list< int >::const_iterator anElemIter;
10386 for ( anElemIter = theListOfModifiedElems.begin();
10387 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10389 int aCurr = *anElemIter;
10390 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10394 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10396 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10398 while ( anIter->more() )
10400 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10401 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10403 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10404 aNodeArr[ ind++ ] = aNewNode;
10407 aNodeArr[ ind++ ] = aCurrNode;
10409 anElemToNodes[ anElem ] = aNodeArr;
10412 // Change nodes of elements
10414 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10415 anElemToNodesIter = anElemToNodes.begin();
10416 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10418 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10419 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10422 MESSAGE("ChangeElementNodes");
10423 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10432 //================================================================================
10434 \brief Check if element located inside shape
10435 \return TRUE if IN or ON shape, FALSE otherwise
10437 //================================================================================
10439 template<class Classifier>
10440 bool isInside(const SMDS_MeshElement* theElem,
10441 Classifier& theClassifier,
10442 const double theTol)
10444 gp_XYZ centerXYZ (0, 0, 0);
10445 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10446 while (aNodeItr->more())
10447 centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
10449 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10450 theClassifier.Perform(aPnt, theTol);
10451 TopAbs_State aState = theClassifier.State();
10452 return (aState == TopAbs_IN || aState == TopAbs_ON );
10455 //================================================================================
10457 * \brief Classifier of the 3D point on the TopoDS_Face
10458 * with interaface suitable for isInside()
10460 //================================================================================
10462 struct _FaceClassifier
10464 Extrema_ExtPS _extremum;
10465 BRepAdaptor_Surface _surface;
10466 TopAbs_State _state;
10468 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10470 _extremum.Initialize( _surface,
10471 _surface.FirstUParameter(), _surface.LastUParameter(),
10472 _surface.FirstVParameter(), _surface.LastVParameter(),
10473 _surface.Tolerance(), _surface.Tolerance() );
10475 void Perform(const gp_Pnt& aPnt, double theTol)
10477 _state = TopAbs_OUT;
10478 _extremum.Perform(aPnt);
10479 if ( _extremum.IsDone() )
10480 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10481 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10483 TopAbs_State State() const
10490 //================================================================================
10492 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10493 \param theElems - group of of elements (edges or faces) to be replicated
10494 \param theNodesNot - group of nodes not to replicate
10495 \param theShape - shape to detect affected elements (element which geometric center
10496 located on or inside shape).
10497 The replicated nodes should be associated to affected elements.
10498 \return TRUE if operation has been completed successfully, FALSE otherwise
10500 //================================================================================
10502 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10503 const TIDSortedElemSet& theNodesNot,
10504 const TopoDS_Shape& theShape )
10506 if ( theShape.IsNull() )
10509 const double aTol = Precision::Confusion();
10510 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10511 auto_ptr<_FaceClassifier> aFaceClassifier;
10512 if ( theShape.ShapeType() == TopAbs_SOLID )
10514 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10515 bsc3d->PerformInfinitePoint(aTol);
10517 else if (theShape.ShapeType() == TopAbs_FACE )
10519 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10522 // iterates on indicated elements and get elements by back references from their nodes
10523 TIDSortedElemSet anAffected;
10524 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10525 for ( ; elemItr != theElems.end(); ++elemItr )
10527 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10531 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10532 while ( nodeItr->more() )
10534 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10535 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10537 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10538 while ( backElemItr->more() )
10540 const SMDS_MeshElement* curElem = backElemItr->next();
10541 if ( curElem && theElems.find(curElem) == theElems.end() &&
10543 isInside( curElem, *bsc3d, aTol ) :
10544 isInside( curElem, *aFaceClassifier, aTol )))
10545 anAffected.insert( curElem );
10549 return DoubleNodes( theElems, theNodesNot, anAffected );
10553 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10554 * The list of groups must describe a partition of the mesh volumes.
10555 * The nodes of the internal faces at the boundaries of the groups are doubled.
10556 * In option, the internal faces are replaced by flat elements.
10557 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10558 * @param theElems - list of groups of volumes, where a group of volume is a set of
10559 * SMDS_MeshElements sorted by Id.
10560 * @param createJointElems - if TRUE, create the elements
10561 * @return TRUE if operation has been completed successfully, FALSE otherwise
10563 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10564 bool createJointElems)
10566 MESSAGE("------------------------------------------------------");
10567 MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
10568 MESSAGE("------------------------------------------------------");
10570 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10571 meshDS->BuildDownWardConnectivity(false);
10573 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10575 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10576 // build the list of nodes shared by 2 or more domains, with their domain indexes
10578 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
10579 std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
10580 faceDomains.clear();
10581 nodeDomains.clear();
10582 std::map<int,int> emptyMap;
10585 for (int idom = 0; idom < theElems.size(); idom++)
10588 // --- build a map (face to duplicate --> volume to modify)
10589 // with all the faces shared by 2 domains (group of elements)
10590 // and corresponding volume of this domain, for each shared face.
10591 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10593 const TIDSortedElemSet& domain = theElems[idom];
10594 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10595 for (; elemItr != domain.end(); ++elemItr)
10597 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10600 int vtkId = anElem->getVtkId();
10601 int neighborsVtkIds[NBMAXNEIGHBORS];
10602 int downIds[NBMAXNEIGHBORS];
10603 unsigned char downTypes[NBMAXNEIGHBORS];
10604 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10605 for (int n = 0; n < nbNeighbors; n++)
10607 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10608 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10609 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10611 DownIdType face(downIds[n], downTypes[n]);
10612 if (!faceDomains.count(face))
10613 faceDomains[face] = emptyMap; // create an empty entry for face
10614 if (!faceDomains[face].count(idom))
10616 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10623 MESSAGE("Number of shared faces " << faceDomains.size());
10625 // --- for each shared face, get the nodes
10626 // for each node, for each domain of the face, create a clone of the node
10628 std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
10629 for( ; itface != faceDomains.end();++itface )
10631 DownIdType face = itface->first;
10632 std::map<int,int> domvol = itface->second;
10633 std::set<int> oldNodes;
10635 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10636 std::set<int>::iterator itn = oldNodes.begin();
10637 for (;itn != oldNodes.end(); ++itn)
10640 if (!nodeDomains.count(oldId))
10641 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10642 std::map<int,int>::iterator itdom = domvol.begin();
10643 for(; itdom != domvol.end(); ++itdom)
10645 int idom = itdom->first;
10646 if ( nodeDomains[oldId].empty() )
10647 nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
10650 double *coords = grid->GetPoint(oldId);
10651 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
10652 int newId = newNode->getVtkId();
10653 nodeDomains[oldId][idom] = newId; // cloned node for other domains
10659 // --- iterate on shared faces (volumes to modify, face to extrude)
10660 // get node id's of the face (id SMDS = id VTK)
10661 // create flat element with old and new nodes if requested
10663 if (createJointElems)
10665 itface = faceDomains.begin();
10666 for( ; itface != faceDomains.end();++itface )
10668 DownIdType face = itface->first;
10669 std::set<int> oldNodes;
10670 std::set<int>::iterator itn;
10672 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10673 std::map<int,int> localClonedNodeIds;
10675 std::map<int,int> domvol = itface->second;
10676 std::map<int,int>::iterator itdom = domvol.begin();
10677 int dom1 = itdom->first;
10678 int vtkVolId = itdom->second;
10680 int dom2 = itdom->first;
10682 localClonedNodeIds.clear();
10683 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10687 if (nodeDomains[oldId].count(dom1))
10688 refid = nodeDomains[oldId][dom1];
10690 MESSAGE("--- problem domain node " << dom1 << " " << oldId);
10692 if (nodeDomains[oldId].count(dom2))
10693 newid = nodeDomains[oldId][dom2];
10695 MESSAGE("--- problem domain node " << dom2 << " " << oldId);
10696 localClonedNodeIds[oldId] = newid;
10698 meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
10702 // --- iterate on shared faces (volumes to modify, face to extrude)
10703 // get node id's of the face
10704 // replace old nodes by new nodes in volumes, and update inverse connectivity
10706 itface = faceDomains.begin();
10707 for( ; itface != faceDomains.end();++itface )
10709 DownIdType face = itface->first;
10710 std::set<int> oldNodes;
10711 std::set<int>::iterator itn;
10713 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10714 std::map<int,int> localClonedNodeIds;
10716 std::map<int,int> domvol = itface->second;
10717 std::map<int,int>::iterator itdom = domvol.begin();
10718 for(; itdom != domvol.end(); ++itdom)
10720 int idom = itdom->first;
10721 int vtkVolId = itdom->second;
10722 localClonedNodeIds.clear();
10723 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
10726 if (nodeDomains[oldId].count(idom))
10727 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
10729 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
10732 grid->BuildLinks();
10734 // TODO replace also old nodes by new nodes in faces and edges
10740 //================================================================================
10742 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
10743 * The created 2D mesh elements based on nodes of free faces of boundary volumes
10744 * \return TRUE if operation has been completed successfully, FALSE otherwise
10746 //================================================================================
10748 bool SMESH_MeshEditor::Make2DMeshFrom3D()
10750 // iterates on volume elements and detect all free faces on them
10751 SMESHDS_Mesh* aMesh = GetMeshDS();
10754 //bool res = false;
10755 int nbFree = 0, nbExisted = 0, nbCreated = 0;
10756 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
10759 const SMDS_MeshVolume* volume = vIt->next();
10760 SMDS_VolumeTool vTool( volume );
10761 vTool.SetExternalNormal();
10762 const bool isPoly = volume->IsPoly();
10763 const bool isQuad = volume->IsQuadratic();
10764 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10766 if (!vTool.IsFreeFace(iface))
10769 vector<const SMDS_MeshNode *> nodes;
10770 int nbFaceNodes = vTool.NbFaceNodes(iface);
10771 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
10773 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
10774 nodes.push_back(faceNodes[inode]);
10776 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10777 nodes.push_back(faceNodes[inode]);
10779 // add new face based on volume nodes
10780 if (aMesh->FindFace( nodes ) ) {
10782 continue; // face already exsist
10784 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
10788 return ( nbFree==(nbExisted+nbCreated) );
10793 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
10795 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
10797 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
10800 //================================================================================
10802 * \brief Creates missing boundary elements
10803 * \param elements - elements whose boundary is to be checked
10804 * \param dimension - defines type of boundary elements to create
10805 * \param group - a group to store created boundary elements in
10806 * \param targetMesh - a mesh to store created boundary elements in
10807 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
10808 * \param toCopyExistingBondary - if true, not only new but also pre-existing
10809 * boundary elements will be copied into the targetMesh
10811 //================================================================================
10813 void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
10814 Bnd_Dimension dimension,
10815 SMESH_Group* group/*=0*/,
10816 SMESH_Mesh* targetMesh/*=0*/,
10817 bool toCopyElements/*=false*/,
10818 bool toCopyExistingBondary/*=false*/)
10820 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
10821 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
10822 // hope that all elements are of the same type, do not check them all
10823 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
10824 throw SALOME_Exception(LOCALIZED("wrong element type"));
10827 toCopyElements = toCopyExistingBondary = false;
10829 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
10830 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
10832 SMDS_VolumeTool vTool;
10833 TIDSortedElemSet emptySet, avoidSet;
10836 typedef vector<const SMDS_MeshNode*> TConnectivity;
10838 SMDS_ElemIteratorPtr eIt;
10839 if (elements.empty())
10840 eIt = aMesh->elementsIterator(elemType);
10842 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10844 while (eIt->more())
10846 const SMDS_MeshElement* elem = eIt->next();
10847 const int iQuad = elem->IsQuadratic();
10849 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
10850 vector<const SMDS_MeshElement*> presentBndElems;
10851 vector<TConnectivity> missingBndElems;
10852 TConnectivity nodes;
10853 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
10855 vTool.SetExternalNormal();
10856 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
10858 if (!vTool.IsFreeFace(iface))
10860 int nbFaceNodes = vTool.NbFaceNodes(iface);
10861 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
10862 if ( missType == SMDSAbs_Edge ) // boundary edges
10864 nodes.resize( 2+iQuad );
10865 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
10867 for ( int j = 0; j < nodes.size(); ++j )
10869 if ( const SMDS_MeshElement* edge =
10870 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
10871 presentBndElems.push_back( edge );
10873 missingBndElems.push_back( nodes );
10876 else // boundary face
10879 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
10880 nodes.push_back( nn[inode] );
10882 for ( inode = 1; inode < nbFaceNodes; inode += 2)
10883 nodes.push_back( nn[inode] );
10885 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
10886 presentBndElems.push_back( f );
10888 missingBndElems.push_back( nodes );
10892 else // elem is a face ------------------------------------------
10894 avoidSet.clear(), avoidSet.insert( elem );
10895 int nbNodes = elem->NbCornerNodes();
10896 nodes.resize( 2 /*+ iQuad*/);
10897 for ( int i = 0; i < nbNodes; i++ )
10899 nodes[0] = elem->GetNode(i);
10900 nodes[1] = elem->GetNode((i+1)%nbNodes);
10901 if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
10902 continue; // not free link
10905 //nodes[2] = elem->GetNode( i + nbNodes );
10906 if ( const SMDS_MeshElement* edge =
10907 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
10908 presentBndElems.push_back( edge );
10910 missingBndElems.push_back( nodes );
10914 // 2. Add missing boundary elements
10915 if ( targetMesh != myMesh )
10916 // instead of making a map of nodes in this mesh and targetMesh,
10917 // we create nodes with same IDs. We can renumber them later, if needed
10918 for ( int i = 0; i < missingBndElems.size(); ++i )
10920 TConnectivity& srcNodes = missingBndElems[i];
10921 TConnectivity nodes( srcNodes.size() );
10922 for ( inode = 0; inode < nodes.size(); ++inode )
10923 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
10924 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10927 for ( int i = 0; i < missingBndElems.size(); ++i )
10929 TConnectivity& nodes = missingBndElems[i];
10930 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
10933 // 3. Copy present boundary elements
10934 if ( toCopyExistingBondary )
10935 for ( int i = 0 ; i < presentBndElems.size(); ++i )
10937 const SMDS_MeshElement* e = presentBndElems[i];
10938 TConnectivity nodes( e->NbNodes() );
10939 for ( inode = 0; inode < nodes.size(); ++inode )
10940 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
10941 tgtEditor.AddElement(nodes, missType, e->IsPoly());
10942 // leave only missing elements in tgtEditor.myLastCreatedElems
10943 tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
10945 } // loop on given elements
10947 // 4. Fill group with missing boundary elements
10950 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
10951 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
10952 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
10954 tgtEditor.myLastCreatedElems.Clear();
10956 // 5. Copy given elements
10957 if ( toCopyElements )
10959 if (elements.empty())
10960 eIt = aMesh->elementsIterator(elemType);
10962 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
10963 while (eIt->more())
10965 const SMDS_MeshElement* elem = eIt->next();
10966 TConnectivity nodes( elem->NbNodes() );
10967 for ( inode = 0; inode < nodes.size(); ++inode )
10968 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
10969 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
10971 tgtEditor.myLastCreatedElems.Clear();