1 // Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
23 // File : SMESH_MeshEditor.cxx
24 // Created : Mon Apr 12 16:10:22 2004
25 // Author : Edward AGAPOV (eap)
28 #include "SMESH_MeshEditor.hxx"
30 #include "SMDS_FaceOfNodes.hxx"
31 #include "SMDS_VolumeTool.hxx"
32 #include "SMDS_EdgePosition.hxx"
33 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
34 #include "SMDS_FacePosition.hxx"
35 #include "SMDS_SpacePosition.hxx"
36 //#include "SMDS_QuadraticFaceOfNodes.hxx"
37 #include "SMDS_MeshGroup.hxx"
38 #include "SMDS_LinearEdge.hxx"
39 #include "SMDS_Downward.hxx"
40 #include "SMDS_SetIterator.hxx"
42 #include "SMESHDS_Group.hxx"
43 #include "SMESHDS_Mesh.hxx"
45 #include "SMESH_Algo.hxx"
46 #include "SMESH_ControlsDef.hxx"
47 #include "SMESH_Group.hxx"
48 #include "SMESH_MesherHelper.hxx"
49 #include "SMESH_OctreeNode.hxx"
50 #include "SMESH_subMesh.hxx"
52 #include <Basics_OCCTVersion.hxx>
54 #include "utilities.h"
56 #include <BRepAdaptor_Surface.hxx>
57 #include <BRepBuilderAPI_MakeEdge.hxx>
58 #include <BRepClass3d_SolidClassifier.hxx>
59 #include <BRep_Tool.hxx>
61 #include <Extrema_GenExtPS.hxx>
62 #include <Extrema_POnCurv.hxx>
63 #include <Extrema_POnSurf.hxx>
64 #include <GC_MakeSegment.hxx>
65 #include <Geom2d_Curve.hxx>
66 #include <GeomAPI_ExtremaCurveCurve.hxx>
67 #include <GeomAdaptor_Surface.hxx>
68 #include <Geom_Curve.hxx>
69 #include <Geom_Line.hxx>
70 #include <Geom_Surface.hxx>
71 #include <IntAna_IntConicQuad.hxx>
72 #include <IntAna_Quadric.hxx>
73 #include <Precision.hxx>
74 #include <TColStd_ListOfInteger.hxx>
75 #include <TopAbs_State.hxx>
77 #include <TopExp_Explorer.hxx>
78 #include <TopTools_ListIteratorOfListOfShape.hxx>
79 #include <TopTools_ListOfShape.hxx>
80 #include <TopTools_SequenceOfShape.hxx>
82 #include <TopoDS_Face.hxx>
88 #include <gp_Trsf.hxx>
102 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
105 using namespace SMESH::Controls;
107 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
108 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
110 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
112 //=======================================================================
113 //function : SMESH_MeshEditor
115 //=======================================================================
117 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
118 :myMesh( theMesh ) // theMesh may be NULL
122 //=======================================================================
126 //=======================================================================
129 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
130 const SMDSAbs_ElementType type,
134 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
135 SMDS_MeshElement* e = 0;
136 int nbnode = node.size();
137 SMESHDS_Mesh* mesh = GetMeshDS();
142 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
143 else e = mesh->AddFace (node[0], node[1], node[2] );
145 else if (nbnode == 4) {
146 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
147 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
149 else if (nbnode == 6) {
150 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
151 node[4], node[5], ID);
152 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
155 else if (nbnode == 8) {
156 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7], ID);
158 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
159 node[4], node[5], node[6], node[7] );
162 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
163 else e = mesh->AddPolygonalFace (node );
170 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
171 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
173 else if (nbnode == 5) {
174 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
176 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
179 else if (nbnode == 6) {
180 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
181 node[4], node[5], ID);
182 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
185 else if (nbnode == 8) {
186 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7], ID);
188 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
189 node[4], node[5], node[6], node[7] );
191 else if (nbnode == 10) {
192 if ( ID >= 1 ) 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],
199 else if (nbnode == 13) {
200 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
201 node[4], node[5], node[6], node[7],
202 node[8], node[9], node[10],node[11],
204 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
205 node[4], node[5], node[6], node[7],
206 node[8], node[9], node[10],node[11],
209 else if (nbnode == 15) {
210 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
211 node[4], node[5], node[6], node[7],
212 node[8], node[9], node[10],node[11],
213 node[12],node[13],node[14],ID);
214 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
215 node[4], node[5], node[6], node[7],
216 node[8], node[9], node[10],node[11],
217 node[12],node[13],node[14] );
219 else if (nbnode == 20) {
220 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
221 node[4], node[5], node[6], node[7],
222 node[8], node[9], node[10],node[11],
223 node[12],node[13],node[14],node[15],
224 node[16],node[17],node[18],node[19],ID);
225 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
226 node[4], node[5], node[6], node[7],
227 node[8], node[9], node[10],node[11],
228 node[12],node[13],node[14],node[15],
229 node[16],node[17],node[18],node[19] );
236 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
237 else e = mesh->AddEdge (node[0], node[1] );
239 else if ( nbnode == 3 ) {
240 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
241 else e = mesh->AddEdge (node[0], node[1], node[2] );
245 case SMDSAbs_0DElement:
247 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
248 else e = mesh->Add0DElement (node[0] );
253 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
254 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
259 if ( e ) myLastCreatedElems.Append( e );
263 //=======================================================================
267 //=======================================================================
269 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
270 const SMDSAbs_ElementType type,
274 vector<const SMDS_MeshNode*> nodes;
275 nodes.reserve( nodeIDs.size() );
276 vector<int>::const_iterator id = nodeIDs.begin();
277 while ( id != nodeIDs.end() ) {
278 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
279 nodes.push_back( node );
283 return AddElement( nodes, type, isPoly, ID );
286 //=======================================================================
288 //purpose : Remove a node or an element.
289 // Modify a compute state of sub-meshes which become empty
290 //=======================================================================
292 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
295 myLastCreatedElems.Clear();
296 myLastCreatedNodes.Clear();
298 SMESHDS_Mesh* aMesh = GetMeshDS();
299 set< SMESH_subMesh *> smmap;
302 list<int>::const_iterator it = theIDs.begin();
303 for ( ; it != theIDs.end(); it++ ) {
304 const SMDS_MeshElement * elem;
306 elem = aMesh->FindNode( *it );
308 elem = aMesh->FindElement( *it );
312 // Notify VERTEX sub-meshes about modification
314 const SMDS_MeshNode* node = cast2Node( elem );
315 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
316 if ( int aShapeID = node->getshapeId() )
317 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
320 // Find sub-meshes to notify about modification
321 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
322 // while ( nodeIt->more() ) {
323 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
324 // const SMDS_PositionPtr& aPosition = node->GetPosition();
325 // if ( aPosition.get() ) {
326 // if ( int aShapeID = aPosition->GetShapeId() ) {
327 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
328 // smmap.insert( sm );
335 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
337 aMesh->RemoveElement( elem );
341 // Notify sub-meshes about modification
342 if ( !smmap.empty() ) {
343 set< SMESH_subMesh *>::iterator smIt;
344 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
345 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
348 // // Check if the whole mesh becomes empty
349 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
350 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
355 //=======================================================================
356 //function : FindShape
357 //purpose : Return an index of the shape theElem is on
358 // or zero if a shape not found
359 //=======================================================================
361 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
363 myLastCreatedElems.Clear();
364 myLastCreatedNodes.Clear();
366 SMESHDS_Mesh * aMesh = GetMeshDS();
367 if ( aMesh->ShapeToMesh().IsNull() )
370 int aShapeID = theElem->getshapeId();
374 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
375 if ( sm->Contains( theElem ))
378 if ( theElem->GetType() == SMDSAbs_Node ) {
379 MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
382 MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
385 TopoDS_Shape aShape; // the shape a node of theElem is on
386 if ( theElem->GetType() != SMDSAbs_Node )
388 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
389 while ( nodeIt->more() ) {
390 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
391 if ((aShapeID = node->getshapeId()) > 0) {
392 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
393 if ( sm->Contains( theElem ))
395 if ( aShape.IsNull() )
396 aShape = aMesh->IndexToShape( aShapeID );
402 // None of nodes is on a proper shape,
403 // find the shape among ancestors of aShape on which a node is
404 if ( !aShape.IsNull() ) {
405 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
406 for ( ; ancIt.More(); ancIt.Next() ) {
407 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
408 if ( sm && sm->Contains( theElem ))
409 return aMesh->ShapeToIndex( ancIt.Value() );
414 const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
415 map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
416 for ( ; id_sm != id2sm.end(); ++id_sm )
417 if ( id_sm->second->Contains( theElem ))
421 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
425 //=======================================================================
426 //function : IsMedium
428 //=======================================================================
430 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
431 const SMDSAbs_ElementType typeToCheck)
433 bool isMedium = false;
434 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
435 while (it->more() && !isMedium ) {
436 const SMDS_MeshElement* elem = it->next();
437 isMedium = elem->IsMediumNode(node);
442 //=======================================================================
443 //function : ShiftNodesQuadTria
445 // Shift nodes in the array corresponded to quadratic triangle
446 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
447 //=======================================================================
448 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
450 const SMDS_MeshNode* nd1 = aNodes[0];
451 aNodes[0] = aNodes[1];
452 aNodes[1] = aNodes[2];
454 const SMDS_MeshNode* nd2 = aNodes[3];
455 aNodes[3] = aNodes[4];
456 aNodes[4] = aNodes[5];
460 //=======================================================================
461 //function : edgeConnectivity
463 // return number of the edges connected with the theNode.
464 // if theEdges has connections with the other type of the
465 // elements, return -1
466 //=======================================================================
467 static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
469 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
471 while(elemIt->more()) {
479 //=======================================================================
480 //function : GetNodesFromTwoTria
482 // Shift nodes in the array corresponded to quadratic triangle
483 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
484 //=======================================================================
485 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
486 const SMDS_MeshElement * theTria2,
487 const SMDS_MeshNode* N1[],
488 const SMDS_MeshNode* N2[])
490 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
493 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
496 if(it->more()) return false;
497 it = theTria2->nodesIterator();
500 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
503 if(it->more()) return false;
505 int sames[3] = {-1,-1,-1};
517 if(nbsames!=2) return false;
519 ShiftNodesQuadTria(N1);
521 ShiftNodesQuadTria(N1);
524 i = sames[0] + sames[1] + sames[2];
526 ShiftNodesQuadTria(N2);
528 // now we receive following N1 and N2 (using numeration as above image)
529 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
530 // i.e. first nodes from both arrays determ new diagonal
534 //=======================================================================
535 //function : InverseDiag
536 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
537 // but having other common link.
538 // Return False if args are improper
539 //=======================================================================
541 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
542 const SMDS_MeshElement * theTria2 )
544 MESSAGE("InverseDiag");
545 myLastCreatedElems.Clear();
546 myLastCreatedNodes.Clear();
548 if (!theTria1 || !theTria2)
551 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
552 if (!F1) return false;
553 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
554 if (!F2) return false;
555 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
556 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
558 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
559 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
563 // put nodes in array and find out indices of the same ones
564 const SMDS_MeshNode* aNodes [6];
565 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
567 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
568 while ( it->more() ) {
569 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
571 if ( i > 2 ) // theTria2
572 // find same node of theTria1
573 for ( int j = 0; j < 3; j++ )
574 if ( aNodes[ i ] == aNodes[ j ]) {
583 return false; // theTria1 is not a triangle
584 it = theTria2->nodesIterator();
586 if ( i == 6 && it->more() )
587 return false; // theTria2 is not a triangle
590 // find indices of 1,2 and of A,B in theTria1
591 int iA = 0, iB = 0, i1 = 0, i2 = 0;
592 for ( i = 0; i < 6; i++ ) {
593 if ( sameInd [ i ] == 0 ) {
602 // nodes 1 and 2 should not be the same
603 if ( aNodes[ i1 ] == aNodes[ i2 ] )
607 aNodes[ iA ] = aNodes[ i2 ];
609 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
611 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
612 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
616 } // end if(F1 && F2)
618 // check case of quadratic faces
619 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
621 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
625 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
626 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
634 const SMDS_MeshNode* N1 [6];
635 const SMDS_MeshNode* N2 [6];
636 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
638 // now we receive following N1 and N2 (using numeration as above image)
639 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
640 // i.e. first nodes from both arrays determ new diagonal
642 const SMDS_MeshNode* N1new [6];
643 const SMDS_MeshNode* N2new [6];
656 // replaces nodes in faces
657 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
658 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
663 //=======================================================================
664 //function : findTriangles
665 //purpose : find triangles sharing theNode1-theNode2 link
666 //=======================================================================
668 static bool findTriangles(const SMDS_MeshNode * theNode1,
669 const SMDS_MeshNode * theNode2,
670 const SMDS_MeshElement*& theTria1,
671 const SMDS_MeshElement*& theTria2)
673 if ( !theNode1 || !theNode2 ) return false;
675 theTria1 = theTria2 = 0;
677 set< const SMDS_MeshElement* > emap;
678 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
680 const SMDS_MeshElement* elem = it->next();
681 if ( elem->NbNodes() == 3 )
684 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
686 const SMDS_MeshElement* elem = it->next();
687 if ( emap.find( elem ) != emap.end() ) {
689 // theTria1 must be element with minimum ID
690 if( theTria1->GetID() < elem->GetID() ) {
704 return ( theTria1 && theTria2 );
707 //=======================================================================
708 //function : InverseDiag
709 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
710 // with ones built on the same 4 nodes but having other common link.
711 // Return false if proper faces not found
712 //=======================================================================
714 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
715 const SMDS_MeshNode * theNode2)
717 myLastCreatedElems.Clear();
718 myLastCreatedNodes.Clear();
720 MESSAGE( "::InverseDiag()" );
722 const SMDS_MeshElement *tr1, *tr2;
723 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
726 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
727 if (!F1) return false;
728 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
729 if (!F2) return false;
730 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
731 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
733 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
734 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
738 // put nodes in array
739 // and find indices of 1,2 and of A in tr1 and of B in tr2
740 int i, iA1 = 0, i1 = 0;
741 const SMDS_MeshNode* aNodes1 [3];
742 SMDS_ElemIteratorPtr it;
743 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
744 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
745 if ( aNodes1[ i ] == theNode1 )
746 iA1 = i; // node A in tr1
747 else if ( aNodes1[ i ] != theNode2 )
751 const SMDS_MeshNode* aNodes2 [3];
752 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
753 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
754 if ( aNodes2[ i ] == theNode2 )
755 iB2 = i; // node B in tr2
756 else if ( aNodes2[ i ] != theNode1 )
760 // nodes 1 and 2 should not be the same
761 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
765 aNodes1[ iA1 ] = aNodes2[ i2 ];
767 aNodes2[ iB2 ] = aNodes1[ i1 ];
769 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
770 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
775 // check case of quadratic faces
776 return InverseDiag(tr1,tr2);
779 //=======================================================================
780 //function : getQuadrangleNodes
781 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
782 // fusion of triangles tr1 and tr2 having shared link on
783 // theNode1 and theNode2
784 //=======================================================================
786 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
787 const SMDS_MeshNode * theNode1,
788 const SMDS_MeshNode * theNode2,
789 const SMDS_MeshElement * tr1,
790 const SMDS_MeshElement * tr2 )
792 if( tr1->NbNodes() != tr2->NbNodes() )
794 // find the 4-th node to insert into tr1
795 const SMDS_MeshNode* n4 = 0;
796 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
798 while ( !n4 && i<3 ) {
799 const SMDS_MeshNode * n = cast2Node( it->next() );
801 bool isDiag = ( n == theNode1 || n == theNode2 );
805 // Make an array of nodes to be in a quadrangle
806 int iNode = 0, iFirstDiag = -1;
807 it = tr1->nodesIterator();
810 const SMDS_MeshNode * n = cast2Node( it->next() );
812 bool isDiag = ( n == theNode1 || n == theNode2 );
814 if ( iFirstDiag < 0 )
816 else if ( iNode - iFirstDiag == 1 )
817 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
819 else if ( n == n4 ) {
820 return false; // tr1 and tr2 should not have all the same nodes
822 theQuadNodes[ iNode++ ] = n;
824 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
825 theQuadNodes[ iNode ] = n4;
830 //=======================================================================
831 //function : DeleteDiag
832 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
833 // with a quadrangle built on the same 4 nodes.
834 // Return false if proper faces not found
835 //=======================================================================
837 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
838 const SMDS_MeshNode * theNode2)
840 myLastCreatedElems.Clear();
841 myLastCreatedNodes.Clear();
843 MESSAGE( "::DeleteDiag()" );
845 const SMDS_MeshElement *tr1, *tr2;
846 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
849 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
850 if (!F1) return false;
851 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
852 if (!F2) return false;
853 SMESHDS_Mesh * aMesh = GetMeshDS();
855 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
856 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
858 const SMDS_MeshNode* aNodes [ 4 ];
859 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
862 const SMDS_MeshElement* newElem = 0;
863 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
864 myLastCreatedElems.Append(newElem);
865 AddToSameGroups( newElem, tr1, aMesh );
866 int aShapeId = tr1->getshapeId();
869 aMesh->SetMeshElementOnShape( newElem, aShapeId );
871 aMesh->RemoveElement( tr1 );
872 aMesh->RemoveElement( tr2 );
877 // check case of quadratic faces
878 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
880 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
884 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
885 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
893 const SMDS_MeshNode* N1 [6];
894 const SMDS_MeshNode* N2 [6];
895 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
897 // now we receive following N1 and N2 (using numeration as above image)
898 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
899 // i.e. first nodes from both arrays determ new diagonal
901 const SMDS_MeshNode* aNodes[8];
911 const SMDS_MeshElement* newElem = 0;
912 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
913 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
914 myLastCreatedElems.Append(newElem);
915 AddToSameGroups( newElem, tr1, aMesh );
916 int aShapeId = tr1->getshapeId();
919 aMesh->SetMeshElementOnShape( newElem, aShapeId );
921 aMesh->RemoveElement( tr1 );
922 aMesh->RemoveElement( tr2 );
924 // remove middle node (9)
925 GetMeshDS()->RemoveNode( N1[4] );
930 //=======================================================================
931 //function : Reorient
932 //purpose : Reverse theElement orientation
933 //=======================================================================
935 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
938 myLastCreatedElems.Clear();
939 myLastCreatedNodes.Clear();
943 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
944 if ( !it || !it->more() )
947 switch ( theElem->GetType() ) {
951 if(!theElem->IsQuadratic()) {
952 int i = theElem->NbNodes();
953 vector<const SMDS_MeshNode*> aNodes( i );
955 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
956 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
959 // quadratic elements
960 if(theElem->GetType()==SMDSAbs_Edge) {
961 vector<const SMDS_MeshNode*> aNodes(3);
962 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
963 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
964 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
965 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
968 int nbn = theElem->NbNodes();
969 vector<const SMDS_MeshNode*> aNodes(nbn);
970 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
972 for(; i<nbn/2; i++) {
973 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
975 for(i=0; i<nbn/2; i++) {
976 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
978 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
982 case SMDSAbs_Volume: {
983 if (theElem->IsPoly()) {
984 // TODO reorient vtk polyhedron
985 MESSAGE("reorient vtk polyhedron ?");
986 const SMDS_VtkVolume* aPolyedre =
987 dynamic_cast<const SMDS_VtkVolume*>( theElem );
989 MESSAGE("Warning: bad volumic element");
993 int nbFaces = aPolyedre->NbFaces();
994 vector<const SMDS_MeshNode *> poly_nodes;
995 vector<int> quantities (nbFaces);
997 // reverse each face of the polyedre
998 for (int iface = 1; iface <= nbFaces; iface++) {
999 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
1000 quantities[iface - 1] = nbFaceNodes;
1002 for (inode = nbFaceNodes; inode >= 1; inode--) {
1003 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
1004 poly_nodes.push_back(curNode);
1008 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
1012 SMDS_VolumeTool vTool;
1013 if ( !vTool.Set( theElem ))
1016 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
1017 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1026 //=======================================================================
1027 //function : getBadRate
1029 //=======================================================================
1031 static double getBadRate (const SMDS_MeshElement* theElem,
1032 SMESH::Controls::NumericalFunctorPtr& theCrit)
1034 SMESH::Controls::TSequenceOfXYZ P;
1035 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1037 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1038 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1041 //=======================================================================
1042 //function : QuadToTri
1043 //purpose : Cut quadrangles into triangles.
1044 // theCrit is used to select a diagonal to cut
1045 //=======================================================================
1047 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1048 SMESH::Controls::NumericalFunctorPtr theCrit)
1050 myLastCreatedElems.Clear();
1051 myLastCreatedNodes.Clear();
1053 MESSAGE( "::QuadToTri()" );
1055 if ( !theCrit.get() )
1058 SMESHDS_Mesh * aMesh = GetMeshDS();
1060 Handle(Geom_Surface) surface;
1061 SMESH_MesherHelper helper( *GetMesh() );
1063 TIDSortedElemSet::iterator itElem;
1064 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1065 const SMDS_MeshElement* elem = *itElem;
1066 if ( !elem || elem->GetType() != SMDSAbs_Face )
1068 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1071 // retrieve element nodes
1072 const SMDS_MeshNode* aNodes [8];
1073 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1075 while ( itN->more() )
1076 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1078 // compare two sets of possible triangles
1079 double aBadRate1, aBadRate2; // to what extent a set is bad
1080 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1081 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1082 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1084 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1085 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1086 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1088 int aShapeId = FindShape( elem );
1089 const SMDS_MeshElement* newElem1 = 0;
1090 const SMDS_MeshElement* newElem2 = 0;
1092 if( !elem->IsQuadratic() ) {
1094 // split liner quadrangle
1095 if ( aBadRate1 <= aBadRate2 ) {
1096 // tr1 + tr2 is better
1097 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1098 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1101 // tr3 + tr4 is better
1102 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1103 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1108 // split quadratic quadrangle
1110 // get surface elem is on
1111 if ( aShapeId != helper.GetSubShapeID() ) {
1115 shape = aMesh->IndexToShape( aShapeId );
1116 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1117 TopoDS_Face face = TopoDS::Face( shape );
1118 surface = BRep_Tool::Surface( face );
1119 if ( !surface.IsNull() )
1120 helper.SetSubShape( shape );
1124 const SMDS_MeshNode* aNodes [8];
1125 const SMDS_MeshNode* inFaceNode = 0;
1126 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1128 while ( itN->more() ) {
1129 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1130 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1131 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1133 inFaceNode = aNodes[ i-1 ];
1136 // find middle point for (0,1,2,3)
1137 // and create a node in this point;
1139 if ( surface.IsNull() ) {
1141 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1145 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1148 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1150 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1152 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1153 myLastCreatedNodes.Append(newN);
1155 // create a new element
1156 if ( aBadRate1 <= aBadRate2 ) {
1157 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1158 aNodes[6], aNodes[7], newN );
1159 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1160 newN, aNodes[4], aNodes[5] );
1163 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1164 aNodes[7], aNodes[4], newN );
1165 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1166 newN, aNodes[5], aNodes[6] );
1170 // care of a new element
1172 myLastCreatedElems.Append(newElem1);
1173 myLastCreatedElems.Append(newElem2);
1174 AddToSameGroups( newElem1, elem, aMesh );
1175 AddToSameGroups( newElem2, elem, aMesh );
1177 // put a new triangle on the same shape
1180 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1181 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1183 aMesh->RemoveElement( elem );
1188 //=======================================================================
1189 //function : BestSplit
1190 //purpose : Find better diagonal for cutting.
1191 //=======================================================================
1193 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1194 SMESH::Controls::NumericalFunctorPtr theCrit)
1196 myLastCreatedElems.Clear();
1197 myLastCreatedNodes.Clear();
1202 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1205 if( theQuad->NbNodes()==4 ||
1206 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1208 // retrieve element nodes
1209 const SMDS_MeshNode* aNodes [4];
1210 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1212 //while (itN->more())
1214 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1216 // compare two sets of possible triangles
1217 double aBadRate1, aBadRate2; // to what extent a set is bad
1218 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1219 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1220 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1222 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1223 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1224 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1226 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1227 return 1; // diagonal 1-3
1229 return 2; // diagonal 2-4
1236 // Methods of splitting volumes into tetra
1238 const int theHexTo5_1[5*4+1] =
1240 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1242 const int theHexTo5_2[5*4+1] =
1244 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1246 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1248 const int theHexTo6_1[6*4+1] =
1250 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
1252 const int theHexTo6_2[6*4+1] =
1254 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
1256 const int theHexTo6_3[6*4+1] =
1258 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
1260 const int theHexTo6_4[6*4+1] =
1262 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
1264 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1266 const int thePyraTo2_1[2*4+1] =
1268 0, 1, 2, 4, 0, 2, 3, 4, -1
1270 const int thePyraTo2_2[2*4+1] =
1272 1, 2, 3, 4, 1, 3, 0, 4, -1
1274 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1276 const int thePentaTo3_1[3*4+1] =
1278 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1280 const int thePentaTo3_2[3*4+1] =
1282 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1284 const int thePentaTo3_3[3*4+1] =
1286 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1288 const int thePentaTo3_4[3*4+1] =
1290 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1292 const int thePentaTo3_5[3*4+1] =
1294 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1296 const int thePentaTo3_6[3*4+1] =
1298 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1300 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1301 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1303 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1306 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1307 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1308 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1313 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1314 bool _baryNode; //!< additional node is to be created at cell barycenter
1315 bool _ownConn; //!< to delete _connectivity in destructor
1316 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1318 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1319 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1320 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1321 bool hasFacet( const TTriangleFacet& facet ) const
1323 const int* tetConn = _connectivity;
1324 for ( ; tetConn[0] >= 0; tetConn += 4 )
1325 if (( facet.contains( tetConn[0] ) +
1326 facet.contains( tetConn[1] ) +
1327 facet.contains( tetConn[2] ) +
1328 facet.contains( tetConn[3] )) == 3 )
1334 //=======================================================================
1336 * \brief return TSplitMethod for the given element
1338 //=======================================================================
1340 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1342 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1344 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1345 // an edge and a face barycenter; tertaherdons are based on triangles and
1346 // a volume barycenter
1347 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1349 // Find out how adjacent volumes are split
1351 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1352 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1353 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1355 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1356 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1357 if ( nbNodes < 4 ) continue;
1359 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1360 const int* nInd = vol.GetFaceNodesIndices( iF );
1363 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1364 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1365 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1366 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1370 int iCom = 0; // common node of triangle faces to split into
1371 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1373 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1374 nInd[ iQ * ( (iCom+1)%nbNodes )],
1375 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1376 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1377 nInd[ iQ * ( (iCom+2)%nbNodes )],
1378 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1379 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1381 triaSplits.push_back( t012 );
1382 triaSplits.push_back( t023 );
1387 if ( !triaSplits.empty() )
1388 hasAdjacentSplits = true;
1391 // Among variants of split method select one compliant with adjacent volumes
1393 TSplitMethod method;
1394 if ( !vol.Element()->IsPoly() && !is24TetMode )
1396 int nbVariants = 2, nbTet = 0;
1397 const int** connVariants = 0;
1398 switch ( vol.Element()->GetEntityType() )
1400 case SMDSEntity_Hexa:
1401 case SMDSEntity_Quad_Hexa:
1402 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1403 connVariants = theHexTo5, nbTet = 5;
1405 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1407 case SMDSEntity_Pyramid:
1408 case SMDSEntity_Quad_Pyramid:
1409 connVariants = thePyraTo2; nbTet = 2;
1411 case SMDSEntity_Penta:
1412 case SMDSEntity_Quad_Penta:
1413 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1418 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1420 // check method compliancy with adjacent tetras,
1421 // all found splits must be among facets of tetras described by this method
1422 method = TSplitMethod( nbTet, connVariants[variant] );
1423 if ( hasAdjacentSplits && method._nbTetra > 0 )
1425 bool facetCreated = true;
1426 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1428 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1429 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1430 facetCreated = method.hasFacet( *facet );
1432 if ( !facetCreated )
1433 method = TSplitMethod(0); // incompatible method
1437 if ( method._nbTetra < 1 )
1439 // No standard method is applicable, use a generic solution:
1440 // each facet of a volume is split into triangles and
1441 // each of triangles and a volume barycenter form a tetrahedron.
1443 int* connectivity = new int[ maxTetConnSize + 1 ];
1444 method._connectivity = connectivity;
1445 method._ownConn = true;
1446 method._baryNode = true;
1449 int baryCenInd = vol.NbNodes();
1450 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1452 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1453 const int* nInd = vol.GetFaceNodesIndices( iF );
1454 // find common node of triangle facets of tetra to create
1455 int iCommon = 0; // index in linear numeration
1456 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1457 if ( !triaSplits.empty() )
1460 const TTriangleFacet* facet = &triaSplits.front();
1461 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1462 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1463 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1466 else if ( nbNodes > 3 && !is24TetMode )
1468 // find the best method of splitting into triangles by aspect ratio
1469 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1470 map< double, int > badness2iCommon;
1471 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1472 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1473 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1474 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1476 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1477 nodes[ iQ*((iLast-1)%nbNodes)],
1478 nodes[ iQ*((iLast )%nbNodes)]);
1479 double badness = getBadRate( &tria, aspectRatio );
1480 badness2iCommon.insert( make_pair( badness, iCommon ));
1482 // use iCommon with lowest badness
1483 iCommon = badness2iCommon.begin()->second;
1485 if ( iCommon >= nbNodes )
1486 iCommon = 0; // something wrong
1488 // fill connectivity of tetrahedra based on a current face
1489 int nbTet = nbNodes - 2;
1490 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1492 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1493 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1495 for ( int i = 0; i < nbTet; ++i )
1497 int i1 = i, i2 = (i+1) % nbNodes;
1498 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1499 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1500 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1501 connectivity[ connSize++ ] = faceBaryCenInd;
1502 connectivity[ connSize++ ] = baryCenInd;
1507 for ( int i = 0; i < nbTet; ++i )
1509 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1510 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1511 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1512 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1513 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1514 connectivity[ connSize++ ] = baryCenInd;
1517 method._nbTetra += nbTet;
1519 connectivity[ connSize++ ] = -1;
1523 //================================================================================
1525 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1527 //================================================================================
1529 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1531 // find the tetrahedron including the three nodes of facet
1532 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1533 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1534 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1535 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1536 while ( volIt1->more() )
1538 const SMDS_MeshElement* v = volIt1->next();
1539 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1541 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1542 while ( volIt2->more() )
1543 if ( v != volIt2->next() )
1545 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1546 while ( volIt3->more() )
1547 if ( v == volIt3->next() )
1553 //=======================================================================
1555 * \brief A key of a face of volume
1557 //=======================================================================
1559 struct TVolumeFaceKey: pair< int, pair< int, int> >
1561 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1563 TIDSortedNodeSet sortedNodes;
1564 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1565 int nbNodes = vol.NbFaceNodes( iF );
1566 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1567 for ( int i = 0; i < nbNodes; i += iQ )
1568 sortedNodes.insert( fNodes[i] );
1569 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1570 first = (*(n++))->GetID();
1571 second.first = (*(n++))->GetID();
1572 second.second = (*(n++))->GetID();
1577 //=======================================================================
1578 //function : SplitVolumesIntoTetra
1579 //purpose : Split volumic elements into tetrahedra.
1580 //=======================================================================
1582 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1583 const int theMethodFlags)
1585 // std-like iterator on coordinates of nodes of mesh element
1586 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1587 NXyzIterator xyzEnd;
1589 SMDS_VolumeTool volTool;
1590 SMESH_MesherHelper helper( *GetMesh());
1592 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1593 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1595 SMESH_SequenceOfElemPtr newNodes, newElems;
1597 // map face of volume to it's baricenrtic node
1598 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1601 TIDSortedElemSet::const_iterator elem = theElems.begin();
1602 for ( ; elem != theElems.end(); ++elem )
1604 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1605 if ( geomType <= SMDSEntity_Quad_Tetra )
1606 continue; // tetra or face or ...
1608 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1610 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1611 if ( splitMethod._nbTetra < 1 ) continue;
1613 // find submesh to add new tetras to
1614 if ( !subMesh || !subMesh->Contains( *elem ))
1616 int shapeID = FindShape( *elem );
1617 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1618 subMesh = GetMeshDS()->MeshElements( shapeID );
1621 if ( (*elem)->IsQuadratic() )
1624 // add quadratic links to the helper
1625 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1627 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1628 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1629 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1631 helper.SetIsQuadratic( true );
1636 helper.SetIsQuadratic( false );
1638 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1639 helper.SetElementsOnShape( true );
1640 if ( splitMethod._baryNode )
1642 // make a node at barycenter
1643 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1644 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1645 nodes.push_back( gcNode );
1646 newNodes.Append( gcNode );
1648 if ( !splitMethod._faceBaryNode.empty() )
1650 // make or find baricentric nodes of faces
1651 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1652 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1654 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1655 volFace2BaryNode.insert
1656 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1659 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1660 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1662 nodes.push_back( iF_n->second = f_n->second );
1667 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1668 const int* tetConn = splitMethod._connectivity;
1669 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1670 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1671 nodes[ tetConn[1] ],
1672 nodes[ tetConn[2] ],
1673 nodes[ tetConn[3] ]));
1675 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1677 // Split faces on sides of the split volume
1679 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1680 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1682 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1683 if ( nbNodes < 4 ) continue;
1685 // find an existing face
1686 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1687 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1688 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1691 helper.SetElementsOnShape( false );
1692 vector< const SMDS_MeshElement* > triangles;
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 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1701 if ( iF_n != splitMethod._faceBaryNode.end() )
1703 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1705 const SMDS_MeshNode* n1 = fNodes[iN];
1706 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1707 const SMDS_MeshNode *n3 = iF_n->second;
1708 if ( !volTool.IsFaceExternal( iF ))
1710 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1712 if ( fSubMesh && n3->getshapeId() < 1 )
1713 fSubMesh->AddNode( n3 );
1718 // among possible triangles create ones discribed by split method
1719 const int* nInd = volTool.GetFaceNodesIndices( iF );
1720 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1721 int iCom = 0; // common node of triangle faces to split into
1722 list< TTriangleFacet > facets;
1723 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1725 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1726 nInd[ iQ * ( (iCom+1)%nbNodes )],
1727 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1728 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1729 nInd[ iQ * ( (iCom+2)%nbNodes )],
1730 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1731 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1733 facets.push_back( t012 );
1734 facets.push_back( t023 );
1735 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1736 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1737 nInd[ iQ * ((iLast-1)%nbNodes )],
1738 nInd[ iQ * ((iLast )%nbNodes )]));
1742 list< TTriangleFacet >::iterator facet = facets.begin();
1743 for ( ; facet != facets.end(); ++facet )
1745 if ( !volTool.IsFaceExternal( iF ))
1746 swap( facet->_n2, facet->_n3 );
1747 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1748 volNodes[ facet->_n2 ],
1749 volNodes[ facet->_n3 ]));
1752 for ( int i = 0; i < triangles.size(); ++i )
1754 if ( !triangles[i] ) continue;
1756 fSubMesh->AddElement( triangles[i]);
1757 newElems.Append( triangles[i] );
1759 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1760 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1763 } // loop on volume faces to split them into triangles
1765 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1767 } // loop on volumes to split
1769 myLastCreatedNodes = newNodes;
1770 myLastCreatedElems = newElems;
1773 //=======================================================================
1774 //function : AddToSameGroups
1775 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1776 //=======================================================================
1778 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1779 const SMDS_MeshElement* elemInGroups,
1780 SMESHDS_Mesh * aMesh)
1782 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1783 if (!groups.empty()) {
1784 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1785 for ( ; grIt != groups.end(); grIt++ ) {
1786 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1787 if ( group && group->Contains( elemInGroups ))
1788 group->SMDSGroup().Add( elemToAdd );
1794 //=======================================================================
1795 //function : RemoveElemFromGroups
1796 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1797 //=======================================================================
1798 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1799 SMESHDS_Mesh * aMesh)
1801 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1802 if (!groups.empty())
1804 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1805 for (; GrIt != groups.end(); GrIt++)
1807 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1808 if (!grp || grp->IsEmpty()) continue;
1809 grp->SMDSGroup().Remove(removeelem);
1814 //================================================================================
1816 * \brief Replace elemToRm by elemToAdd in the all groups
1818 //================================================================================
1820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1821 const SMDS_MeshElement* elemToAdd,
1822 SMESHDS_Mesh * aMesh)
1824 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825 if (!groups.empty()) {
1826 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1827 for ( ; grIt != groups.end(); grIt++ ) {
1828 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1829 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1830 group->SMDSGroup().Add( elemToAdd );
1835 //================================================================================
1837 * \brief Replace elemToRm by elemToAdd in the all groups
1839 //================================================================================
1841 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1842 const vector<const SMDS_MeshElement*>& elemToAdd,
1843 SMESHDS_Mesh * aMesh)
1845 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1846 if (!groups.empty())
1848 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1849 for ( ; grIt != groups.end(); grIt++ ) {
1850 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1851 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1852 for ( int i = 0; i < elemToAdd.size(); ++i )
1853 group->SMDSGroup().Add( elemToAdd[ i ] );
1858 //=======================================================================
1859 //function : QuadToTri
1860 //purpose : Cut quadrangles into triangles.
1861 // theCrit is used to select a diagonal to cut
1862 //=======================================================================
1864 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1865 const bool the13Diag)
1867 myLastCreatedElems.Clear();
1868 myLastCreatedNodes.Clear();
1870 MESSAGE( "::QuadToTri()" );
1872 SMESHDS_Mesh * aMesh = GetMeshDS();
1874 Handle(Geom_Surface) surface;
1875 SMESH_MesherHelper helper( *GetMesh() );
1877 TIDSortedElemSet::iterator itElem;
1878 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1879 const SMDS_MeshElement* elem = *itElem;
1880 if ( !elem || elem->GetType() != SMDSAbs_Face )
1882 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1883 if(!isquad) continue;
1885 if(elem->NbNodes()==4) {
1886 // retrieve element nodes
1887 const SMDS_MeshNode* aNodes [4];
1888 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1890 while ( itN->more() )
1891 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1893 int aShapeId = FindShape( elem );
1894 const SMDS_MeshElement* newElem1 = 0;
1895 const SMDS_MeshElement* newElem2 = 0;
1897 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1898 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1901 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1902 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1904 myLastCreatedElems.Append(newElem1);
1905 myLastCreatedElems.Append(newElem2);
1906 // put a new triangle on the same shape and add to the same groups
1909 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1910 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1912 AddToSameGroups( newElem1, elem, aMesh );
1913 AddToSameGroups( newElem2, elem, aMesh );
1914 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1915 aMesh->RemoveElement( elem );
1918 // Quadratic quadrangle
1920 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1922 // get surface elem is on
1923 int aShapeId = FindShape( elem );
1924 if ( aShapeId != helper.GetSubShapeID() ) {
1928 shape = aMesh->IndexToShape( aShapeId );
1929 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1930 TopoDS_Face face = TopoDS::Face( shape );
1931 surface = BRep_Tool::Surface( face );
1932 if ( !surface.IsNull() )
1933 helper.SetSubShape( shape );
1937 const SMDS_MeshNode* aNodes [8];
1938 const SMDS_MeshNode* inFaceNode = 0;
1939 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1941 while ( itN->more() ) {
1942 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1943 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1944 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1946 inFaceNode = aNodes[ i-1 ];
1950 // find middle point for (0,1,2,3)
1951 // and create a node in this point;
1953 if ( surface.IsNull() ) {
1955 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1959 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1962 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1964 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1966 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1967 myLastCreatedNodes.Append(newN);
1969 // create a new element
1970 const SMDS_MeshElement* newElem1 = 0;
1971 const SMDS_MeshElement* newElem2 = 0;
1973 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1974 aNodes[6], aNodes[7], newN );
1975 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1976 newN, aNodes[4], aNodes[5] );
1979 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1980 aNodes[7], aNodes[4], newN );
1981 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1982 newN, aNodes[5], aNodes[6] );
1984 myLastCreatedElems.Append(newElem1);
1985 myLastCreatedElems.Append(newElem2);
1986 // put a new triangle on the same shape and add to the same groups
1989 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1990 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1992 AddToSameGroups( newElem1, elem, aMesh );
1993 AddToSameGroups( newElem2, elem, aMesh );
1994 aMesh->RemoveElement( elem );
2001 //=======================================================================
2002 //function : getAngle
2004 //=======================================================================
2006 double getAngle(const SMDS_MeshElement * tr1,
2007 const SMDS_MeshElement * tr2,
2008 const SMDS_MeshNode * n1,
2009 const SMDS_MeshNode * n2)
2011 double angle = 2*PI; // bad angle
2014 SMESH::Controls::TSequenceOfXYZ P1, P2;
2015 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2016 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2019 if(!tr1->IsQuadratic())
2020 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2022 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2023 if ( N1.SquareMagnitude() <= gp::Resolution() )
2025 if(!tr2->IsQuadratic())
2026 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2028 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2029 if ( N2.SquareMagnitude() <= gp::Resolution() )
2032 // find the first diagonal node n1 in the triangles:
2033 // take in account a diagonal link orientation
2034 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2035 for ( int t = 0; t < 2; t++ ) {
2036 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2037 int i = 0, iDiag = -1;
2038 while ( it->more()) {
2039 const SMDS_MeshElement *n = it->next();
2040 if ( n == n1 || n == n2 ) {
2044 if ( i - iDiag == 1 )
2045 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2054 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2057 angle = N1.Angle( N2 );
2062 // =================================================
2063 // class generating a unique ID for a pair of nodes
2064 // and able to return nodes by that ID
2065 // =================================================
2069 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2070 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2073 long GetLinkID (const SMDS_MeshNode * n1,
2074 const SMDS_MeshNode * n2) const
2076 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2079 bool GetNodes (const long theLinkID,
2080 const SMDS_MeshNode* & theNode1,
2081 const SMDS_MeshNode* & theNode2) const
2083 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2084 if ( !theNode1 ) return false;
2085 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2086 if ( !theNode2 ) return false;
2092 const SMESHDS_Mesh* myMesh;
2097 //=======================================================================
2098 //function : TriToQuad
2099 //purpose : Fuse neighbour triangles into quadrangles.
2100 // theCrit is used to select a neighbour to fuse with.
2101 // theMaxAngle is a max angle between element normals at which
2102 // fusion is still performed.
2103 //=======================================================================
2105 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2106 SMESH::Controls::NumericalFunctorPtr theCrit,
2107 const double theMaxAngle)
2109 myLastCreatedElems.Clear();
2110 myLastCreatedNodes.Clear();
2112 MESSAGE( "::TriToQuad()" );
2114 if ( !theCrit.get() )
2117 SMESHDS_Mesh * aMesh = GetMeshDS();
2119 // Prepare data for algo: build
2120 // 1. map of elements with their linkIDs
2121 // 2. map of linkIDs with their elements
2123 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2124 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2125 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2126 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2128 TIDSortedElemSet::iterator itElem;
2129 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2130 const SMDS_MeshElement* elem = *itElem;
2131 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2132 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2133 if(!IsTria) continue;
2135 // retrieve element nodes
2136 const SMDS_MeshNode* aNodes [4];
2137 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2140 aNodes[ i++ ] = cast2Node( itN->next() );
2141 aNodes[ 3 ] = aNodes[ 0 ];
2144 for ( i = 0; i < 3; i++ ) {
2145 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2146 // check if elements sharing a link can be fused
2147 itLE = mapLi_listEl.find( link );
2148 if ( itLE != mapLi_listEl.end() ) {
2149 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2151 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2152 //if ( FindShape( elem ) != FindShape( elem2 ))
2153 // continue; // do not fuse triangles laying on different shapes
2154 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2155 continue; // avoid making badly shaped quads
2156 (*itLE).second.push_back( elem );
2159 mapLi_listEl[ link ].push_back( elem );
2161 mapEl_setLi [ elem ].insert( link );
2164 // Clean the maps from the links shared by a sole element, ie
2165 // links to which only one element is bound in mapLi_listEl
2167 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2168 int nbElems = (*itLE).second.size();
2169 if ( nbElems < 2 ) {
2170 const SMDS_MeshElement* elem = (*itLE).second.front();
2171 SMESH_TLink link = (*itLE).first;
2172 mapEl_setLi[ elem ].erase( link );
2173 if ( mapEl_setLi[ elem ].empty() )
2174 mapEl_setLi.erase( elem );
2178 // Algo: fuse triangles into quadrangles
2180 while ( ! mapEl_setLi.empty() ) {
2181 // Look for the start element:
2182 // the element having the least nb of shared links
2183 const SMDS_MeshElement* startElem = 0;
2185 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2186 int nbLinks = (*itEL).second.size();
2187 if ( nbLinks < minNbLinks ) {
2188 startElem = (*itEL).first;
2189 minNbLinks = nbLinks;
2190 if ( minNbLinks == 1 )
2195 // search elements to fuse starting from startElem or links of elements
2196 // fused earlyer - startLinks
2197 list< SMESH_TLink > startLinks;
2198 while ( startElem || !startLinks.empty() ) {
2199 while ( !startElem && !startLinks.empty() ) {
2200 // Get an element to start, by a link
2201 SMESH_TLink linkId = startLinks.front();
2202 startLinks.pop_front();
2203 itLE = mapLi_listEl.find( linkId );
2204 if ( itLE != mapLi_listEl.end() ) {
2205 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2206 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2207 for ( ; itE != listElem.end() ; itE++ )
2208 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2210 mapLi_listEl.erase( itLE );
2215 // Get candidates to be fused
2216 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2217 const SMESH_TLink *link12, *link13;
2219 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2220 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2221 ASSERT( !setLi.empty() );
2222 set< SMESH_TLink >::iterator itLi;
2223 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2225 const SMESH_TLink & link = (*itLi);
2226 itLE = mapLi_listEl.find( link );
2227 if ( itLE == mapLi_listEl.end() )
2230 const SMDS_MeshElement* elem = (*itLE).second.front();
2232 elem = (*itLE).second.back();
2233 mapLi_listEl.erase( itLE );
2234 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2245 // add other links of elem to list of links to re-start from
2246 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2247 set< SMESH_TLink >::iterator it;
2248 for ( it = links.begin(); it != links.end(); it++ ) {
2249 const SMESH_TLink& link2 = (*it);
2250 if ( link2 != link )
2251 startLinks.push_back( link2 );
2255 // Get nodes of possible quadrangles
2256 const SMDS_MeshNode *n12 [4], *n13 [4];
2257 bool Ok12 = false, Ok13 = false;
2258 const SMDS_MeshNode *linkNode1, *linkNode2;
2260 linkNode1 = link12->first;
2261 linkNode2 = link12->second;
2262 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2266 linkNode1 = link13->first;
2267 linkNode2 = link13->second;
2268 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2272 // Choose a pair to fuse
2273 if ( Ok12 && Ok13 ) {
2274 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2275 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2276 double aBadRate12 = getBadRate( &quad12, theCrit );
2277 double aBadRate13 = getBadRate( &quad13, theCrit );
2278 if ( aBadRate13 < aBadRate12 )
2285 // and remove fused elems and removed links from the maps
2286 mapEl_setLi.erase( tr1 );
2288 mapEl_setLi.erase( tr2 );
2289 mapLi_listEl.erase( *link12 );
2290 if(tr1->NbNodes()==3) {
2291 const SMDS_MeshElement* newElem = 0;
2292 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2293 myLastCreatedElems.Append(newElem);
2294 AddToSameGroups( newElem, tr1, aMesh );
2295 int aShapeId = tr1->getshapeId();
2298 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2300 aMesh->RemoveElement( tr1 );
2301 aMesh->RemoveElement( tr2 );
2304 const SMDS_MeshNode* N1 [6];
2305 const SMDS_MeshNode* N2 [6];
2306 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2307 // now we receive following N1 and N2 (using numeration as above image)
2308 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2309 // i.e. first nodes from both arrays determ new diagonal
2310 const SMDS_MeshNode* aNodes[8];
2319 const SMDS_MeshElement* newElem = 0;
2320 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2321 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2322 myLastCreatedElems.Append(newElem);
2323 AddToSameGroups( newElem, tr1, aMesh );
2324 int aShapeId = tr1->getshapeId();
2327 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2329 aMesh->RemoveElement( tr1 );
2330 aMesh->RemoveElement( tr2 );
2331 // remove middle node (9)
2332 GetMeshDS()->RemoveNode( N1[4] );
2336 mapEl_setLi.erase( tr3 );
2337 mapLi_listEl.erase( *link13 );
2338 if(tr1->NbNodes()==3) {
2339 const SMDS_MeshElement* newElem = 0;
2340 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2341 myLastCreatedElems.Append(newElem);
2342 AddToSameGroups( newElem, tr1, aMesh );
2343 int aShapeId = tr1->getshapeId();
2346 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2348 aMesh->RemoveElement( tr1 );
2349 aMesh->RemoveElement( tr3 );
2352 const SMDS_MeshNode* N1 [6];
2353 const SMDS_MeshNode* N2 [6];
2354 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2355 // now we receive following N1 and N2 (using numeration as above image)
2356 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2357 // i.e. first nodes from both arrays determ new diagonal
2358 const SMDS_MeshNode* aNodes[8];
2367 const SMDS_MeshElement* newElem = 0;
2368 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2369 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2370 myLastCreatedElems.Append(newElem);
2371 AddToSameGroups( newElem, tr1, aMesh );
2372 int aShapeId = tr1->getshapeId();
2375 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2377 aMesh->RemoveElement( tr1 );
2378 aMesh->RemoveElement( tr3 );
2379 // remove middle node (9)
2380 GetMeshDS()->RemoveNode( N1[4] );
2384 // Next element to fuse: the rejected one
2386 startElem = Ok12 ? tr3 : tr2;
2388 } // if ( startElem )
2389 } // while ( startElem || !startLinks.empty() )
2390 } // while ( ! mapEl_setLi.empty() )
2396 /*#define DUMPSO(txt) \
2397 // cout << txt << endl;
2398 //=============================================================================
2402 //=============================================================================
2403 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2407 int tmp = idNodes[ i1 ];
2408 idNodes[ i1 ] = idNodes[ i2 ];
2409 idNodes[ i2 ] = tmp;
2410 gp_Pnt Ptmp = P[ i1 ];
2413 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2416 //=======================================================================
2417 //function : SortQuadNodes
2418 //purpose : Set 4 nodes of a quadrangle face in a good order.
2419 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2421 //=======================================================================
2423 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2428 for ( i = 0; i < 4; i++ ) {
2429 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2431 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2434 gp_Vec V1(P[0], P[1]);
2435 gp_Vec V2(P[0], P[2]);
2436 gp_Vec V3(P[0], P[3]);
2438 gp_Vec Cross1 = V1 ^ V2;
2439 gp_Vec Cross2 = V2 ^ V3;
2442 if (Cross1.Dot(Cross2) < 0)
2447 if (Cross1.Dot(Cross2) < 0)
2451 swap ( i, i + 1, idNodes, P );
2453 // for ( int ii = 0; ii < 4; ii++ ) {
2454 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2455 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2461 //=======================================================================
2462 //function : SortHexaNodes
2463 //purpose : Set 8 nodes of a hexahedron in a good order.
2464 // Return success status
2465 //=======================================================================
2467 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2472 DUMPSO( "INPUT: ========================================");
2473 for ( i = 0; i < 8; i++ ) {
2474 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2475 if ( !n ) return false;
2476 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2477 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2479 DUMPSO( "========================================");
2482 set<int> faceNodes; // ids of bottom face nodes, to be found
2483 set<int> checkedId1; // ids of tried 2-nd nodes
2484 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2485 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2486 int iMin, iLoop1 = 0;
2488 // Loop to try the 2-nd nodes
2490 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2492 // Find not checked 2-nd node
2493 for ( i = 1; i < 8; i++ )
2494 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2495 int id1 = idNodes[i];
2496 swap ( 1, i, idNodes, P );
2497 checkedId1.insert ( id1 );
2501 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2502 // ie that all but meybe one (id3 which is on the same face) nodes
2503 // lay on the same side from the triangle plane.
2505 bool manyInPlane = false; // more than 4 nodes lay in plane
2507 while ( ++iLoop2 < 6 ) {
2509 // get 1-2-3 plane coeffs
2510 Standard_Real A, B, C, D;
2511 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2512 if ( N.SquareMagnitude() > gp::Resolution() )
2514 gp_Pln pln ( P[0], N );
2515 pln.Coefficients( A, B, C, D );
2517 // find the node (iMin) closest to pln
2518 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2520 for ( i = 3; i < 8; i++ ) {
2521 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2522 if ( fabs( dist[i] ) < minDist ) {
2523 minDist = fabs( dist[i] );
2526 if ( fabs( dist[i] ) <= tol )
2527 idInPln.insert( idNodes[i] );
2530 // there should not be more than 4 nodes in bottom plane
2531 if ( idInPln.size() > 1 )
2533 DUMPSO( "### idInPln.size() = " << idInPln.size());
2534 // idInPlane does not contain the first 3 nodes
2535 if ( manyInPlane || idInPln.size() == 5)
2536 return false; // all nodes in one plane
2539 // set the 1-st node to be not in plane
2540 for ( i = 3; i < 8; i++ ) {
2541 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2542 DUMPSO( "### Reset 0-th node");
2543 swap( 0, i, idNodes, P );
2548 // reset to re-check second nodes
2549 leastDist = DBL_MAX;
2553 break; // from iLoop2;
2556 // check that the other 4 nodes are on the same side
2557 bool sameSide = true;
2558 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2559 for ( i = 3; sameSide && i < 8; i++ ) {
2561 sameSide = ( isNeg == dist[i] <= 0.);
2564 // keep best solution
2565 if ( sameSide && minDist < leastDist ) {
2566 leastDist = minDist;
2568 faceNodes.insert( idNodes[ 1 ] );
2569 faceNodes.insert( idNodes[ 2 ] );
2570 faceNodes.insert( idNodes[ iMin ] );
2571 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2572 << " leastDist = " << leastDist);
2573 if ( leastDist <= DBL_MIN )
2578 // set next 3-d node to check
2579 int iNext = 2 + iLoop2;
2581 DUMPSO( "Try 2-nd");
2582 swap ( 2, iNext, idNodes, P );
2584 } // while ( iLoop2 < 6 )
2587 if ( faceNodes.empty() ) return false;
2589 // Put the faceNodes in proper places
2590 for ( i = 4; i < 8; i++ ) {
2591 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2592 // find a place to put
2594 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2596 DUMPSO( "Set faceNodes");
2597 swap ( iTo, i, idNodes, P );
2602 // Set nodes of the found bottom face in good order
2603 DUMPSO( " Found bottom face: ");
2604 i = SortQuadNodes( theMesh, idNodes );
2606 gp_Pnt Ptmp = P[ i ];
2611 // for ( int ii = 0; ii < 4; ii++ ) {
2612 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2613 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2616 // Gravity center of the top and bottom faces
2617 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2618 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2620 // Get direction from the bottom to the top face
2621 gp_Vec upDir ( aGCb, aGCt );
2622 Standard_Real upDirSize = upDir.Magnitude();
2623 if ( upDirSize <= gp::Resolution() ) return false;
2626 // Assure that the bottom face normal points up
2627 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2628 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2629 if ( Nb.Dot( upDir ) < 0 ) {
2630 DUMPSO( "Reverse bottom face");
2631 swap( 1, 3, idNodes, P );
2634 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2635 Standard_Real minDist = DBL_MAX;
2636 for ( i = 4; i < 8; i++ ) {
2637 // projection of P[i] to the plane defined by P[0] and upDir
2638 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2639 Standard_Real sqDist = P[0].SquareDistance( Pp );
2640 if ( sqDist < minDist ) {
2645 DUMPSO( "Set 4-th");
2646 swap ( 4, iMin, idNodes, P );
2648 // Set nodes of the top face in good order
2649 DUMPSO( "Sort top face");
2650 i = SortQuadNodes( theMesh, &idNodes[4] );
2653 gp_Pnt Ptmp = P[ i ];
2658 // Assure that direction of the top face normal is from the bottom face
2659 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2660 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2661 if ( Nt.Dot( upDir ) < 0 ) {
2662 DUMPSO( "Reverse top face");
2663 swap( 5, 7, idNodes, P );
2666 // DUMPSO( "OUTPUT: ========================================");
2667 // for ( i = 0; i < 8; i++ ) {
2668 // float *p = ugrid->GetPoint(idNodes[i]);
2669 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2675 //================================================================================
2677 * \brief Return nodes linked to the given one
2678 * \param theNode - the node
2679 * \param linkedNodes - the found nodes
2680 * \param type - the type of elements to check
2682 * Medium nodes are ignored
2684 //================================================================================
2686 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2687 TIDSortedElemSet & linkedNodes,
2688 SMDSAbs_ElementType type )
2690 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2691 while ( elemIt->more() )
2693 const SMDS_MeshElement* elem = elemIt->next();
2694 if(elem->GetType() == SMDSAbs_0DElement)
2697 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2698 if ( elem->GetType() == SMDSAbs_Volume )
2700 SMDS_VolumeTool vol( elem );
2701 while ( nodeIt->more() ) {
2702 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2703 if ( theNode != n && vol.IsLinked( theNode, n ))
2704 linkedNodes.insert( n );
2709 for ( int i = 0; nodeIt->more(); ++i ) {
2710 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2711 if ( n == theNode ) {
2712 int iBefore = i - 1;
2714 if ( elem->IsQuadratic() ) {
2715 int nb = elem->NbNodes() / 2;
2716 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2717 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2719 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2720 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2727 //=======================================================================
2728 //function : laplacianSmooth
2729 //purpose : pulls theNode toward the center of surrounding nodes directly
2730 // connected to that node along an element edge
2731 //=======================================================================
2733 void laplacianSmooth(const SMDS_MeshNode* theNode,
2734 const Handle(Geom_Surface)& theSurface,
2735 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2737 // find surrounding nodes
2739 TIDSortedElemSet nodeSet;
2740 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2742 // compute new coodrs
2744 double coord[] = { 0., 0., 0. };
2745 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2746 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2747 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2748 if ( theSurface.IsNull() ) { // smooth in 3D
2749 coord[0] += node->X();
2750 coord[1] += node->Y();
2751 coord[2] += node->Z();
2753 else { // smooth in 2D
2754 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2755 gp_XY* uv = theUVMap[ node ];
2756 coord[0] += uv->X();
2757 coord[1] += uv->Y();
2760 int nbNodes = nodeSet.size();
2763 coord[0] /= nbNodes;
2764 coord[1] /= nbNodes;
2766 if ( !theSurface.IsNull() ) {
2767 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2768 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2769 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2775 coord[2] /= nbNodes;
2779 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2782 //=======================================================================
2783 //function : centroidalSmooth
2784 //purpose : pulls theNode toward the element-area-weighted centroid of the
2785 // surrounding elements
2786 //=======================================================================
2788 void centroidalSmooth(const SMDS_MeshNode* theNode,
2789 const Handle(Geom_Surface)& theSurface,
2790 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2792 gp_XYZ aNewXYZ(0.,0.,0.);
2793 SMESH::Controls::Area anAreaFunc;
2794 double totalArea = 0.;
2799 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2800 while ( elemIt->more() )
2802 const SMDS_MeshElement* elem = elemIt->next();
2805 gp_XYZ elemCenter(0.,0.,0.);
2806 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2807 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2808 int nn = elem->NbNodes();
2809 if(elem->IsQuadratic()) nn = nn/2;
2811 //while ( itN->more() ) {
2813 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2815 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2816 aNodePoints.push_back( aP );
2817 if ( !theSurface.IsNull() ) { // smooth in 2D
2818 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2819 gp_XY* uv = theUVMap[ aNode ];
2820 aP.SetCoord( uv->X(), uv->Y(), 0. );
2824 double elemArea = anAreaFunc.GetValue( aNodePoints );
2825 totalArea += elemArea;
2827 aNewXYZ += elemCenter * elemArea;
2829 aNewXYZ /= totalArea;
2830 if ( !theSurface.IsNull() ) {
2831 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2832 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2837 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2840 //=======================================================================
2841 //function : getClosestUV
2842 //purpose : return UV of closest projection
2843 //=======================================================================
2845 static bool getClosestUV (Extrema_GenExtPS& projector,
2846 const gp_Pnt& point,
2849 projector.Perform( point );
2850 if ( projector.IsDone() ) {
2851 double u, v, minVal = DBL_MAX;
2852 for ( int i = projector.NbExt(); i > 0; i-- )
2853 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
2854 if ( projector.SquareDistance( i ) < minVal ) {
2855 minVal = projector.SquareDistance( i );
2857 if ( projector.Value( i ) < minVal ) {
2858 minVal = projector.Value( i );
2860 projector.Point( i ).Parameter( u, v );
2862 result.SetCoord( u, v );
2868 //=======================================================================
2870 //purpose : Smooth theElements during theNbIterations or until a worst
2871 // element has aspect ratio <= theTgtAspectRatio.
2872 // Aspect Ratio varies in range [1.0, inf].
2873 // If theElements is empty, the whole mesh is smoothed.
2874 // theFixedNodes contains additionally fixed nodes. Nodes built
2875 // on edges and boundary nodes are always fixed.
2876 //=======================================================================
2878 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2879 set<const SMDS_MeshNode*> & theFixedNodes,
2880 const SmoothMethod theSmoothMethod,
2881 const int theNbIterations,
2882 double theTgtAspectRatio,
2885 myLastCreatedElems.Clear();
2886 myLastCreatedNodes.Clear();
2888 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2890 if ( theTgtAspectRatio < 1.0 )
2891 theTgtAspectRatio = 1.0;
2893 const double disttol = 1.e-16;
2895 SMESH::Controls::AspectRatio aQualityFunc;
2897 SMESHDS_Mesh* aMesh = GetMeshDS();
2899 if ( theElems.empty() ) {
2900 // add all faces to theElems
2901 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2902 while ( fIt->more() ) {
2903 const SMDS_MeshElement* face = fIt->next();
2904 theElems.insert( face );
2907 // get all face ids theElems are on
2908 set< int > faceIdSet;
2909 TIDSortedElemSet::iterator itElem;
2911 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2912 int fId = FindShape( *itElem );
2913 // check that corresponding submesh exists and a shape is face
2915 faceIdSet.find( fId ) == faceIdSet.end() &&
2916 aMesh->MeshElements( fId )) {
2917 TopoDS_Shape F = aMesh->IndexToShape( fId );
2918 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2919 faceIdSet.insert( fId );
2922 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2924 // ===============================================
2925 // smooth elements on each TopoDS_Face separately
2926 // ===============================================
2928 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2929 for ( ; fId != faceIdSet.rend(); ++fId ) {
2930 // get face surface and submesh
2931 Handle(Geom_Surface) surface;
2932 SMESHDS_SubMesh* faceSubMesh = 0;
2934 double fToler2 = 0, f,l;
2935 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2936 bool isUPeriodic = false, isVPeriodic = false;
2938 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2939 surface = BRep_Tool::Surface( face );
2940 faceSubMesh = aMesh->MeshElements( *fId );
2941 fToler2 = BRep_Tool::Tolerance( face );
2942 fToler2 *= fToler2 * 10.;
2943 isUPeriodic = surface->IsUPeriodic();
2946 isVPeriodic = surface->IsVPeriodic();
2949 surface->Bounds( u1, u2, v1, v2 );
2951 // ---------------------------------------------------------
2952 // for elements on a face, find movable and fixed nodes and
2953 // compute UV for them
2954 // ---------------------------------------------------------
2955 bool checkBoundaryNodes = false;
2956 bool isQuadratic = false;
2957 set<const SMDS_MeshNode*> setMovableNodes;
2958 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2959 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2960 list< const SMDS_MeshElement* > elemsOnFace;
2962 Extrema_GenExtPS projector;
2963 GeomAdaptor_Surface surfAdaptor;
2964 if ( !surface.IsNull() ) {
2965 surfAdaptor.Load( surface );
2966 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2968 int nbElemOnFace = 0;
2969 itElem = theElems.begin();
2970 // loop on not yet smoothed elements: look for elems on a face
2971 while ( itElem != theElems.end() ) {
2972 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2973 break; // all elements found
2975 const SMDS_MeshElement* elem = *itElem;
2976 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2977 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2981 elemsOnFace.push_back( elem );
2982 theElems.erase( itElem++ );
2986 isQuadratic = elem->IsQuadratic();
2988 // get movable nodes of elem
2989 const SMDS_MeshNode* node;
2990 SMDS_TypeOfPosition posType;
2991 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2992 int nn = 0, nbn = elem->NbNodes();
2993 if(elem->IsQuadratic())
2995 while ( nn++ < nbn ) {
2996 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2997 const SMDS_PositionPtr& pos = node->GetPosition();
2998 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2999 if (posType != SMDS_TOP_EDGE &&
3000 posType != SMDS_TOP_VERTEX &&
3001 theFixedNodes.find( node ) == theFixedNodes.end())
3003 // check if all faces around the node are on faceSubMesh
3004 // because a node on edge may be bound to face
3005 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3007 if ( faceSubMesh ) {
3008 while ( eIt->more() && all ) {
3009 const SMDS_MeshElement* e = eIt->next();
3010 all = faceSubMesh->Contains( e );
3014 setMovableNodes.insert( node );
3016 checkBoundaryNodes = true;
3018 if ( posType == SMDS_TOP_3DSPACE )
3019 checkBoundaryNodes = true;
3022 if ( surface.IsNull() )
3025 // get nodes to check UV
3026 list< const SMDS_MeshNode* > uvCheckNodes;
3027 itN = elem->nodesIterator();
3028 nn = 0; nbn = elem->NbNodes();
3029 if(elem->IsQuadratic())
3031 while ( nn++ < nbn ) {
3032 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3033 if ( uvMap.find( node ) == uvMap.end() )
3034 uvCheckNodes.push_back( node );
3035 // add nodes of elems sharing node
3036 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3037 // while ( eIt->more() ) {
3038 // const SMDS_MeshElement* e = eIt->next();
3039 // if ( e != elem ) {
3040 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3041 // while ( nIt->more() ) {
3042 // const SMDS_MeshNode* n =
3043 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3044 // if ( uvMap.find( n ) == uvMap.end() )
3045 // uvCheckNodes.push_back( n );
3051 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3052 for ( ; n != uvCheckNodes.end(); ++n ) {
3055 const SMDS_PositionPtr& pos = node->GetPosition();
3056 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3058 switch ( posType ) {
3059 case SMDS_TOP_FACE: {
3060 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3061 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3064 case SMDS_TOP_EDGE: {
3065 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3066 Handle(Geom2d_Curve) pcurve;
3067 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3068 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3069 if ( !pcurve.IsNull() ) {
3070 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3071 uv = pcurve->Value( u ).XY();
3075 case SMDS_TOP_VERTEX: {
3076 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3077 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3078 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3083 // check existing UV
3084 bool project = true;
3085 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3086 double dist1 = DBL_MAX, dist2 = 0;
3087 if ( posType != SMDS_TOP_3DSPACE ) {
3088 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3089 project = dist1 > fToler2;
3091 if ( project ) { // compute new UV
3093 if ( !getClosestUV( projector, pNode, newUV )) {
3094 MESSAGE("Node Projection Failed " << node);
3098 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3100 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3102 if ( posType != SMDS_TOP_3DSPACE )
3103 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3104 if ( dist2 < dist1 )
3108 // store UV in the map
3109 listUV.push_back( uv );
3110 uvMap.insert( make_pair( node, &listUV.back() ));
3112 } // loop on not yet smoothed elements
3114 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3115 checkBoundaryNodes = true;
3117 // fix nodes on mesh boundary
3119 if ( checkBoundaryNodes ) {
3120 map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3121 map< SMESH_TLink, int >::iterator link_nb;
3122 // put all elements links to linkNbMap
3123 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3124 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3125 const SMDS_MeshElement* elem = (*elemIt);
3126 int nbn = elem->NbCornerNodes();
3127 // loop on elem links: insert them in linkNbMap
3128 for ( int iN = 0; iN < nbn; ++iN ) {
3129 const SMDS_MeshNode* n1 = elem->GetNode( iN );
3130 const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
3131 SMESH_TLink link( n1, n2 );
3132 link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
3136 // remove nodes that are in links encountered only once from setMovableNodes
3137 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3138 if ( link_nb->second == 1 ) {
3139 setMovableNodes.erase( link_nb->first.node1() );
3140 setMovableNodes.erase( link_nb->first.node2() );
3145 // -----------------------------------------------------
3146 // for nodes on seam edge, compute one more UV ( uvMap2 );
3147 // find movable nodes linked to nodes on seam and which
3148 // are to be smoothed using the second UV ( uvMap2 )
3149 // -----------------------------------------------------
3151 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3152 if ( !surface.IsNull() ) {
3153 TopExp_Explorer eExp( face, TopAbs_EDGE );
3154 for ( ; eExp.More(); eExp.Next() ) {
3155 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3156 if ( !BRep_Tool::IsClosed( edge, face ))
3158 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3159 if ( !sm ) continue;
3160 // find out which parameter varies for a node on seam
3163 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3164 if ( pcurve.IsNull() ) continue;
3165 uv1 = pcurve->Value( f );
3167 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3168 if ( pcurve.IsNull() ) continue;
3169 uv2 = pcurve->Value( f );
3170 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3172 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3173 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3175 // get nodes on seam and its vertices
3176 list< const SMDS_MeshNode* > seamNodes;
3177 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3178 while ( nSeamIt->more() ) {
3179 const SMDS_MeshNode* node = nSeamIt->next();
3180 if ( !isQuadratic || !IsMedium( node ))
3181 seamNodes.push_back( node );
3183 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3184 for ( ; vExp.More(); vExp.Next() ) {
3185 sm = aMesh->MeshElements( vExp.Current() );
3187 nSeamIt = sm->GetNodes();
3188 while ( nSeamIt->more() )
3189 seamNodes.push_back( nSeamIt->next() );
3192 // loop on nodes on seam
3193 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3194 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3195 const SMDS_MeshNode* nSeam = *noSeIt;
3196 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3197 if ( n_uv == uvMap.end() )
3200 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3201 // set the second UV
3202 listUV.push_back( *n_uv->second );
3203 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3204 if ( uvMap2.empty() )
3205 uvMap2 = uvMap; // copy the uvMap contents
3206 uvMap2[ nSeam ] = &listUV.back();
3208 // collect movable nodes linked to ones on seam in nodesNearSeam
3209 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3210 while ( eIt->more() ) {
3211 const SMDS_MeshElement* e = eIt->next();
3212 int nbUseMap1 = 0, nbUseMap2 = 0;
3213 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3214 int nn = 0, nbn = e->NbNodes();
3215 if(e->IsQuadratic()) nbn = nbn/2;
3216 while ( nn++ < nbn )
3218 const SMDS_MeshNode* n =
3219 static_cast<const SMDS_MeshNode*>( nIt->next() );
3221 setMovableNodes.find( n ) == setMovableNodes.end() )
3223 // add only nodes being closer to uv2 than to uv1
3224 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3225 0.5 * ( n->Y() + nSeam->Y() ),
3226 0.5 * ( n->Z() + nSeam->Z() ));
3228 getClosestUV( projector, pMid, uv );
3229 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3230 nodesNearSeam.insert( n );
3236 // for centroidalSmooth all element nodes must
3237 // be on one side of a seam
3238 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3239 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3241 while ( nn++ < nbn ) {
3242 const SMDS_MeshNode* n =
3243 static_cast<const SMDS_MeshNode*>( nIt->next() );
3244 setMovableNodes.erase( n );
3248 } // loop on nodes on seam
3249 } // loop on edge of a face
3250 } // if ( !face.IsNull() )
3252 if ( setMovableNodes.empty() ) {
3253 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3254 continue; // goto next face
3262 double maxRatio = -1., maxDisplacement = -1.;
3263 set<const SMDS_MeshNode*>::iterator nodeToMove;
3264 for ( it = 0; it < theNbIterations; it++ ) {
3265 maxDisplacement = 0.;
3266 nodeToMove = setMovableNodes.begin();
3267 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3268 const SMDS_MeshNode* node = (*nodeToMove);
3269 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3272 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3273 if ( theSmoothMethod == LAPLACIAN )
3274 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3276 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3278 // node displacement
3279 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3280 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3281 if ( aDispl > maxDisplacement )
3282 maxDisplacement = aDispl;
3284 // no node movement => exit
3285 //if ( maxDisplacement < 1.e-16 ) {
3286 if ( maxDisplacement < disttol ) {
3287 MESSAGE("-- no node movement --");
3291 // check elements quality
3293 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3294 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3295 const SMDS_MeshElement* elem = (*elemIt);
3296 if ( !elem || elem->GetType() != SMDSAbs_Face )
3298 SMESH::Controls::TSequenceOfXYZ aPoints;
3299 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3300 double aValue = aQualityFunc.GetValue( aPoints );
3301 if ( aValue > maxRatio )
3305 if ( maxRatio <= theTgtAspectRatio ) {
3306 MESSAGE("-- quality achived --");
3309 if (it+1 == theNbIterations) {
3310 MESSAGE("-- Iteration limit exceeded --");
3312 } // smoothing iterations
3314 MESSAGE(" Face id: " << *fId <<
3315 " Nb iterstions: " << it <<
3316 " Displacement: " << maxDisplacement <<
3317 " Aspect Ratio " << maxRatio);
3319 // ---------------------------------------
3320 // new nodes positions are computed,
3321 // record movement in DS and set new UV
3322 // ---------------------------------------
3323 nodeToMove = setMovableNodes.begin();
3324 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3325 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3326 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3327 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3328 if ( node_uv != uvMap.end() ) {
3329 gp_XY* uv = node_uv->second;
3331 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3335 // move medium nodes of quadratic elements
3338 SMESH_MesherHelper helper( *GetMesh() );
3339 if ( !face.IsNull() )
3340 helper.SetSubShape( face );
3341 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3342 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3343 const SMDS_VtkFace* QF =
3344 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3345 if(QF && QF->IsQuadratic()) {
3346 vector<const SMDS_MeshNode*> Ns;
3347 Ns.reserve(QF->NbNodes()+1);
3348 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3349 while ( anIter->more() )
3350 Ns.push_back( cast2Node(anIter->next()) );
3351 Ns.push_back( Ns[0] );
3353 for(int i=0; i<QF->NbNodes(); i=i+2) {
3354 if ( !surface.IsNull() ) {
3355 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3356 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3357 gp_XY uv = ( uv1 + uv2 ) / 2.;
3358 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3359 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3362 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3363 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3364 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3366 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3367 fabs( Ns[i+1]->Y() - y ) > disttol ||
3368 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3369 // we have to move i+1 node
3370 aMesh->MoveNode( Ns[i+1], x, y, z );
3377 } // loop on face ids
3381 //=======================================================================
3382 //function : isReverse
3383 //purpose : Return true if normal of prevNodes is not co-directied with
3384 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3385 // iNotSame is where prevNodes and nextNodes are different
3386 //=======================================================================
3388 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3389 vector<const SMDS_MeshNode*> nextNodes,
3393 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3394 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3396 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3397 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3398 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3399 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3401 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3402 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3403 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3404 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3406 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3408 return (vA ^ vB) * vN < 0.0;
3411 //=======================================================================
3413 * \brief Create elements by sweeping an element
3414 * \param elem - element to sweep
3415 * \param newNodesItVec - nodes generated from each node of the element
3416 * \param newElems - generated elements
3417 * \param nbSteps - number of sweeping steps
3418 * \param srcElements - to append elem for each generated element
3420 //=======================================================================
3422 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3423 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3424 list<const SMDS_MeshElement*>& newElems,
3426 SMESH_SequenceOfElemPtr& srcElements)
3428 //MESSAGE("sweepElement " << nbSteps);
3429 SMESHDS_Mesh* aMesh = GetMeshDS();
3431 // Loop on elem nodes:
3432 // find new nodes and detect same nodes indices
3433 int nbNodes = elem->NbNodes();
3434 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3435 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3436 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3437 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3439 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3440 vector<int> sames(nbNodes);
3441 vector<bool> issimple(nbNodes);
3443 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3444 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3445 const SMDS_MeshNode* node = nnIt->first;
3446 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3447 if ( listNewNodes.empty() ) {
3451 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3453 itNN[ iNode ] = listNewNodes.begin();
3454 prevNod[ iNode ] = node;
3455 nextNod[ iNode ] = listNewNodes.front();
3456 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3457 if ( prevNod[ iNode ] != nextNod [ iNode ])
3458 iNotSameNode = iNode;
3462 sames[nbSame++] = iNode;
3467 //cerr<<" nbSame = "<<nbSame<<endl;
3468 if ( nbSame == nbNodes || nbSame > 2) {
3469 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3470 //INFOS( " Too many same nodes of element " << elem->GetID() );
3474 // if( elem->IsQuadratic() && nbSame>0 ) {
3475 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3479 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3480 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3482 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3483 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3484 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3488 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3489 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3490 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3491 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3493 // check element orientation
3495 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3496 //MESSAGE("Reversed elem " << elem );
3500 std::swap( iBeforeSame, iAfterSame );
3503 // make new elements
3504 const SMDS_MeshElement* lastElem = elem;
3505 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3507 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3508 if(issimple[iNode]) {
3509 nextNod[ iNode ] = *itNN[ iNode ];
3513 if( elem->GetType()==SMDSAbs_Node ) {
3514 // we have to use two nodes
3515 midlNod[ iNode ] = *itNN[ iNode ];
3517 nextNod[ iNode ] = *itNN[ iNode ];
3520 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3521 // we have to use each second node
3523 nextNod[ iNode ] = *itNN[ iNode ];
3527 // we have to use two nodes
3528 midlNod[ iNode ] = *itNN[ iNode ];
3530 nextNod[ iNode ] = *itNN[ iNode ];
3535 SMDS_MeshElement* aNewElem = 0;
3536 if(!elem->IsPoly()) {
3537 switch ( nbNodes ) {
3541 if ( nbSame == 0 ) {
3543 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3545 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3551 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3552 nextNod[ 1 ], nextNod[ 0 ] );
3554 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3555 nextNod[ iNotSameNode ] );
3559 case 3: { // TRIANGLE or quadratic edge
3560 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3562 if ( nbSame == 0 ) // --- pentahedron
3563 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3564 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3566 else if ( nbSame == 1 ) // --- pyramid
3567 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3568 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3569 nextNod[ iSameNode ]);
3571 else // 2 same nodes: --- tetrahedron
3572 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3573 nextNod[ iNotSameNode ]);
3575 else { // quadratic edge
3576 if(nbSame==0) { // quadratic quadrangle
3577 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3578 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3580 else if(nbSame==1) { // quadratic triangle
3582 return; // medium node on axis
3584 else if(sames[0]==0) {
3585 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3586 nextNod[2], midlNod[1], prevNod[2]);
3588 else { // sames[0]==1
3589 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3590 midlNod[0], nextNod[2], prevNod[2]);
3599 case 4: { // QUADRANGLE
3601 if ( nbSame == 0 ) // --- hexahedron
3602 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3603 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3605 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3606 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3607 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3608 nextNod[ iSameNode ]);
3609 newElems.push_back( aNewElem );
3610 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3611 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3612 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3614 else if ( nbSame == 2 ) { // pentahedron
3615 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3616 // iBeforeSame is same too
3617 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3618 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3619 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3621 // iAfterSame is same too
3622 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3623 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3624 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3628 case 6: { // quadratic triangle
3629 // create pentahedron with 15 nodes
3631 if(i0>0) { // reversed case
3632 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3633 nextNod[0], nextNod[2], nextNod[1],
3634 prevNod[5], prevNod[4], prevNod[3],
3635 nextNod[5], nextNod[4], nextNod[3],
3636 midlNod[0], midlNod[2], midlNod[1]);
3638 else { // not reversed case
3639 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3640 nextNod[0], nextNod[1], nextNod[2],
3641 prevNod[3], prevNod[4], prevNod[5],
3642 nextNod[3], nextNod[4], nextNod[5],
3643 midlNod[0], midlNod[1], midlNod[2]);
3646 else if(nbSame==1) {
3647 // 2d order pyramid of 13 nodes
3648 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3649 // int n12,int n23,int n34,int n41,
3650 // int n15,int n25,int n35,int n45, int ID);
3652 int n1,n4,n41,n15,n45;
3653 if(i0>0) { // reversed case
3654 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3655 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3661 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3662 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3667 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3668 nextNod[n4], prevNod[n4], prevNod[n5],
3669 midlNod[n1], nextNod[n41],
3670 midlNod[n4], prevNod[n41],
3671 prevNod[n15], nextNod[n15],
3672 nextNod[n45], prevNod[n45]);
3674 else if(nbSame==2) {
3675 // 2d order tetrahedron of 10 nodes
3676 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3677 // int n12,int n23,int n31,
3678 // int n14,int n24,int n34, int ID);
3679 int n1 = iNotSameNode;
3680 int n2,n3,n12,n23,n31;
3681 if(i0>0) { // reversed case
3682 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3683 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3689 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3690 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3695 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3696 prevNod[n12], prevNod[n23], prevNod[n31],
3697 midlNod[n1], nextNod[n12], nextNod[n31]);
3701 case 8: { // quadratic quadrangle
3703 // create hexahedron with 20 nodes
3704 if(i0>0) { // reversed case
3705 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3706 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3707 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3708 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3709 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3711 else { // not reversed case
3712 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3713 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3714 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3715 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3716 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3719 else if(nbSame==1) {
3720 // --- pyramid + pentahedron - can not be created since it is needed
3721 // additional middle node ot the center of face
3722 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3725 else if(nbSame==2) {
3726 // 2d order Pentahedron with 15 nodes
3727 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3728 // int n12,int n23,int n31,int n45,int n56,int n64,
3729 // int n14,int n25,int n36, int ID);
3731 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3732 // iBeforeSame is same too
3739 // iAfterSame is same too
3745 int n12,n45,n14,n25;
3746 if(i0>0) { //reversed case
3758 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3759 prevNod[n4], prevNod[n5], nextNod[n5],
3760 prevNod[n12], midlNod[n2], nextNod[n12],
3761 prevNod[n45], midlNod[n5], nextNod[n45],
3762 prevNod[n14], prevNod[n25], nextNod[n25]);
3767 // realized for extrusion only
3768 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3769 //vector<int> quantities (nbNodes + 2);
3771 //quantities[0] = nbNodes; // bottom of prism
3772 //for (int inode = 0; inode < nbNodes; inode++) {
3773 // polyedre_nodes[inode] = prevNod[inode];
3776 //quantities[1] = nbNodes; // top of prism
3777 //for (int inode = 0; inode < nbNodes; inode++) {
3778 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3781 //for (int iface = 0; iface < nbNodes; iface++) {
3782 // quantities[iface + 2] = 4;
3783 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3784 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3785 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3786 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3787 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3789 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3796 // realized for extrusion only
3797 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3798 vector<int> quantities (nbNodes + 2);
3800 quantities[0] = nbNodes; // bottom of prism
3801 for (int inode = 0; inode < nbNodes; inode++) {
3802 polyedre_nodes[inode] = prevNod[inode];
3805 quantities[1] = nbNodes; // top of prism
3806 for (int inode = 0; inode < nbNodes; inode++) {
3807 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3810 for (int iface = 0; iface < nbNodes; iface++) {
3811 quantities[iface + 2] = 4;
3812 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3813 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3814 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3815 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3816 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3818 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3822 newElems.push_back( aNewElem );
3823 myLastCreatedElems.Append(aNewElem);
3824 srcElements.Append( elem );
3825 lastElem = aNewElem;
3828 // set new prev nodes
3829 for ( iNode = 0; iNode < nbNodes; iNode++ )
3830 prevNod[ iNode ] = nextNod[ iNode ];
3835 //=======================================================================
3837 * \brief Create 1D and 2D elements around swept elements
3838 * \param mapNewNodes - source nodes and ones generated from them
3839 * \param newElemsMap - source elements and ones generated from them
3840 * \param elemNewNodesMap - nodes generated from each node of each element
3841 * \param elemSet - all swept elements
3842 * \param nbSteps - number of sweeping steps
3843 * \param srcElements - to append elem for each generated element
3845 //=======================================================================
3847 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3848 TElemOfElemListMap & newElemsMap,
3849 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3850 TIDSortedElemSet& elemSet,
3852 SMESH_SequenceOfElemPtr& srcElements)
3854 MESSAGE("makeWalls");
3855 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3856 SMESHDS_Mesh* aMesh = GetMeshDS();
3858 // Find nodes belonging to only one initial element - sweep them to get edges.
3860 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3861 for ( ; nList != mapNewNodes.end(); nList++ ) {
3862 const SMDS_MeshNode* node =
3863 static_cast<const SMDS_MeshNode*>( nList->first );
3864 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3865 int nbInitElems = 0;
3866 const SMDS_MeshElement* el = 0;
3867 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3868 while ( eIt->more() && nbInitElems < 2 ) {
3870 SMDSAbs_ElementType type = el->GetType();
3871 if ( type == SMDSAbs_Volume || type < highType ) continue;
3872 if ( type > highType ) {
3876 if ( elemSet.find(el) != elemSet.end() )
3879 if ( nbInitElems < 2 ) {
3880 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3881 if(!NotCreateEdge) {
3882 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3883 list<const SMDS_MeshElement*> newEdges;
3884 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3889 // Make a ceiling for each element ie an equal element of last new nodes.
3890 // Find free links of faces - make edges and sweep them into faces.
3892 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3893 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3894 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3895 const SMDS_MeshElement* elem = itElem->first;
3896 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3898 if(itElem->second.size()==0) continue;
3900 if ( elem->GetType() == SMDSAbs_Edge ) {
3901 // create a ceiling edge
3902 if (!elem->IsQuadratic()) {
3903 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3904 vecNewNodes[ 1 ]->second.back())) {
3905 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3906 vecNewNodes[ 1 ]->second.back()));
3907 srcElements.Append( myLastCreatedElems.Last() );
3911 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3912 vecNewNodes[ 1 ]->second.back(),
3913 vecNewNodes[ 2 ]->second.back())) {
3914 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3915 vecNewNodes[ 1 ]->second.back(),
3916 vecNewNodes[ 2 ]->second.back()));
3917 srcElements.Append( myLastCreatedElems.Last() );
3921 if ( elem->GetType() != SMDSAbs_Face )
3924 bool hasFreeLinks = false;
3926 TIDSortedElemSet avoidSet;
3927 avoidSet.insert( elem );
3929 set<const SMDS_MeshNode*> aFaceLastNodes;
3930 int iNode, nbNodes = vecNewNodes.size();
3931 if(!elem->IsQuadratic()) {
3932 // loop on the face nodes
3933 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3934 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3935 // look for free links of the face
3936 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3937 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3938 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3939 // check if a link is free
3940 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3941 hasFreeLinks = true;
3942 // make an edge and a ceiling for a new edge
3943 if ( !aMesh->FindEdge( n1, n2 )) {
3944 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3945 srcElements.Append( myLastCreatedElems.Last() );
3947 n1 = vecNewNodes[ iNode ]->second.back();
3948 n2 = vecNewNodes[ iNext ]->second.back();
3949 if ( !aMesh->FindEdge( n1, n2 )) {
3950 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3951 srcElements.Append( myLastCreatedElems.Last() );
3956 else { // elem is quadratic face
3957 int nbn = nbNodes/2;
3958 for ( iNode = 0; iNode < nbn; iNode++ ) {
3959 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3960 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3961 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3962 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3963 // check if a link is free
3964 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3965 hasFreeLinks = true;
3966 // make an edge and a ceiling for a new edge
3968 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3969 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3970 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3971 srcElements.Append( myLastCreatedElems.Last() );
3973 n1 = vecNewNodes[ iNode ]->second.back();
3974 n2 = vecNewNodes[ iNext ]->second.back();
3975 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3976 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3977 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3978 srcElements.Append( myLastCreatedElems.Last() );
3982 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3983 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3987 // sweep free links into faces
3989 if ( hasFreeLinks ) {
3990 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3991 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3993 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3994 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3995 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3996 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3998 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3999 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4001 while ( iVol++ < volNb ) v++;
4002 // find indices of free faces of a volume and their source edges
4003 list< int > freeInd;
4004 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4005 SMDS_VolumeTool vTool( *v );
4006 int iF, nbF = vTool.NbFaces();
4007 for ( iF = 0; iF < nbF; iF ++ ) {
4008 if (vTool.IsFreeFace( iF ) &&
4009 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4010 initNodeSet != faceNodeSet) // except an initial face
4012 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4014 freeInd.push_back( iF );
4015 // find source edge of a free face iF
4016 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4017 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4018 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4019 initNodeSet.begin(), initNodeSet.end(),
4020 commonNodes.begin());
4021 if ( (*v)->IsQuadratic() )
4022 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4024 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4026 if ( !srcEdges.back() )
4028 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4029 << iF << " of volume #" << vTool.ID() << endl;
4034 if ( freeInd.empty() )
4037 // create faces for all steps;
4038 // if such a face has been already created by sweep of edge,
4039 // assure that its orientation is OK
4040 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4042 vTool.SetExternalNormal();
4043 const int nextShift = vTool.IsForward() ? +1 : -1;
4044 list< int >::iterator ind = freeInd.begin();
4045 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4046 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4048 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4049 int nbn = vTool.NbFaceNodes( *ind );
4050 if ( ! (*v)->IsPoly() )
4052 case 3: { ///// triangle
4053 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4055 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4057 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4059 nodes[ 1 + nextShift ] };
4061 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4063 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4068 case 4: { ///// quadrangle
4069 const SMDS_MeshFace * f =
4070 aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4072 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4074 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4075 nodes[ 2 ], nodes[ 2+nextShift ] };
4077 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4079 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4080 newOrder[ 2 ], newOrder[ 3 ]));
4084 case 6: { /////// quadratic triangle
4085 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4086 nodes[1], nodes[3], nodes[5] );
4088 nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4090 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4092 nodes[2 + 2*nextShift],
4093 nodes[3 - 2*nextShift],
4095 nodes[3 + 2*nextShift]};
4097 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4099 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4108 default: /////// quadratic quadrangle
4109 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4110 nodes[1], nodes[3], nodes[5], nodes[7] );
4112 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4114 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4115 nodes[4 - 2*nextShift],
4117 nodes[4 + 2*nextShift],
4119 nodes[5 - 2*nextShift],
4121 nodes[5 + 2*nextShift] };
4123 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4125 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4126 newOrder[ 2 ], newOrder[ 3 ],
4127 newOrder[ 4 ], newOrder[ 5 ],
4128 newOrder[ 6 ], newOrder[ 7 ]));
4132 else { //////// polygon
4134 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4135 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4137 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4139 if ( !vTool.IsForward() )
4140 std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4142 aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4144 AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
4148 while ( srcElements.Length() < myLastCreatedElems.Length() )
4149 srcElements.Append( *srcEdge );
4151 } // loop on free faces
4153 // go to the next volume
4155 while ( iVol++ < nbVolumesByStep ) v++;
4158 } // loop on volumes of one step
4159 } // sweep free links into faces
4161 // Make a ceiling face with a normal external to a volume
4163 SMDS_VolumeTool lastVol( itElem->second.back() );
4165 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4167 lastVol.SetExternalNormal();
4168 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4169 int nbn = lastVol.NbFaceNodes( iF );
4172 if (!hasFreeLinks ||
4173 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4174 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4177 if (!hasFreeLinks ||
4178 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4179 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4182 if(itElem->second.back()->IsQuadratic()) {
4184 if (!hasFreeLinks ||
4185 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4186 nodes[1], nodes[3], nodes[5]) ) {
4187 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4188 nodes[1], nodes[3], nodes[5]));
4192 if (!hasFreeLinks ||
4193 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4194 nodes[1], nodes[3], nodes[5], nodes[7]) )
4195 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4196 nodes[1], nodes[3], nodes[5], nodes[7]));
4200 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4201 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4202 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4206 while ( srcElements.Length() < myLastCreatedElems.Length() )
4207 srcElements.Append( myLastCreatedElems.Last() );
4209 } // loop on swept elements
4212 //=======================================================================
4213 //function : RotationSweep
4215 //=======================================================================
4217 SMESH_MeshEditor::PGroupIDs
4218 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4219 const gp_Ax1& theAxis,
4220 const double theAngle,
4221 const int theNbSteps,
4222 const double theTol,
4223 const bool theMakeGroups,
4224 const bool theMakeWalls)
4226 myLastCreatedElems.Clear();
4227 myLastCreatedNodes.Clear();
4229 // source elements for each generated one
4230 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4232 MESSAGE( "RotationSweep()");
4234 aTrsf.SetRotation( theAxis, theAngle );
4236 aTrsf2.SetRotation( theAxis, theAngle/2. );
4238 gp_Lin aLine( theAxis );
4239 double aSqTol = theTol * theTol;
4241 SMESHDS_Mesh* aMesh = GetMeshDS();
4243 TNodeOfNodeListMap mapNewNodes;
4244 TElemOfVecOfNnlmiMap mapElemNewNodes;
4245 TElemOfElemListMap newElemsMap;
4248 TIDSortedElemSet::iterator itElem;
4249 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4250 const SMDS_MeshElement* elem = *itElem;
4251 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4253 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4254 newNodesItVec.reserve( elem->NbNodes() );
4256 // loop on elem nodes
4257 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4258 while ( itN->more() ) {
4259 // check if a node has been already sweeped
4260 const SMDS_MeshNode* node = cast2Node( itN->next() );
4262 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4264 aXYZ.Coord( coord[0], coord[1], coord[2] );
4265 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4267 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4268 if ( nIt == mapNewNodes.end() ) {
4269 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4270 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4273 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4275 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4276 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4277 const SMDS_MeshNode * newNode = node;
4278 for ( int i = 0; i < theNbSteps; i++ ) {
4280 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4282 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4283 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4284 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4285 myLastCreatedNodes.Append(newNode);
4286 srcNodes.Append( node );
4287 listNewNodes.push_back( newNode );
4288 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4289 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4292 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4294 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4295 myLastCreatedNodes.Append(newNode);
4296 srcNodes.Append( node );
4297 listNewNodes.push_back( newNode );
4300 listNewNodes.push_back( newNode );
4301 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4302 listNewNodes.push_back( newNode );
4309 // if current elem is quadratic and current node is not medium
4310 // we have to check - may be it is needed to insert additional nodes
4311 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4312 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4313 if(listNewNodes.size()==theNbSteps) {
4314 listNewNodes.clear();
4316 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4318 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4319 const SMDS_MeshNode * newNode = node;
4321 for(int i = 0; i<theNbSteps; i++) {
4322 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4323 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4324 cout<<" 3 AddNode: "<<newNode;
4325 myLastCreatedNodes.Append(newNode);
4326 listNewNodes.push_back( newNode );
4327 srcNodes.Append( node );
4328 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4329 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4330 cout<<" 4 AddNode: "<<newNode;
4331 myLastCreatedNodes.Append(newNode);
4332 srcNodes.Append( node );
4333 listNewNodes.push_back( newNode );
4337 listNewNodes.push_back( newNode );
4343 newNodesItVec.push_back( nIt );
4345 // make new elements
4346 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4350 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4352 PGroupIDs newGroupIDs;
4353 if ( theMakeGroups )
4354 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4360 //=======================================================================
4361 //function : CreateNode
4363 //=======================================================================
4364 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4367 const double tolnode,
4368 SMESH_SequenceOfNode& aNodes)
4370 myLastCreatedElems.Clear();
4371 myLastCreatedNodes.Clear();
4374 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4376 // try to search in sequence of existing nodes
4377 // if aNodes.Length()>0 we 'nave to use given sequence
4378 // else - use all nodes of mesh
4379 if(aNodes.Length()>0) {
4381 for(i=1; i<=aNodes.Length(); i++) {
4382 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4383 if(P1.Distance(P2)<tolnode)
4384 return aNodes.Value(i);
4388 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4389 while(itn->more()) {
4390 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4391 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4392 if(P1.Distance(P2)<tolnode)
4397 // create new node and return it
4398 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4399 myLastCreatedNodes.Append(NewNode);
4404 //=======================================================================
4405 //function : ExtrusionSweep
4407 //=======================================================================
4409 SMESH_MeshEditor::PGroupIDs
4410 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4411 const gp_Vec& theStep,
4412 const int theNbSteps,
4413 TElemOfElemListMap& newElemsMap,
4414 const bool theMakeGroups,
4416 const double theTolerance)
4418 ExtrusParam aParams;
4419 aParams.myDir = gp_Dir(theStep);
4420 aParams.myNodes.Clear();
4421 aParams.mySteps = new TColStd_HSequenceOfReal;
4423 for(i=1; i<=theNbSteps; i++)
4424 aParams.mySteps->Append(theStep.Magnitude());
4427 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4431 //=======================================================================
4432 //function : ExtrusionSweep
4434 //=======================================================================
4436 SMESH_MeshEditor::PGroupIDs
4437 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4438 ExtrusParam& theParams,
4439 TElemOfElemListMap& newElemsMap,
4440 const bool theMakeGroups,
4442 const double theTolerance)
4444 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4445 myLastCreatedElems.Clear();
4446 myLastCreatedNodes.Clear();
4448 // source elements for each generated one
4449 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4451 SMESHDS_Mesh* aMesh = GetMeshDS();
4453 int nbsteps = theParams.mySteps->Length();
4455 TNodeOfNodeListMap mapNewNodes;
4456 //TNodeOfNodeVecMap mapNewNodes;
4457 TElemOfVecOfNnlmiMap mapElemNewNodes;
4458 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4461 TIDSortedElemSet::iterator itElem;
4462 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4463 // check element type
4464 const SMDS_MeshElement* elem = *itElem;
4465 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4468 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4469 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4470 newNodesItVec.reserve( elem->NbNodes() );
4472 // loop on elem nodes
4473 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4474 while ( itN->more() )
4476 // check if a node has been already sweeped
4477 const SMDS_MeshNode* node = cast2Node( itN->next() );
4478 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4479 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4480 if ( nIt == mapNewNodes.end() ) {
4481 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4482 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4483 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4484 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4485 //vecNewNodes.reserve(nbsteps);
4488 double coord[] = { node->X(), node->Y(), node->Z() };
4489 //int nbsteps = theParams.mySteps->Length();
4490 for ( int i = 0; i < nbsteps; i++ ) {
4491 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4492 // create additional node
4493 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4494 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4495 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4496 if( theFlags & EXTRUSION_FLAG_SEW ) {
4497 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4498 theTolerance, theParams.myNodes);
4499 listNewNodes.push_back( newNode );
4502 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4503 myLastCreatedNodes.Append(newNode);
4504 srcNodes.Append( node );
4505 listNewNodes.push_back( newNode );
4508 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4509 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4510 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4511 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4512 if( theFlags & EXTRUSION_FLAG_SEW ) {
4513 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4514 theTolerance, theParams.myNodes);
4515 listNewNodes.push_back( newNode );
4516 //vecNewNodes[i]=newNode;
4519 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4520 myLastCreatedNodes.Append(newNode);
4521 srcNodes.Append( node );
4522 listNewNodes.push_back( newNode );
4523 //vecNewNodes[i]=newNode;
4528 // if current elem is quadratic and current node is not medium
4529 // we have to check - may be it is needed to insert additional nodes
4530 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4531 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4532 if(listNewNodes.size()==nbsteps) {
4533 listNewNodes.clear();
4534 double coord[] = { node->X(), node->Y(), node->Z() };
4535 for ( int i = 0; i < nbsteps; i++ ) {
4536 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4537 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4538 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4539 if( theFlags & EXTRUSION_FLAG_SEW ) {
4540 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4541 theTolerance, theParams.myNodes);
4542 listNewNodes.push_back( newNode );
4545 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4546 myLastCreatedNodes.Append(newNode);
4547 srcNodes.Append( node );
4548 listNewNodes.push_back( newNode );
4550 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4551 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4552 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4553 if( theFlags & EXTRUSION_FLAG_SEW ) {
4554 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4555 theTolerance, theParams.myNodes);
4556 listNewNodes.push_back( newNode );
4559 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4560 myLastCreatedNodes.Append(newNode);
4561 srcNodes.Append( node );
4562 listNewNodes.push_back( newNode );
4568 newNodesItVec.push_back( nIt );
4570 // make new elements
4571 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4574 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4575 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4577 PGroupIDs newGroupIDs;
4578 if ( theMakeGroups )
4579 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4585 //=======================================================================
4586 //class : SMESH_MeshEditor_PathPoint
4587 //purpose : auxiliary class
4588 //=======================================================================
4589 class SMESH_MeshEditor_PathPoint {
4591 SMESH_MeshEditor_PathPoint() {
4592 myPnt.SetCoord(99., 99., 99.);
4593 myTgt.SetCoord(1.,0.,0.);
4597 void SetPnt(const gp_Pnt& aP3D){
4600 void SetTangent(const gp_Dir& aTgt){
4603 void SetAngle(const double& aBeta){
4606 void SetParameter(const double& aPrm){
4609 const gp_Pnt& Pnt()const{
4612 const gp_Dir& Tangent()const{
4615 double Angle()const{
4618 double Parameter()const{
4630 //=======================================================================
4631 //function : ExtrusionAlongTrack
4633 //=======================================================================
4634 SMESH_MeshEditor::Extrusion_Error
4635 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4636 SMESH_subMesh* theTrack,
4637 const SMDS_MeshNode* theN1,
4638 const bool theHasAngles,
4639 list<double>& theAngles,
4640 const bool theLinearVariation,
4641 const bool theHasRefPoint,
4642 const gp_Pnt& theRefPoint,
4643 const bool theMakeGroups)
4645 MESSAGE("ExtrusionAlongTrack");
4646 myLastCreatedElems.Clear();
4647 myLastCreatedNodes.Clear();
4650 std::list<double> aPrms;
4651 TIDSortedElemSet::iterator itElem;
4654 TopoDS_Edge aTrackEdge;
4655 TopoDS_Vertex aV1, aV2;
4657 SMDS_ElemIteratorPtr aItE;
4658 SMDS_NodeIteratorPtr aItN;
4659 SMDSAbs_ElementType aTypeE;
4661 TNodeOfNodeListMap mapNewNodes;
4664 aNbE = theElements.size();
4667 return EXTR_NO_ELEMENTS;
4669 // 1.1 Track Pattern
4672 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4674 aItE = pSubMeshDS->GetElements();
4675 while ( aItE->more() ) {
4676 const SMDS_MeshElement* pE = aItE->next();
4677 aTypeE = pE->GetType();
4678 // Pattern must contain links only
4679 if ( aTypeE != SMDSAbs_Edge )
4680 return EXTR_PATH_NOT_EDGE;
4683 list<SMESH_MeshEditor_PathPoint> fullList;
4685 const TopoDS_Shape& aS = theTrack->GetSubShape();
4686 // Sub shape for the Pattern must be an Edge or Wire
4687 if( aS.ShapeType() == TopAbs_EDGE ) {
4688 aTrackEdge = TopoDS::Edge( aS );
4689 // the Edge must not be degenerated
4690 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4691 return EXTR_BAD_PATH_SHAPE;
4692 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4693 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4694 const SMDS_MeshNode* aN1 = aItN->next();
4695 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4696 const SMDS_MeshNode* aN2 = aItN->next();
4697 // starting node must be aN1 or aN2
4698 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4699 return EXTR_BAD_STARTING_NODE;
4700 aItN = pSubMeshDS->GetNodes();
4701 while ( aItN->more() ) {
4702 const SMDS_MeshNode* pNode = aItN->next();
4703 const SMDS_EdgePosition* pEPos =
4704 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4705 double aT = pEPos->GetUParameter();
4706 aPrms.push_back( aT );
4708 //Extrusion_Error err =
4709 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4710 } else if( aS.ShapeType() == TopAbs_WIRE ) {
4711 list< SMESH_subMesh* > LSM;
4712 TopTools_SequenceOfShape Edges;
4713 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4714 while(itSM->more()) {
4715 SMESH_subMesh* SM = itSM->next();
4717 const TopoDS_Shape& aS = SM->GetSubShape();
4720 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4721 int startNid = theN1->GetID();
4722 TColStd_MapOfInteger UsedNums;
4724 int NbEdges = Edges.Length();
4726 for(; i<=NbEdges; i++) {
4728 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4729 for(; itLSM!=LSM.end(); itLSM++) {
4731 if(UsedNums.Contains(k)) continue;
4732 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4733 SMESH_subMesh* locTrack = *itLSM;
4734 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4735 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4736 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4737 const SMDS_MeshNode* aN1 = aItN->next();
4738 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4739 const SMDS_MeshNode* aN2 = aItN->next();
4740 // starting node must be aN1 or aN2
4741 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4742 // 2. Collect parameters on the track edge
4744 aItN = locMeshDS->GetNodes();
4745 while ( aItN->more() ) {
4746 const SMDS_MeshNode* pNode = aItN->next();
4747 const SMDS_EdgePosition* pEPos =
4748 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4749 double aT = pEPos->GetUParameter();
4750 aPrms.push_back( aT );
4752 list<SMESH_MeshEditor_PathPoint> LPP;
4753 //Extrusion_Error err =
4754 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4755 LLPPs.push_back(LPP);
4757 // update startN for search following egde
4758 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4759 else startNid = aN1->GetID();
4763 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4764 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4765 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4766 for(; itPP!=firstList.end(); itPP++) {
4767 fullList.push_back( *itPP );
4769 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4770 fullList.pop_back();
4772 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4773 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4774 itPP = currList.begin();
4775 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4776 gp_Dir D1 = PP1.Tangent();
4777 gp_Dir D2 = PP2.Tangent();
4778 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4779 (D1.Z()+D2.Z())/2 ) );
4780 PP1.SetTangent(Dnew);
4781 fullList.push_back(PP1);
4783 for(; itPP!=firstList.end(); itPP++) {
4784 fullList.push_back( *itPP );
4786 PP1 = fullList.back();
4787 fullList.pop_back();
4789 // if wire not closed
4790 fullList.push_back(PP1);
4794 return EXTR_BAD_PATH_SHAPE;
4797 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4798 theHasRefPoint, theRefPoint, theMakeGroups);
4802 //=======================================================================
4803 //function : ExtrusionAlongTrack
4805 //=======================================================================
4806 SMESH_MeshEditor::Extrusion_Error
4807 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4808 SMESH_Mesh* theTrack,
4809 const SMDS_MeshNode* theN1,
4810 const bool theHasAngles,
4811 list<double>& theAngles,
4812 const bool theLinearVariation,
4813 const bool theHasRefPoint,
4814 const gp_Pnt& theRefPoint,
4815 const bool theMakeGroups)
4817 myLastCreatedElems.Clear();
4818 myLastCreatedNodes.Clear();
4821 std::list<double> aPrms;
4822 TIDSortedElemSet::iterator itElem;
4825 TopoDS_Edge aTrackEdge;
4826 TopoDS_Vertex aV1, aV2;
4828 SMDS_ElemIteratorPtr aItE;
4829 SMDS_NodeIteratorPtr aItN;
4830 SMDSAbs_ElementType aTypeE;
4832 TNodeOfNodeListMap mapNewNodes;
4835 aNbE = theElements.size();
4838 return EXTR_NO_ELEMENTS;
4840 // 1.1 Track Pattern
4843 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4845 aItE = pMeshDS->elementsIterator();
4846 while ( aItE->more() ) {
4847 const SMDS_MeshElement* pE = aItE->next();
4848 aTypeE = pE->GetType();
4849 // Pattern must contain links only
4850 if ( aTypeE != SMDSAbs_Edge )
4851 return EXTR_PATH_NOT_EDGE;
4854 list<SMESH_MeshEditor_PathPoint> fullList;
4856 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4858 if( aS == SMESH_Mesh::PseudoShape() ) {
4859 //Mesh without shape
4860 const SMDS_MeshNode* currentNode = NULL;
4861 const SMDS_MeshNode* prevNode = theN1;
4862 std::vector<const SMDS_MeshNode*> aNodesList;
4863 aNodesList.push_back(theN1);
4864 int nbEdges = 0, conn=0;
4865 const SMDS_MeshElement* prevElem = NULL;
4866 const SMDS_MeshElement* currentElem = NULL;
4867 int totalNbEdges = theTrack->NbEdges();
4868 SMDS_ElemIteratorPtr nIt;
4869 bool isClosed = false;
4872 if( !theTrack->GetMeshDS()->Contains(theN1) ) {
4873 return EXTR_BAD_STARTING_NODE;
4876 conn = nbEdgeConnectivity(theN1);
4878 return EXTR_PATH_NOT_EDGE;
4880 aItE = theN1->GetInverseElementIterator();
4881 prevElem = aItE->next();
4882 currentElem = prevElem;
4884 if(totalNbEdges == 1 ) {
4885 nIt = currentElem->nodesIterator();
4886 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4887 if(currentNode == prevNode)
4888 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4889 aNodesList.push_back(currentNode);
4891 nIt = currentElem->nodesIterator();
4892 while( nIt->more() ) {
4893 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4894 if(currentNode == prevNode)
4895 currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
4896 aNodesList.push_back(currentNode);
4898 //case of the closed mesh
4899 if(currentNode == theN1) {
4905 conn = nbEdgeConnectivity(currentNode);
4907 return EXTR_PATH_NOT_EDGE;
4908 }else if( conn == 1 && nbEdges > 0 ) {
4913 prevNode = currentNode;
4914 aItE = currentNode->GetInverseElementIterator();
4915 currentElem = aItE->next();
4916 if( currentElem == prevElem)
4917 currentElem = aItE->next();
4918 nIt = currentElem->nodesIterator();
4919 prevElem = currentElem;
4925 if(nbEdges != totalNbEdges)
4926 return EXTR_PATH_NOT_EDGE;
4928 TopTools_SequenceOfShape Edges;
4929 double x1,x2,y1,y2,z1,z2;
4930 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4931 int startNid = theN1->GetID();
4932 for(int i = 1; i < aNodesList.size(); i++) {
4933 x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
4934 y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
4935 z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
4936 TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
4937 list<SMESH_MeshEditor_PathPoint> LPP;
4939 MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
4940 LLPPs.push_back(LPP);
4941 if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
4942 else startNid = aNodesList[i-1]->GetID();
4946 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4947 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4948 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4949 for(; itPP!=firstList.end(); itPP++) {
4950 fullList.push_back( *itPP );
4953 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4954 SMESH_MeshEditor_PathPoint PP2;
4955 fullList.pop_back();
4957 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4958 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4959 itPP = currList.begin();
4960 PP2 = currList.front();
4961 gp_Dir D1 = PP1.Tangent();
4962 gp_Dir D2 = PP2.Tangent();
4963 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4964 (D1.Z()+D2.Z())/2 ) );
4965 PP1.SetTangent(Dnew);
4966 fullList.push_back(PP1);
4968 for(; itPP!=currList.end(); itPP++) {
4969 fullList.push_back( *itPP );
4971 PP1 = fullList.back();
4972 fullList.pop_back();
4974 fullList.push_back(PP1);
4976 } // Sub shape for the Pattern must be an Edge or Wire
4977 else if( aS.ShapeType() == TopAbs_EDGE ) {
4978 aTrackEdge = TopoDS::Edge( aS );
4979 // the Edge must not be degenerated
4980 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4981 return EXTR_BAD_PATH_SHAPE;
4982 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4983 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4984 const SMDS_MeshNode* aN1 = aItN->next();
4985 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4986 const SMDS_MeshNode* aN2 = aItN->next();
4987 // starting node must be aN1 or aN2
4988 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4989 return EXTR_BAD_STARTING_NODE;
4990 aItN = pMeshDS->nodesIterator();
4991 while ( aItN->more() ) {
4992 const SMDS_MeshNode* pNode = aItN->next();
4993 if( pNode==aN1 || pNode==aN2 ) continue;
4994 const SMDS_EdgePosition* pEPos =
4995 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4996 double aT = pEPos->GetUParameter();
4997 aPrms.push_back( aT );
4999 //Extrusion_Error err =
5000 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
5002 else if( aS.ShapeType() == TopAbs_WIRE ) {
5003 list< SMESH_subMesh* > LSM;
5004 TopTools_SequenceOfShape Edges;
5005 TopExp_Explorer eExp(aS, TopAbs_EDGE);
5006 for(; eExp.More(); eExp.Next()) {
5007 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
5008 if( BRep_Tool::Degenerated(E) ) continue;
5009 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
5015 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
5016 int startNid = theN1->GetID();
5017 TColStd_MapOfInteger UsedNums;
5018 int NbEdges = Edges.Length();
5020 for(; i<=NbEdges; i++) {
5022 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
5023 for(; itLSM!=LSM.end(); itLSM++) {
5025 if(UsedNums.Contains(k)) continue;
5026 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
5027 SMESH_subMesh* locTrack = *itLSM;
5028 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
5029 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5030 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
5031 const SMDS_MeshNode* aN1 = aItN->next();
5032 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
5033 const SMDS_MeshNode* aN2 = aItN->next();
5034 // starting node must be aN1 or aN2
5035 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
5036 // 2. Collect parameters on the track edge
5038 aItN = locMeshDS->GetNodes();
5039 while ( aItN->more() ) {
5040 const SMDS_MeshNode* pNode = aItN->next();
5041 const SMDS_EdgePosition* pEPos =
5042 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
5043 double aT = pEPos->GetUParameter();
5044 aPrms.push_back( aT );
5046 list<SMESH_MeshEditor_PathPoint> LPP;
5047 //Extrusion_Error err =
5048 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
5049 LLPPs.push_back(LPP);
5051 // update startN for search following egde
5052 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
5053 else startNid = aN1->GetID();
5057 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
5058 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
5059 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
5060 for(; itPP!=firstList.end(); itPP++) {
5061 fullList.push_back( *itPP );
5063 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
5064 fullList.pop_back();
5066 for(; itLLPP!=LLPPs.end(); itLLPP++) {
5067 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
5068 itPP = currList.begin();
5069 SMESH_MeshEditor_PathPoint PP2 = currList.front();
5070 gp_Dir D1 = PP1.Tangent();
5071 gp_Dir D2 = PP2.Tangent();
5072 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
5073 (D1.Z()+D2.Z())/2 ) );
5074 PP1.SetTangent(Dnew);
5075 fullList.push_back(PP1);
5077 for(; itPP!=currList.end(); itPP++) {
5078 fullList.push_back( *itPP );
5080 PP1 = fullList.back();
5081 fullList.pop_back();
5083 // if wire not closed
5084 fullList.push_back(PP1);
5088 return EXTR_BAD_PATH_SHAPE;
5091 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
5092 theHasRefPoint, theRefPoint, theMakeGroups);
5096 //=======================================================================
5097 //function : MakeEdgePathPoints
5098 //purpose : auxilary for ExtrusionAlongTrack
5099 //=======================================================================
5100 SMESH_MeshEditor::Extrusion_Error
5101 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
5102 const TopoDS_Edge& aTrackEdge,
5104 list<SMESH_MeshEditor_PathPoint>& LPP)
5106 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
5108 aTolVec2=aTolVec*aTolVec;
5110 TopoDS_Vertex aV1, aV2;
5111 TopExp::Vertices( aTrackEdge, aV1, aV2 );
5112 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
5113 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
5114 // 2. Collect parameters on the track edge
5115 aPrms.push_front( aT1 );
5116 aPrms.push_back( aT2 );
5119 if( FirstIsStart ) {
5130 SMESH_MeshEditor_PathPoint aPP;
5131 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5132 std::list<double>::iterator aItD = aPrms.begin();
5133 for(; aItD != aPrms.end(); ++aItD) {
5137 aC3D->D1( aT, aP3D, aVec );
5138 aL2 = aVec.SquareMagnitude();
5139 if ( aL2 < aTolVec2 )
5140 return EXTR_CANT_GET_TANGENT;
5141 gp_Dir aTgt( aVec );
5143 aPP.SetTangent( aTgt );
5144 aPP.SetParameter( aT );
5151 //=======================================================================
5152 //function : MakeExtrElements
5153 //purpose : auxilary for ExtrusionAlongTrack
5154 //=======================================================================
5155 SMESH_MeshEditor::Extrusion_Error
5156 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5157 list<SMESH_MeshEditor_PathPoint>& fullList,
5158 const bool theHasAngles,
5159 list<double>& theAngles,
5160 const bool theLinearVariation,
5161 const bool theHasRefPoint,
5162 const gp_Pnt& theRefPoint,
5163 const bool theMakeGroups)
5165 MESSAGE("MakeExtrElements");
5166 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5167 int aNbTP = fullList.size();
5168 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5170 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5171 LinearAngleVariation(aNbTP-1, theAngles);
5173 vector<double> aAngles( aNbTP );
5175 for(; j<aNbTP; ++j) {
5178 if ( theHasAngles ) {
5180 std::list<double>::iterator aItD = theAngles.begin();
5181 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5183 aAngles[j] = anAngle;
5186 // fill vector of path points with angles
5187 //aPPs.resize(fullList.size());
5189 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5190 for(; itPP!=fullList.end(); itPP++) {
5192 SMESH_MeshEditor_PathPoint PP = *itPP;
5193 PP.SetAngle(aAngles[j]);
5197 TNodeOfNodeListMap mapNewNodes;
5198 TElemOfVecOfNnlmiMap mapElemNewNodes;
5199 TElemOfElemListMap newElemsMap;
5200 TIDSortedElemSet::iterator itElem;
5203 SMDSAbs_ElementType aTypeE;
5204 // source elements for each generated one
5205 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5207 // 3. Center of rotation aV0
5208 gp_Pnt aV0 = theRefPoint;
5210 if ( !theHasRefPoint ) {
5212 aGC.SetCoord( 0.,0.,0. );
5214 itElem = theElements.begin();
5215 for ( ; itElem != theElements.end(); itElem++ ) {
5216 const SMDS_MeshElement* elem = *itElem;
5218 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5219 while ( itN->more() ) {
5220 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5225 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5226 list<const SMDS_MeshNode*> aLNx;
5227 mapNewNodes[node] = aLNx;
5229 gp_XYZ aXYZ( aX, aY, aZ );
5237 } // if (!theHasRefPoint) {
5238 mapNewNodes.clear();
5240 // 4. Processing the elements
5241 SMESHDS_Mesh* aMesh = GetMeshDS();
5243 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5244 // check element type
5245 const SMDS_MeshElement* elem = *itElem;
5246 aTypeE = elem->GetType();
5247 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5250 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5251 newNodesItVec.reserve( elem->NbNodes() );
5253 // loop on elem nodes
5255 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5256 while ( itN->more() )
5259 // check if a node has been already processed
5260 const SMDS_MeshNode* node =
5261 static_cast<const SMDS_MeshNode*>( itN->next() );
5262 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5263 if ( nIt == mapNewNodes.end() ) {
5264 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5265 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5268 aX = node->X(); aY = node->Y(); aZ = node->Z();
5270 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5271 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5272 gp_Ax1 anAx1, anAxT1T0;
5273 gp_Dir aDT1x, aDT0x, aDT1T0;
5278 aPN0.SetCoord(aX, aY, aZ);
5280 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5282 aDT0x= aPP0.Tangent();
5283 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5285 for ( j = 1; j < aNbTP; ++j ) {
5286 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5288 aDT1x = aPP1.Tangent();
5289 aAngle1x = aPP1.Angle();
5291 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5293 gp_Vec aV01x( aP0x, aP1x );
5294 aTrsf.SetTranslation( aV01x );
5297 aV1x = aV0x.Transformed( aTrsf );
5298 aPN1 = aPN0.Transformed( aTrsf );
5300 // rotation 1 [ T1,T0 ]
5301 aAngleT1T0=-aDT1x.Angle( aDT0x );
5302 if (fabs(aAngleT1T0) > aTolAng) {
5304 anAxT1T0.SetLocation( aV1x );
5305 anAxT1T0.SetDirection( aDT1T0 );
5306 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5308 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5312 if ( theHasAngles ) {
5313 anAx1.SetLocation( aV1x );
5314 anAx1.SetDirection( aDT1x );
5315 aTrsfRot.SetRotation( anAx1, aAngle1x );
5317 aPN1 = aPN1.Transformed( aTrsfRot );
5321 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5322 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5323 // create additional node
5324 double x = ( aPN1.X() + aPN0.X() )/2.;
5325 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5326 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5327 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5328 myLastCreatedNodes.Append(newNode);
5329 srcNodes.Append( node );
5330 listNewNodes.push_back( newNode );
5335 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5336 myLastCreatedNodes.Append(newNode);
5337 srcNodes.Append( node );
5338 listNewNodes.push_back( newNode );
5348 // if current elem is quadratic and current node is not medium
5349 // we have to check - may be it is needed to insert additional nodes
5350 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5351 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5352 if(listNewNodes.size()==aNbTP-1) {
5353 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5354 gp_XYZ P(node->X(), node->Y(), node->Z());
5355 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5357 for(i=0; i<aNbTP-1; i++) {
5358 const SMDS_MeshNode* N = *it;
5359 double x = ( N->X() + P.X() )/2.;
5360 double y = ( N->Y() + P.Y() )/2.;
5361 double z = ( N->Z() + P.Z() )/2.;
5362 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5363 srcNodes.Append( node );
5364 myLastCreatedNodes.Append(newN);
5367 P = gp_XYZ(N->X(),N->Y(),N->Z());
5369 listNewNodes.clear();
5370 for(i=0; i<2*(aNbTP-1); i++) {
5371 listNewNodes.push_back(aNodes[i]);
5377 newNodesItVec.push_back( nIt );
5379 // make new elements
5380 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5381 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5382 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5385 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5387 if ( theMakeGroups )
5388 generateGroups( srcNodes, srcElems, "extruded");
5394 //=======================================================================
5395 //function : LinearAngleVariation
5396 //purpose : auxilary for ExtrusionAlongTrack
5397 //=======================================================================
5398 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5399 list<double>& Angles)
5401 int nbAngles = Angles.size();
5402 if( nbSteps > nbAngles ) {
5403 vector<double> theAngles(nbAngles);
5404 list<double>::iterator it = Angles.begin();
5406 for(; it!=Angles.end(); it++) {
5408 theAngles[i] = (*it);
5411 double rAn2St = double( nbAngles ) / double( nbSteps );
5412 double angPrev = 0, angle;
5413 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5414 double angCur = rAn2St * ( iSt+1 );
5415 double angCurFloor = floor( angCur );
5416 double angPrevFloor = floor( angPrev );
5417 if ( angPrevFloor == angCurFloor )
5418 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5420 int iP = int( angPrevFloor );
5421 double angPrevCeil = ceil(angPrev);
5422 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5424 int iC = int( angCurFloor );
5425 if ( iC < nbAngles )
5426 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5428 iP = int( angPrevCeil );
5430 angle += theAngles[ iC ];
5432 res.push_back(angle);
5437 for(; it!=res.end(); it++)
5438 Angles.push_back( *it );
5443 //================================================================================
5445 * \brief Move or copy theElements applying theTrsf to their nodes
5446 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5447 * \param theTrsf - transformation to apply
5448 * \param theCopy - if true, create translated copies of theElems
5449 * \param theMakeGroups - if true and theCopy, create translated groups
5450 * \param theTargetMesh - mesh to copy translated elements into
5451 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5453 //================================================================================
5455 SMESH_MeshEditor::PGroupIDs
5456 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5457 const gp_Trsf& theTrsf,
5459 const bool theMakeGroups,
5460 SMESH_Mesh* theTargetMesh)
5462 myLastCreatedElems.Clear();
5463 myLastCreatedNodes.Clear();
5465 bool needReverse = false;
5466 string groupPostfix;
5467 switch ( theTrsf.Form() ) {
5469 MESSAGE("gp_PntMirror");
5471 groupPostfix = "mirrored";
5474 MESSAGE("gp_Ax1Mirror");
5475 groupPostfix = "mirrored";
5478 MESSAGE("gp_Ax2Mirror");
5480 groupPostfix = "mirrored";
5483 MESSAGE("gp_Rotation");
5484 groupPostfix = "rotated";
5486 case gp_Translation:
5487 MESSAGE("gp_Translation");
5488 groupPostfix = "translated";
5491 MESSAGE("gp_Scale");
5492 groupPostfix = "scaled";
5494 case gp_CompoundTrsf: // different scale by axis
5495 MESSAGE("gp_CompoundTrsf");
5496 groupPostfix = "scaled";
5500 needReverse = false;
5501 groupPostfix = "transformed";
5504 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5505 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5506 SMESHDS_Mesh* aMesh = GetMeshDS();
5509 // map old node to new one
5510 TNodeNodeMap nodeMap;
5512 // elements sharing moved nodes; those of them which have all
5513 // nodes mirrored but are not in theElems are to be reversed
5514 TIDSortedElemSet inverseElemSet;
5516 // source elements for each generated one
5517 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5519 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5520 TIDSortedElemSet orphanNode;
5522 if ( theElems.empty() ) // transform the whole mesh
5525 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5526 while ( eIt->more() ) theElems.insert( eIt->next() );
5528 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5529 while ( nIt->more() )
5531 const SMDS_MeshNode* node = nIt->next();
5532 if ( node->NbInverseElements() == 0)
5533 orphanNode.insert( node );
5537 // loop on elements to transform nodes : first orphan nodes then elems
5538 TIDSortedElemSet::iterator itElem;
5539 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5540 for (int i=0; i<2; i++)
5541 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5542 const SMDS_MeshElement* elem = *itElem;
5546 // loop on elem nodes
5547 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5548 while ( itN->more() ) {
5550 const SMDS_MeshNode* node = cast2Node( itN->next() );
5551 // check if a node has been already transformed
5552 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5553 nodeMap.insert( make_pair ( node, node ));
5554 if ( !n2n_isnew.second )
5558 coord[0] = node->X();
5559 coord[1] = node->Y();
5560 coord[2] = node->Z();
5561 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5562 if ( theTargetMesh ) {
5563 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5564 n2n_isnew.first->second = newNode;
5565 myLastCreatedNodes.Append(newNode);
5566 srcNodes.Append( node );
5568 else if ( theCopy ) {
5569 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5570 n2n_isnew.first->second = newNode;
5571 myLastCreatedNodes.Append(newNode);
5572 srcNodes.Append( node );
5575 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5576 // node position on shape becomes invalid
5577 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5578 ( SMDS_SpacePosition::originSpacePosition() );
5581 // keep inverse elements
5582 if ( !theCopy && !theTargetMesh && needReverse ) {
5583 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5584 while ( invElemIt->more() ) {
5585 const SMDS_MeshElement* iel = invElemIt->next();
5586 inverseElemSet.insert( iel );
5592 // either create new elements or reverse mirrored ones
5593 if ( !theCopy && !needReverse && !theTargetMesh )
5596 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5597 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5598 theElems.insert( *invElemIt );
5600 // replicate or reverse elements
5601 // TODO revoir ordre reverse vtk
5603 REV_TETRA = 0, // = nbNodes - 4
5604 REV_PYRAMID = 1, // = nbNodes - 4
5605 REV_PENTA = 2, // = nbNodes - 4
5607 REV_HEXA = 4, // = nbNodes - 4
5611 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5612 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5613 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5614 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5615 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5616 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5619 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5621 const SMDS_MeshElement* elem = *itElem;
5622 if ( !elem || elem->GetType() == SMDSAbs_Node )
5625 int nbNodes = elem->NbNodes();
5626 int elemType = elem->GetType();
5628 if (elem->IsPoly()) {
5629 // Polygon or Polyhedral Volume
5630 switch ( elemType ) {
5633 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5635 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5636 while (itN->more()) {
5637 const SMDS_MeshNode* node =
5638 static_cast<const SMDS_MeshNode*>(itN->next());
5639 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5640 if (nodeMapIt == nodeMap.end())
5641 break; // not all nodes transformed
5643 // reverse mirrored faces and volumes
5644 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5646 poly_nodes[iNode] = (*nodeMapIt).second;
5650 if ( iNode != nbNodes )
5651 continue; // not all nodes transformed
5653 if ( theTargetMesh ) {
5654 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5655 srcElems.Append( elem );
5657 else if ( theCopy ) {
5658 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5659 srcElems.Append( elem );
5662 aMesh->ChangePolygonNodes(elem, poly_nodes);
5666 case SMDSAbs_Volume:
5668 // ATTENTION: Reversing is not yet done!!!
5669 const SMDS_VtkVolume* aPolyedre =
5670 dynamic_cast<const SMDS_VtkVolume*>( elem );
5672 MESSAGE("Warning: bad volumic element");
5676 vector<const SMDS_MeshNode*> poly_nodes;
5677 vector<int> quantities;
5679 bool allTransformed = true;
5680 int nbFaces = aPolyedre->NbFaces();
5681 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5682 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5683 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5684 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5685 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5686 if (nodeMapIt == nodeMap.end()) {
5687 allTransformed = false; // not all nodes transformed
5689 poly_nodes.push_back((*nodeMapIt).second);
5692 quantities.push_back(nbFaceNodes);
5694 if ( !allTransformed )
5695 continue; // not all nodes transformed
5697 if ( theTargetMesh ) {
5698 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5699 srcElems.Append( elem );
5701 else if ( theCopy ) {
5702 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5703 srcElems.Append( elem );
5706 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5716 int* i = index[ FORWARD ];
5717 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5718 if ( elemType == SMDSAbs_Face )
5719 i = index[ REV_FACE ];
5721 i = index[ nbNodes - 4 ];
5723 if(elem->IsQuadratic()) {
5724 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5727 if(nbNodes==3) { // quadratic edge
5728 static int anIds[] = {1,0,2};
5731 else if(nbNodes==6) { // quadratic triangle
5732 static int anIds[] = {0,2,1,5,4,3};
5735 else if(nbNodes==8) { // quadratic quadrangle
5736 static int anIds[] = {0,3,2,1,7,6,5,4};
5739 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5740 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5743 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5744 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5747 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5748 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5751 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5752 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5758 // find transformed nodes
5759 vector<const SMDS_MeshNode*> nodes(nbNodes);
5761 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5762 while ( itN->more() ) {
5763 const SMDS_MeshNode* node =
5764 static_cast<const SMDS_MeshNode*>( itN->next() );
5765 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5766 if ( nodeMapIt == nodeMap.end() )
5767 break; // not all nodes transformed
5768 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5770 if ( iNode != nbNodes )
5771 continue; // not all nodes transformed
5773 if ( theTargetMesh ) {
5774 if ( SMDS_MeshElement* copy =
5775 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5776 myLastCreatedElems.Append( copy );
5777 srcElems.Append( elem );
5780 else if ( theCopy ) {
5781 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5782 srcElems.Append( elem );
5785 // reverse element as it was reversed by transformation
5787 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5791 PGroupIDs newGroupIDs;
5793 if ( ( theMakeGroups && theCopy ) ||
5794 ( theMakeGroups && theTargetMesh ) )
5795 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5801 ////=======================================================================
5802 ////function : Scale
5804 ////=======================================================================
5806 //SMESH_MeshEditor::PGroupIDs
5807 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5808 // const gp_Pnt& thePoint,
5809 // const std::list<double>& theScaleFact,
5810 // const bool theCopy,
5811 // const bool theMakeGroups,
5812 // SMESH_Mesh* theTargetMesh)
5814 // MESSAGE("Scale");
5815 // myLastCreatedElems.Clear();
5816 // myLastCreatedNodes.Clear();
5818 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5819 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5820 // SMESHDS_Mesh* aMesh = GetMeshDS();
5822 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5823 // std::list<double>::const_iterator itS = theScaleFact.begin();
5825 // if(theScaleFact.size()==1) {
5829 // if(theScaleFact.size()==2) {
5834 // if(theScaleFact.size()>2) {
5841 // // map old node to new one
5842 // TNodeNodeMap nodeMap;
5844 // // elements sharing moved nodes; those of them which have all
5845 // // nodes mirrored but are not in theElems are to be reversed
5846 // TIDSortedElemSet inverseElemSet;
5848 // // source elements for each generated one
5849 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5851 // // loop on theElems
5852 // TIDSortedElemSet::iterator itElem;
5853 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5854 // const SMDS_MeshElement* elem = *itElem;
5858 // // loop on elem nodes
5859 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5860 // while ( itN->more() ) {
5862 // // check if a node has been already transformed
5863 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5864 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5865 // nodeMap.insert( make_pair ( node, node ));
5866 // if ( !n2n_isnew.second )
5869 // //double coord[3];
5870 // //coord[0] = node->X();
5871 // //coord[1] = node->Y();
5872 // //coord[2] = node->Z();
5873 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5874 // double dx = (node->X() - thePoint.X()) * scaleX;
5875 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5876 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5877 // if ( theTargetMesh ) {
5878 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5879 // const SMDS_MeshNode * newNode =
5880 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5881 // n2n_isnew.first->second = newNode;
5882 // myLastCreatedNodes.Append(newNode);
5883 // srcNodes.Append( node );
5885 // else if ( theCopy ) {
5886 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5887 // const SMDS_MeshNode * newNode =
5888 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5889 // n2n_isnew.first->second = newNode;
5890 // myLastCreatedNodes.Append(newNode);
5891 // srcNodes.Append( node );
5894 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5895 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5896 // // node position on shape becomes invalid
5897 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5898 // ( SMDS_SpacePosition::originSpacePosition() );
5901 // // keep inverse elements
5902 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5903 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5904 // // while ( invElemIt->more() ) {
5905 // // const SMDS_MeshElement* iel = invElemIt->next();
5906 // // inverseElemSet.insert( iel );
5912 // // either create new elements or reverse mirrored ones
5913 // //if ( !theCopy && !needReverse && !theTargetMesh )
5914 // if ( !theCopy && !theTargetMesh )
5915 // return PGroupIDs();
5917 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5918 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5919 // theElems.insert( *invElemIt );
5921 // // replicate or reverse elements
5924 // REV_TETRA = 0, // = nbNodes - 4
5925 // REV_PYRAMID = 1, // = nbNodes - 4
5926 // REV_PENTA = 2, // = nbNodes - 4
5928 // REV_HEXA = 4, // = nbNodes - 4
5931 // int index[][8] = {
5932 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5933 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5934 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5935 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5936 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5937 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5940 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5942 // const SMDS_MeshElement* elem = *itElem;
5943 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5946 // int nbNodes = elem->NbNodes();
5947 // int elemType = elem->GetType();
5949 // if (elem->IsPoly()) {
5950 // // Polygon or Polyhedral Volume
5951 // switch ( elemType ) {
5952 // case SMDSAbs_Face:
5954 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5956 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5957 // while (itN->more()) {
5958 // const SMDS_MeshNode* node =
5959 // static_cast<const SMDS_MeshNode*>(itN->next());
5960 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5961 // if (nodeMapIt == nodeMap.end())
5962 // break; // not all nodes transformed
5963 // //if (needReverse) {
5964 // // // reverse mirrored faces and volumes
5965 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5967 // poly_nodes[iNode] = (*nodeMapIt).second;
5971 // if ( iNode != nbNodes )
5972 // continue; // not all nodes transformed
5974 // if ( theTargetMesh ) {
5975 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5976 // srcElems.Append( elem );
5978 // else if ( theCopy ) {
5979 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5980 // srcElems.Append( elem );
5983 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5987 // case SMDSAbs_Volume:
5989 // // ATTENTION: Reversing is not yet done!!!
5990 // const SMDS_VtkVolume* aPolyedre =
5991 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5992 // if (!aPolyedre) {
5993 // MESSAGE("Warning: bad volumic element");
5997 // vector<const SMDS_MeshNode*> poly_nodes;
5998 // vector<int> quantities;
6000 // bool allTransformed = true;
6001 // int nbFaces = aPolyedre->NbFaces();
6002 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
6003 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
6004 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
6005 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
6006 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
6007 // if (nodeMapIt == nodeMap.end()) {
6008 // allTransformed = false; // not all nodes transformed
6010 // poly_nodes.push_back((*nodeMapIt).second);
6013 // quantities.push_back(nbFaceNodes);
6015 // if ( !allTransformed )
6016 // continue; // not all nodes transformed
6018 // if ( theTargetMesh ) {
6019 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
6020 // srcElems.Append( elem );
6022 // else if ( theCopy ) {
6023 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
6024 // srcElems.Append( elem );
6027 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
6036 // // Regular elements
6037 // int* i = index[ FORWARD ];
6038 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
6039 // // if ( elemType == SMDSAbs_Face )
6040 // // i = index[ REV_FACE ];
6042 // // i = index[ nbNodes - 4 ];
6044 // if(elem->IsQuadratic()) {
6045 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
6047 // //if(needReverse) {
6048 // // if(nbNodes==3) { // quadratic edge
6049 // // static int anIds[] = {1,0,2};
6052 // // else if(nbNodes==6) { // quadratic triangle
6053 // // static int anIds[] = {0,2,1,5,4,3};
6056 // // else if(nbNodes==8) { // quadratic quadrangle
6057 // // static int anIds[] = {0,3,2,1,7,6,5,4};
6060 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
6061 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
6064 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
6065 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
6068 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
6069 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
6072 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
6073 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
6079 // // find transformed nodes
6080 // vector<const SMDS_MeshNode*> nodes(nbNodes);
6082 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
6083 // while ( itN->more() ) {
6084 // const SMDS_MeshNode* node =
6085 // static_cast<const SMDS_MeshNode*>( itN->next() );
6086 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
6087 // if ( nodeMapIt == nodeMap.end() )
6088 // break; // not all nodes transformed
6089 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
6091 // if ( iNode != nbNodes )
6092 // continue; // not all nodes transformed
6094 // if ( theTargetMesh ) {
6095 // if ( SMDS_MeshElement* copy =
6096 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6097 // myLastCreatedElems.Append( copy );
6098 // srcElems.Append( elem );
6101 // else if ( theCopy ) {
6102 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
6103 // myLastCreatedElems.Append( copy );
6104 // srcElems.Append( elem );
6108 // // reverse element as it was reversed by transformation
6109 // if ( nbNodes > 2 )
6110 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
6114 // PGroupIDs newGroupIDs;
6116 // if ( theMakeGroups && theCopy ||
6117 // theMakeGroups && theTargetMesh ) {
6118 // string groupPostfix = "scaled";
6119 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
6122 // return newGroupIDs;
6126 //=======================================================================
6128 * \brief Create groups of elements made during transformation
6129 * \param nodeGens - nodes making corresponding myLastCreatedNodes
6130 * \param elemGens - elements making corresponding myLastCreatedElems
6131 * \param postfix - to append to names of new groups
6133 //=======================================================================
6135 SMESH_MeshEditor::PGroupIDs
6136 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6137 const SMESH_SequenceOfElemPtr& elemGens,
6138 const std::string& postfix,
6139 SMESH_Mesh* targetMesh)
6141 PGroupIDs newGroupIDs( new list<int> );
6142 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6144 // Sort existing groups by types and collect their names
6146 // to store an old group and a generated new one
6147 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6148 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6150 set< string > groupNames;
6152 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6153 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6154 while ( groupIt->more() ) {
6155 SMESH_Group * group = groupIt->next();
6156 if ( !group ) continue;
6157 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6158 if ( !groupDS || groupDS->IsEmpty() ) continue;
6159 groupNames.insert( group->GetName() );
6160 groupDS->SetStoreName( group->GetName() );
6161 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6166 // loop on nodes and elements
6167 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6169 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6170 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6171 if ( gens.Length() != elems.Length() )
6172 throw SALOME_Exception(LOCALIZED("invalid args"));
6174 // loop on created elements
6175 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6177 const SMDS_MeshElement* sourceElem = gens( iElem );
6178 if ( !sourceElem ) {
6179 MESSAGE("generateGroups(): NULL source element");
6182 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6183 if ( groupsOldNew.empty() ) {
6184 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6185 ++iElem; // skip all elements made by sourceElem
6188 // collect all elements made by sourceElem
6189 list< const SMDS_MeshElement* > resultElems;
6190 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6191 if ( resElem != sourceElem )
6192 resultElems.push_back( resElem );
6193 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6194 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6195 if ( resElem != sourceElem )
6196 resultElems.push_back( resElem );
6197 // do not generate element groups from node ones
6198 if ( sourceElem->GetType() == SMDSAbs_Node &&
6199 elems( iElem )->GetType() != SMDSAbs_Node )
6202 // add resultElems to groups made by ones the sourceElem belongs to
6203 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6204 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6206 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6207 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6209 SMDS_MeshGroup* & newGroup = gOldNew->second;
6210 if ( !newGroup )// create a new group
6213 string name = oldGroup->GetStoreName();
6214 if ( !targetMesh ) {
6218 while ( !groupNames.insert( name ).second ) // name exists
6224 TCollection_AsciiString nbStr(nb+1);
6225 name.resize( name.rfind('_')+1 );
6226 name += nbStr.ToCString();
6233 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6235 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6236 newGroup = & groupDS->SMDSGroup();
6237 newGroupIDs->push_back( id );
6240 // fill in a new group
6241 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6242 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6243 newGroup->Add( *resElemIt );
6246 } // loop on created elements
6247 }// loop on nodes and elements
6252 //================================================================================
6254 * \brief Return list of group of nodes close to each other within theTolerance
6255 * Search among theNodes or in the whole mesh if theNodes is empty using
6256 * an Octree algorithm
6258 //================================================================================
6260 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6261 const double theTolerance,
6262 TListOfListOfNodes & theGroupsOfNodes)
6264 myLastCreatedElems.Clear();
6265 myLastCreatedNodes.Clear();
6267 if ( theNodes.empty() )
6268 { // get all nodes in the mesh
6269 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6270 while ( nIt->more() )
6271 theNodes.insert( theNodes.end(),nIt->next());
6274 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6278 //=======================================================================
6280 * \brief Implementation of search for the node closest to point
6282 //=======================================================================
6284 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6286 //---------------------------------------------------------------------
6288 * \brief Constructor
6290 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6292 myMesh = ( SMESHDS_Mesh* ) theMesh;
6294 TIDSortedNodeSet nodes;
6296 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6297 while ( nIt->more() )
6298 nodes.insert( nodes.end(), nIt->next() );
6300 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6302 // get max size of a leaf box
6303 SMESH_OctreeNode* tree = myOctreeNode;
6304 while ( !tree->isLeaf() )
6306 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6310 myHalfLeafSize = tree->maxSize() / 2.;
6313 //---------------------------------------------------------------------
6315 * \brief Move node and update myOctreeNode accordingly
6317 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6319 myOctreeNode->UpdateByMoveNode( node, toPnt );
6320 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6323 //---------------------------------------------------------------------
6325 * \brief Do it's job
6327 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6329 map<double, const SMDS_MeshNode*> dist2Nodes;
6330 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6331 if ( !dist2Nodes.empty() )
6332 return dist2Nodes.begin()->second;
6333 list<const SMDS_MeshNode*> nodes;
6334 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6336 double minSqDist = DBL_MAX;
6337 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6339 // sort leafs by their distance from thePnt
6340 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6341 TDistTreeMap treeMap;
6342 list< SMESH_OctreeNode* > treeList;
6343 list< SMESH_OctreeNode* >::iterator trIt;
6344 treeList.push_back( myOctreeNode );
6346 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6347 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6348 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6350 SMESH_OctreeNode* tree = *trIt;
6351 if ( !tree->isLeaf() ) // put children to the queue
6353 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6354 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6355 while ( cIt->more() )
6356 treeList.push_back( cIt->next() );
6358 else if ( tree->NbNodes() ) // put a tree to the treeMap
6360 const Bnd_B3d& box = tree->getBox();
6361 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6362 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6363 if ( !it_in.second ) // not unique distance to box center
6364 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6367 // find distance after which there is no sense to check tree's
6368 double sqLimit = DBL_MAX;
6369 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6370 if ( treeMap.size() > 5 ) {
6371 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6372 const Bnd_B3d& box = closestTree->getBox();
6373 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6374 sqLimit = limit * limit;
6376 // get all nodes from trees
6377 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6378 if ( sqDist_tree->first > sqLimit )
6380 SMESH_OctreeNode* tree = sqDist_tree->second;
6381 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6384 // find closest among nodes
6385 minSqDist = DBL_MAX;
6386 const SMDS_MeshNode* closestNode = 0;
6387 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6388 for ( ; nIt != nodes.end(); ++nIt ) {
6389 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6390 if ( minSqDist > sqDist ) {
6398 //---------------------------------------------------------------------
6402 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6404 //---------------------------------------------------------------------
6406 * \brief Return the node tree
6408 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6411 SMESH_OctreeNode* myOctreeNode;
6412 SMESHDS_Mesh* myMesh;
6413 double myHalfLeafSize; // max size of a leaf box
6416 //=======================================================================
6418 * \brief Return SMESH_NodeSearcher
6420 //=======================================================================
6422 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6424 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6427 // ========================================================================
6428 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6430 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6431 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6432 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6434 //=======================================================================
6436 * \brief Octal tree of bounding boxes of elements
6438 //=======================================================================
6440 class ElementBndBoxTree : public SMESH_Octree
6444 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6445 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6446 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6447 ~ElementBndBoxTree();
6450 ElementBndBoxTree() {}
6451 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6452 void buildChildrenData();
6453 Bnd_B3d* buildRootBox();
6455 //!< Bounding box of element
6456 struct ElementBox : public Bnd_B3d
6458 const SMDS_MeshElement* _element;
6459 int _refCount; // an ElementBox can be included in several tree branches
6460 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6462 vector< ElementBox* > _elements;
6465 //================================================================================
6467 * \brief ElementBndBoxTree creation
6469 //================================================================================
6471 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6472 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6474 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6475 _elements.reserve( nbElems );
6477 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6478 while ( elemIt->more() )
6479 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6481 if ( _elements.size() > MaxNbElemsInLeaf )
6487 //================================================================================
6491 //================================================================================
6493 ElementBndBoxTree::~ElementBndBoxTree()
6495 for ( int i = 0; i < _elements.size(); ++i )
6496 if ( --_elements[i]->_refCount <= 0 )
6497 delete _elements[i];
6500 //================================================================================
6502 * \brief Return the maximal box
6504 //================================================================================
6506 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6508 Bnd_B3d* box = new Bnd_B3d;
6509 for ( int i = 0; i < _elements.size(); ++i )
6510 box->Add( *_elements[i] );
6514 //================================================================================
6516 * \brief Redistrubute element boxes among children
6518 //================================================================================
6520 void ElementBndBoxTree::buildChildrenData()
6522 for ( int i = 0; i < _elements.size(); ++i )
6524 for (int j = 0; j < 8; j++)
6526 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6528 _elements[i]->_refCount++;
6529 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6532 _elements[i]->_refCount--;
6536 for (int j = 0; j < 8; j++)
6538 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6539 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6540 child->myIsLeaf = true;
6542 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6543 child->_elements.resize( child->_elements.size() ); // compact
6547 //================================================================================
6549 * \brief Return elements which can include the point
6551 //================================================================================
6553 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6554 TIDSortedElemSet& foundElems)
6556 if ( level() && getBox().IsOut( point.XYZ() ))
6561 for ( int i = 0; i < _elements.size(); ++i )
6562 if ( !_elements[i]->IsOut( point.XYZ() ))
6563 foundElems.insert( _elements[i]->_element );
6567 for (int i = 0; i < 8; i++)
6568 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6572 //================================================================================
6574 * \brief Return elements which can be intersected by the line
6576 //================================================================================
6578 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6579 TIDSortedElemSet& foundElems)
6581 if ( level() && getBox().IsOut( line ))
6586 for ( int i = 0; i < _elements.size(); ++i )
6587 if ( !_elements[i]->IsOut( line ))
6588 foundElems.insert( _elements[i]->_element );
6592 for (int i = 0; i < 8; i++)
6593 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6597 //================================================================================
6599 * \brief Construct the element box
6601 //================================================================================
6603 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6607 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6608 while ( nIt->more() )
6609 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6610 Enlarge( tolerance );
6615 //=======================================================================
6617 * \brief Implementation of search for the elements by point and
6618 * of classification of point in 2D mesh
6620 //=======================================================================
6622 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6624 SMESHDS_Mesh* _mesh;
6625 SMDS_ElemIteratorPtr _meshPartIt;
6626 ElementBndBoxTree* _ebbTree;
6627 SMESH_NodeSearcherImpl* _nodeSearcher;
6628 SMDSAbs_ElementType _elementType;
6630 bool _outerFacesFound;
6631 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6633 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6634 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6635 ~SMESH_ElementSearcherImpl()
6637 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6638 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6640 virtual int FindElementsByPoint(const gp_Pnt& point,
6641 SMDSAbs_ElementType type,
6642 vector< const SMDS_MeshElement* >& foundElements);
6643 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6645 void GetElementsNearLine( const gp_Ax1& line,
6646 SMDSAbs_ElementType type,
6647 vector< const SMDS_MeshElement* >& foundElems);
6648 double getTolerance();
6649 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6650 const double tolerance, double & param);
6651 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6652 bool isOuterBoundary(const SMDS_MeshElement* face) const
6654 return _outerFaces.empty() || _outerFaces.count(face);
6656 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6658 const SMDS_MeshElement* _face;
6660 bool _coincides; //!< the line lays in face plane
6661 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6662 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6664 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6667 TIDSortedElemSet _faces;
6668 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6669 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6673 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6675 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6676 << ", _coincides="<<i._coincides << ")";
6679 //=======================================================================
6681 * \brief define tolerance for search
6683 //=======================================================================
6685 double SMESH_ElementSearcherImpl::getTolerance()
6687 if ( _tolerance < 0 )
6689 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6692 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6694 double boxSize = _nodeSearcher->getTree()->maxSize();
6695 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6697 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6699 double boxSize = _ebbTree->maxSize();
6700 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6702 if ( _tolerance == 0 )
6704 // define tolerance by size of a most complex element
6705 int complexType = SMDSAbs_Volume;
6706 while ( complexType > SMDSAbs_All &&
6707 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6709 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6711 if ( complexType == int( SMDSAbs_Node ))
6713 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6715 if ( meshInfo.NbNodes() > 2 )
6716 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6720 SMDS_ElemIteratorPtr elemIt =
6721 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6722 const SMDS_MeshElement* elem = elemIt->next();
6723 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6724 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6726 while ( nodeIt->more() )
6728 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6729 elemSize = max( dist, elemSize );
6732 _tolerance = 1e-4 * elemSize;
6738 //================================================================================
6740 * \brief Find intersection of the line and an edge of face and return parameter on line
6742 //================================================================================
6744 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6745 const SMDS_MeshElement* face,
6752 GeomAPI_ExtremaCurveCurve anExtCC;
6753 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6755 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6756 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6758 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6759 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6760 anExtCC.Init( lineCurve, edge);
6761 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6763 Quantity_Parameter pl, pe;
6764 anExtCC.LowerDistanceParameters( pl, pe );
6766 if ( ++nbInts == 2 )
6770 if ( nbInts > 0 ) param /= nbInts;
6773 //================================================================================
6775 * \brief Find all faces belonging to the outer boundary of mesh
6777 //================================================================================
6779 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6781 if ( _outerFacesFound ) return;
6783 // Collect all outer faces by passing from one outer face to another via their links
6784 // and BTW find out if there are internal faces at all.
6786 // checked links and links where outer boundary meets internal one
6787 set< SMESH_TLink > visitedLinks, seamLinks;
6789 // links to treat with already visited faces sharing them
6790 list < TFaceLink > startLinks;
6792 // load startLinks with the first outerFace
6793 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6794 _outerFaces.insert( outerFace );
6796 TIDSortedElemSet emptySet;
6797 while ( !startLinks.empty() )
6799 const SMESH_TLink& link = startLinks.front()._link;
6800 TIDSortedElemSet& faces = startLinks.front()._faces;
6802 outerFace = *faces.begin();
6803 // find other faces sharing the link
6804 const SMDS_MeshElement* f;
6805 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6808 // select another outer face among the found
6809 const SMDS_MeshElement* outerFace2 = 0;
6810 if ( faces.size() == 2 )
6812 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6814 else if ( faces.size() > 2 )
6816 seamLinks.insert( link );
6818 // link direction within the outerFace
6819 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6820 SMESH_TNodeXYZ( link.node2()));
6821 int i1 = outerFace->GetNodeIndex( link.node1() );
6822 int i2 = outerFace->GetNodeIndex( link.node2() );
6823 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6824 if ( rev ) n1n2.Reverse();
6826 gp_XYZ ofNorm, fNorm;
6827 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6829 // direction from the link inside outerFace
6830 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6831 // sort all other faces by angle with the dirInOF
6832 map< double, const SMDS_MeshElement* > angle2Face;
6833 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6834 for ( ; face != faces.end(); ++face )
6836 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6838 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6839 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6840 if ( angle < 0 ) angle += 2*PI;
6841 angle2Face.insert( make_pair( angle, *face ));
6843 if ( !angle2Face.empty() )
6844 outerFace2 = angle2Face.begin()->second;
6847 // store the found outer face and add its links to continue seaching from
6850 _outerFaces.insert( outerFace );
6851 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6852 for ( int i = 0; i < nbNodes; ++i )
6854 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6855 if ( visitedLinks.insert( link2 ).second )
6856 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6859 startLinks.pop_front();
6861 _outerFacesFound = true;
6863 if ( !seamLinks.empty() )
6865 // There are internal boundaries touching the outher one,
6866 // find all faces of internal boundaries in order to find
6867 // faces of boundaries of holes, if any.
6872 _outerFaces.clear();
6876 //=======================================================================
6878 * \brief Find elements of given type where the given point is IN or ON.
6879 * Returns nb of found elements and elements them-selves.
6881 * 'ALL' type means elements of any type excluding nodes and 0D elements
6883 //=======================================================================
6885 int SMESH_ElementSearcherImpl::
6886 FindElementsByPoint(const gp_Pnt& point,
6887 SMDSAbs_ElementType type,
6888 vector< const SMDS_MeshElement* >& foundElements)
6890 foundElements.clear();
6892 double tolerance = getTolerance();
6894 // =================================================================================
6895 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6897 if ( !_nodeSearcher )
6898 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6900 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6901 if ( !closeNode ) return foundElements.size();
6903 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6904 return foundElements.size(); // to far from any node
6906 if ( type == SMDSAbs_Node )
6908 foundElements.push_back( closeNode );
6912 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6913 while ( elemIt->more() )
6914 foundElements.push_back( elemIt->next() );
6917 // =================================================================================
6918 else // elements more complex than 0D
6920 if ( !_ebbTree || _elementType != type )
6922 if ( _ebbTree ) delete _ebbTree;
6923 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6925 TIDSortedElemSet suspectElems;
6926 _ebbTree->getElementsNearPoint( point, suspectElems );
6927 TIDSortedElemSet::iterator elem = suspectElems.begin();
6928 for ( ; elem != suspectElems.end(); ++elem )
6929 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6930 foundElements.push_back( *elem );
6932 return foundElements.size();
6935 //================================================================================
6937 * \brief Classify the given point in the closed 2D mesh
6939 //================================================================================
6941 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6943 double tolerance = getTolerance();
6944 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6946 if ( _ebbTree ) delete _ebbTree;
6947 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6949 // Algo: analyse transition of a line starting at the point through mesh boundary;
6950 // try three lines parallel to axis of the coordinate system and perform rough
6951 // analysis. If solution is not clear perform thorough analysis.
6953 const int nbAxes = 3;
6954 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6955 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6956 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6957 multimap< int, int > nbInt2Axis; // to find the simplest case
6958 for ( int axis = 0; axis < nbAxes; ++axis )
6960 gp_Ax1 lineAxis( point, axisDir[axis]);
6961 gp_Lin line ( lineAxis );
6963 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6964 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6966 // Intersect faces with the line
6968 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6969 TIDSortedElemSet::iterator face = suspectFaces.begin();
6970 for ( ; face != suspectFaces.end(); ++face )
6974 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6975 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6977 // perform intersection
6978 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6979 if ( !intersection.IsDone() )
6981 if ( intersection.IsInQuadric() )
6983 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6985 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6987 gp_Pnt intersectionPoint = intersection.Point(1);
6988 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6989 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6992 // Analyse intersections roughly
6994 int nbInter = u2inters.size();
6998 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6999 if ( nbInter == 1 ) // not closed mesh
7000 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7002 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7005 if ( (f<0) == (l<0) )
7008 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
7009 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
7010 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7013 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
7015 if ( _outerFacesFound ) break; // pass to thorough analysis
7017 } // three attempts - loop on CS axes
7019 // Analyse intersections thoroughly.
7020 // We make two loops maximum, on the first one we only exclude touching intersections,
7021 // on the second, if situation is still unclear, we gather and use information on
7022 // position of faces (internal or outer). If faces position is already gathered,
7023 // we make the second loop right away.
7025 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
7027 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
7028 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
7030 int axis = nb_axis->second;
7031 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
7033 gp_Ax1 lineAxis( point, axisDir[axis]);
7034 gp_Lin line ( lineAxis );
7036 // add tangent intersections to u2inters
7038 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
7039 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
7040 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
7041 u2inters.insert(make_pair( param, *tgtInt ));
7042 tangentInters[ axis ].clear();
7044 // Count intersections before and after the point excluding touching ones.
7045 // If hasPositionInfo we count intersections of outer boundary only
7047 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
7048 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
7049 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
7050 bool ok = ! u_int1->second._coincides;
7051 while ( ok && u_int1 != u2inters.end() )
7053 double u = u_int1->first;
7054 bool touchingInt = false;
7055 if ( ++u_int2 != u2inters.end() )
7057 // skip intersections at the same point (if the line passes through edge or node)
7059 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
7065 // skip tangent intersections
7067 const SMDS_MeshElement* prevFace = u_int1->second._face;
7068 while ( ok && u_int2->second._coincides )
7070 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
7076 ok = ( u_int2 != u2inters.end() );
7081 // skip intersections at the same point after tangent intersections
7084 double u2 = u_int2->first;
7086 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
7092 // decide if we skipped a touching intersection
7093 if ( nbSamePnt + nbTgt > 0 )
7095 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
7096 map< double, TInters >::iterator u_int = u_int1;
7097 for ( ; u_int != u_int2; ++u_int )
7099 if ( u_int->second._coincides ) continue;
7100 double dot = u_int->second._faceNorm * line.Direction();
7101 if ( dot > maxDot ) maxDot = dot;
7102 if ( dot < minDot ) minDot = dot;
7104 touchingInt = ( minDot*maxDot < 0 );
7109 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
7120 u_int1 = u_int2; // to next intersection
7122 } // loop on intersections with one line
7126 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
7129 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
7132 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7133 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7135 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7138 if ( (f<0) == (l<0) )
7141 if ( hasPositionInfo )
7142 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7144 } // loop on intersections of the tree lines - thorough analysis
7146 if ( !hasPositionInfo )
7148 // gather info on faces position - is face in the outer boundary or not
7149 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7150 findOuterBoundary( u2inters.begin()->second._face );
7153 } // two attempts - with and w/o faces position info in the mesh
7155 return TopAbs_UNKNOWN;
7158 //=======================================================================
7160 * \brief Return elements possibly intersecting the line
7162 //=======================================================================
7164 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7165 SMDSAbs_ElementType type,
7166 vector< const SMDS_MeshElement* >& foundElems)
7168 if ( !_ebbTree || _elementType != type )
7170 if ( _ebbTree ) delete _ebbTree;
7171 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7173 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7174 _ebbTree->getElementsNearLine( line, suspectFaces );
7175 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7178 //=======================================================================
7180 * \brief Return SMESH_ElementSearcher
7182 //=======================================================================
7184 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7186 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7189 //=======================================================================
7191 * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
7193 //=======================================================================
7195 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7197 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7200 //=======================================================================
7202 * \brief Return true if the point is IN or ON of the element
7204 //=======================================================================
7206 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7208 if ( element->GetType() == SMDSAbs_Volume)
7210 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7213 // get ordered nodes
7215 vector< gp_XYZ > xyz;
7216 vector<const SMDS_MeshNode*> nodeList;
7218 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7219 if ( element->IsQuadratic() ) {
7220 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7221 nodeIt = f->interlacedNodesElemIterator();
7222 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7223 nodeIt = e->interlacedNodesElemIterator();
7225 while ( nodeIt->more() )
7227 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7228 xyz.push_back( SMESH_TNodeXYZ(node) );
7229 nodeList.push_back(node);
7232 int i, nbNodes = element->NbNodes();
7234 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7236 // compute face normal
7237 gp_Vec faceNorm(0,0,0);
7238 xyz.push_back( xyz.front() );
7239 nodeList.push_back( nodeList.front() );
7240 for ( i = 0; i < nbNodes; ++i )
7242 gp_Vec edge1( xyz[i+1], xyz[i]);
7243 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7244 faceNorm += edge1 ^ edge2;
7246 double normSize = faceNorm.Magnitude();
7247 if ( normSize <= tol )
7249 // degenerated face: point is out if it is out of all face edges
7250 for ( i = 0; i < nbNodes; ++i )
7252 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7253 if ( !isOut( &edge, point, tol ))
7258 faceNorm /= normSize;
7260 // check if the point lays on face plane
7261 gp_Vec n2p( xyz[0], point );
7262 if ( fabs( n2p * faceNorm ) > tol )
7263 return true; // not on face plane
7265 // check if point is out of face boundary:
7266 // define it by closest transition of a ray point->infinity through face boundary
7267 // on the face plane.
7268 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7269 // to find intersections of the ray with the boundary.
7271 gp_Vec plnNorm = ray ^ faceNorm;
7272 normSize = plnNorm.Magnitude();
7273 if ( normSize <= tol ) return false; // point coincides with the first node
7274 plnNorm /= normSize;
7275 // for each node of the face, compute its signed distance to the plane
7276 vector<double> dist( nbNodes + 1);
7277 for ( i = 0; i < nbNodes; ++i )
7279 gp_Vec n2p( xyz[i], point );
7280 dist[i] = n2p * plnNorm;
7282 dist.back() = dist.front();
7283 // find the closest intersection
7285 double rClosest, distClosest = 1e100;;
7287 for ( i = 0; i < nbNodes; ++i )
7290 if ( fabs( dist[i]) < tol )
7292 else if ( fabs( dist[i+1]) < tol )
7294 else if ( dist[i] * dist[i+1] < 0 )
7295 r = dist[i] / ( dist[i] - dist[i+1] );
7297 continue; // no intersection
7298 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7299 gp_Vec p2int ( point, pInt);
7300 if ( p2int * ray > -tol ) // right half-space
7302 double intDist = p2int.SquareMagnitude();
7303 if ( intDist < distClosest )
7308 distClosest = intDist;
7313 return true; // no intesections - out
7315 // analyse transition
7316 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7317 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7318 gp_Vec p2int ( point, pClosest );
7319 bool out = (edgeNorm * p2int) < -tol;
7320 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7323 // ray pass through a face node; analyze transition through an adjacent edge
7324 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7325 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7326 gp_Vec edgeAdjacent( p1, p2 );
7327 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7328 bool out2 = (edgeNorm2 * p2int) < -tol;
7330 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7331 return covexCorner ? (out || out2) : (out && out2);
7333 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7335 // point is out of edge if it is NOT ON any straight part of edge
7336 // (we consider quadratic edge as being composed of two straight parts)
7337 for ( i = 1; i < nbNodes; ++i )
7339 gp_Vec edge( xyz[i-1], xyz[i]);
7340 gp_Vec n1p ( xyz[i-1], point);
7341 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7344 gp_Vec n2p( xyz[i], point );
7345 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7347 return false; // point is ON this part
7351 // Node or 0D element -------------------------------------------------------------------------
7353 gp_Vec n2p ( xyz[0], point );
7354 return n2p.Magnitude() <= tol;
7359 //=======================================================================
7360 //function : SimplifyFace
7362 //=======================================================================
7363 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7364 vector<const SMDS_MeshNode *>& poly_nodes,
7365 vector<int>& quantities) const
7367 int nbNodes = faceNodes.size();
7372 set<const SMDS_MeshNode*> nodeSet;
7374 // get simple seq of nodes
7375 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7376 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7377 int iSimple = 0, nbUnique = 0;
7379 simpleNodes[iSimple++] = faceNodes[0];
7381 for (int iCur = 1; iCur < nbNodes; iCur++) {
7382 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7383 simpleNodes[iSimple++] = faceNodes[iCur];
7384 if (nodeSet.insert( faceNodes[iCur] ).second)
7388 int nbSimple = iSimple;
7389 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7399 bool foundLoop = (nbSimple > nbUnique);
7402 set<const SMDS_MeshNode*> loopSet;
7403 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7404 const SMDS_MeshNode* n = simpleNodes[iSimple];
7405 if (!loopSet.insert( n ).second) {
7409 int iC = 0, curLast = iSimple;
7410 for (; iC < curLast; iC++) {
7411 if (simpleNodes[iC] == n) break;
7413 int loopLen = curLast - iC;
7415 // create sub-element
7417 quantities.push_back(loopLen);
7418 for (; iC < curLast; iC++) {
7419 poly_nodes.push_back(simpleNodes[iC]);
7422 // shift the rest nodes (place from the first loop position)
7423 for (iC = curLast + 1; iC < nbSimple; iC++) {
7424 simpleNodes[iC - loopLen] = simpleNodes[iC];
7426 nbSimple -= loopLen;
7429 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7430 } // while (foundLoop)
7434 quantities.push_back(iSimple);
7435 for (int i = 0; i < iSimple; i++)
7436 poly_nodes.push_back(simpleNodes[i]);
7442 //=======================================================================
7443 //function : MergeNodes
7444 //purpose : In each group, the cdr of nodes are substituted by the first one
7446 //=======================================================================
7448 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7450 MESSAGE("MergeNodes");
7451 myLastCreatedElems.Clear();
7452 myLastCreatedNodes.Clear();
7454 SMESHDS_Mesh* aMesh = GetMeshDS();
7456 TNodeNodeMap nodeNodeMap; // node to replace - new node
7457 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7458 list< int > rmElemIds, rmNodeIds;
7460 // Fill nodeNodeMap and elems
7462 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7463 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7464 list<const SMDS_MeshNode*>& nodes = *grIt;
7465 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7466 const SMDS_MeshNode* nToKeep = *nIt;
7467 //MESSAGE("node to keep " << nToKeep->GetID());
7468 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7469 const SMDS_MeshNode* nToRemove = *nIt;
7470 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7471 if ( nToRemove != nToKeep ) {
7472 //MESSAGE(" node to remove " << nToRemove->GetID());
7473 rmNodeIds.push_back( nToRemove->GetID() );
7474 AddToSameGroups( nToKeep, nToRemove, aMesh );
7477 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7478 while ( invElemIt->more() ) {
7479 const SMDS_MeshElement* elem = invElemIt->next();
7484 // Change element nodes or remove an element
7486 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7487 for ( ; eIt != elems.end(); eIt++ ) {
7488 const SMDS_MeshElement* elem = *eIt;
7489 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7490 int nbNodes = elem->NbNodes();
7491 int aShapeId = FindShape( elem );
7493 set<const SMDS_MeshNode*> nodeSet;
7494 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7495 int iUnique = 0, iCur = 0, nbRepl = 0;
7496 vector<int> iRepl( nbNodes );
7498 // get new seq of nodes
7499 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7500 while ( itN->more() ) {
7501 const SMDS_MeshNode* n =
7502 static_cast<const SMDS_MeshNode*>( itN->next() );
7504 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7505 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7507 // BUG 0020185: begin
7509 bool stopRecur = false;
7510 set<const SMDS_MeshNode*> nodesRecur;
7511 nodesRecur.insert(n);
7512 while (!stopRecur) {
7513 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7514 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7515 n = (*nnIt_i).second;
7516 if (!nodesRecur.insert(n).second) {
7517 // error: recursive dependancy
7526 iRepl[ nbRepl++ ] = iCur;
7528 curNodes[ iCur ] = n;
7529 bool isUnique = nodeSet.insert( n ).second;
7531 uniqueNodes[ iUnique++ ] = n;
7532 if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7533 --nbRepl; // n do not stick to a node of the elem
7538 // Analyse element topology after replacement
7541 int nbUniqueNodes = nodeSet.size();
7542 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7543 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7544 // Polygons and Polyhedral volumes
7545 if (elem->IsPoly()) {
7547 if (elem->GetType() == SMDSAbs_Face) {
7549 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7551 for (; inode < nbNodes; inode++) {
7552 face_nodes[inode] = curNodes[inode];
7555 vector<const SMDS_MeshNode *> polygons_nodes;
7556 vector<int> quantities;
7557 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7560 for (int iface = 0; iface < nbNew; iface++) {
7561 int nbNodes = quantities[iface];
7562 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7563 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7564 poly_nodes[ii] = polygons_nodes[inode];
7566 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7567 myLastCreatedElems.Append(newElem);
7569 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7572 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7573 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7574 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7576 if (nbNew > 0) quid = nbNew - 1;
7577 vector<int> newquant(quantities.begin()+quid, quantities.end());
7578 const SMDS_MeshElement* newElem = 0;
7579 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7580 myLastCreatedElems.Append(newElem);
7581 if ( aShapeId && newElem )
7582 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7583 rmElemIds.push_back(elem->GetID());
7586 rmElemIds.push_back(elem->GetID());
7590 else if (elem->GetType() == SMDSAbs_Volume) {
7591 // Polyhedral volume
7592 if (nbUniqueNodes < 4) {
7593 rmElemIds.push_back(elem->GetID());
7596 // each face has to be analyzed in order to check volume validity
7597 const SMDS_VtkVolume* aPolyedre =
7598 dynamic_cast<const SMDS_VtkVolume*>( elem );
7600 int nbFaces = aPolyedre->NbFaces();
7602 vector<const SMDS_MeshNode *> poly_nodes;
7603 vector<int> quantities;
7605 for (int iface = 1; iface <= nbFaces; iface++) {
7606 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7607 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7609 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7610 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7611 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7612 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7613 faceNode = (*nnIt).second;
7615 faceNodes[inode - 1] = faceNode;
7618 SimplifyFace(faceNodes, poly_nodes, quantities);
7621 if (quantities.size() > 3) {
7622 // to be done: remove coincident faces
7625 if (quantities.size() > 3)
7627 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7628 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7629 const SMDS_MeshElement* newElem = 0;
7630 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7631 myLastCreatedElems.Append(newElem);
7632 if ( aShapeId && newElem )
7633 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7634 rmElemIds.push_back(elem->GetID());
7638 rmElemIds.push_back(elem->GetID());
7649 // TODO not all the possible cases are solved. Find something more generic?
7650 switch ( nbNodes ) {
7651 case 2: ///////////////////////////////////// EDGE
7652 isOk = false; break;
7653 case 3: ///////////////////////////////////// TRIANGLE
7654 isOk = false; break;
7656 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7658 else { //////////////////////////////////// QUADRANGLE
7659 if ( nbUniqueNodes < 3 )
7661 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7662 isOk = false; // opposite nodes stick
7663 //MESSAGE("isOk " << isOk);
7666 case 6: ///////////////////////////////////// PENTAHEDRON
7667 if ( nbUniqueNodes == 4 ) {
7668 // ---------------------------------> tetrahedron
7670 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7671 // all top nodes stick: reverse a bottom
7672 uniqueNodes[ 0 ] = curNodes [ 1 ];
7673 uniqueNodes[ 1 ] = curNodes [ 0 ];
7675 else if (nbRepl == 3 &&
7676 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7677 // all bottom nodes stick: set a top before
7678 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7679 uniqueNodes[ 0 ] = curNodes [ 3 ];
7680 uniqueNodes[ 1 ] = curNodes [ 4 ];
7681 uniqueNodes[ 2 ] = curNodes [ 5 ];
7683 else if (nbRepl == 4 &&
7684 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7685 // a lateral face turns into a line: reverse a bottom
7686 uniqueNodes[ 0 ] = curNodes [ 1 ];
7687 uniqueNodes[ 1 ] = curNodes [ 0 ];
7692 else if ( nbUniqueNodes == 5 ) {
7693 // PENTAHEDRON --------------------> 2 tetrahedrons
7694 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7695 // a bottom node sticks with a linked top one
7697 SMDS_MeshElement* newElem =
7698 aMesh->AddVolume(curNodes[ 3 ],
7701 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7702 myLastCreatedElems.Append(newElem);
7704 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7705 // 2. : reverse a bottom
7706 uniqueNodes[ 0 ] = curNodes [ 1 ];
7707 uniqueNodes[ 1 ] = curNodes [ 0 ];
7717 if(elem->IsQuadratic()) { // Quadratic quadrangle
7729 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7732 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7734 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7735 uniqueNodes[0] = curNodes[0];
7736 uniqueNodes[1] = curNodes[2];
7737 uniqueNodes[2] = curNodes[3];
7738 uniqueNodes[3] = curNodes[5];
7739 uniqueNodes[4] = curNodes[6];
7740 uniqueNodes[5] = curNodes[7];
7743 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7744 uniqueNodes[0] = curNodes[0];
7745 uniqueNodes[1] = curNodes[1];
7746 uniqueNodes[2] = curNodes[2];
7747 uniqueNodes[3] = curNodes[4];
7748 uniqueNodes[4] = curNodes[5];
7749 uniqueNodes[5] = curNodes[6];
7752 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7753 uniqueNodes[0] = curNodes[1];
7754 uniqueNodes[1] = curNodes[2];
7755 uniqueNodes[2] = curNodes[3];
7756 uniqueNodes[3] = curNodes[5];
7757 uniqueNodes[4] = curNodes[6];
7758 uniqueNodes[5] = curNodes[0];
7761 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7762 uniqueNodes[0] = curNodes[0];
7763 uniqueNodes[1] = curNodes[1];
7764 uniqueNodes[2] = curNodes[3];
7765 uniqueNodes[3] = curNodes[4];
7766 uniqueNodes[4] = curNodes[6];
7767 uniqueNodes[5] = curNodes[7];
7770 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7771 uniqueNodes[0] = curNodes[0];
7772 uniqueNodes[1] = curNodes[2];
7773 uniqueNodes[2] = curNodes[3];
7774 uniqueNodes[3] = curNodes[1];
7775 uniqueNodes[4] = curNodes[6];
7776 uniqueNodes[5] = curNodes[7];
7779 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7780 uniqueNodes[0] = curNodes[0];
7781 uniqueNodes[1] = curNodes[1];
7782 uniqueNodes[2] = curNodes[2];
7783 uniqueNodes[3] = curNodes[4];
7784 uniqueNodes[4] = curNodes[5];
7785 uniqueNodes[5] = curNodes[7];
7788 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7789 uniqueNodes[0] = curNodes[0];
7790 uniqueNodes[1] = curNodes[1];
7791 uniqueNodes[2] = curNodes[3];
7792 uniqueNodes[3] = curNodes[4];
7793 uniqueNodes[4] = curNodes[2];
7794 uniqueNodes[5] = curNodes[7];
7797 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7798 uniqueNodes[0] = curNodes[0];
7799 uniqueNodes[1] = curNodes[1];
7800 uniqueNodes[2] = curNodes[2];
7801 uniqueNodes[3] = curNodes[4];
7802 uniqueNodes[4] = curNodes[5];
7803 uniqueNodes[5] = curNodes[3];
7808 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7811 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7815 //////////////////////////////////// HEXAHEDRON
7817 SMDS_VolumeTool hexa (elem);
7818 hexa.SetExternalNormal();
7819 if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7820 //////////////////////// HEX ---> 1 tetrahedron
7821 for ( int iFace = 0; iFace < 6; iFace++ ) {
7822 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7823 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7824 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7825 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7826 // one face turns into a point ...
7827 int iOppFace = hexa.GetOppFaceIndex( iFace );
7828 ind = hexa.GetFaceNodesIndices( iOppFace );
7830 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7831 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7834 if ( nbStick == 1 ) {
7835 // ... and the opposite one - into a triangle.
7837 ind = hexa.GetFaceNodesIndices( iFace );
7838 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7845 else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7846 //////////////////////// HEX ---> 1 prism
7847 int nbTria = 0, iTria[3];
7848 const int *ind; // indices of face nodes
7849 // look for triangular faces
7850 for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7851 ind = hexa.GetFaceNodesIndices( iFace );
7852 TIDSortedNodeSet faceNodes;
7853 for ( iCur = 0; iCur < 4; iCur++ )
7854 faceNodes.insert( curNodes[ind[iCur]] );
7855 if ( faceNodes.size() == 3 )
7856 iTria[ nbTria++ ] = iFace;
7858 // check if triangles are opposite
7859 if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7862 // set nodes of the bottom triangle
7863 ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7865 for ( iCur = 0; iCur < 4; iCur++ )
7866 if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7867 indB.push_back( ind[iCur] );
7868 if ( !hexa.IsForward() )
7869 std::swap( indB[0], indB[2] );
7870 for ( iCur = 0; iCur < 3; iCur++ )
7871 uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7872 // set nodes of the top triangle
7873 const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7874 for ( iCur = 0; iCur < 3; ++iCur )
7875 for ( int j = 0; j < 4; ++j )
7876 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7878 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7884 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7885 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7886 for ( int iFace = 0; iFace < 6; iFace++ ) {
7887 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7888 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7889 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7890 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7891 // one face turns into a point ...
7892 int iOppFace = hexa.GetOppFaceIndex( iFace );
7893 ind = hexa.GetFaceNodesIndices( iOppFace );
7895 iUnique = 2; // reverse a tetrahedron 1 bottom
7896 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7897 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7899 else if ( iUnique >= 0 )
7900 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7902 if ( nbStick == 0 ) {
7903 // ... and the opposite one is a quadrangle
7905 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7906 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7909 SMDS_MeshElement* newElem =
7910 aMesh->AddVolume(curNodes[ind[ 0 ]],
7913 curNodes[indTop[ 0 ]]);
7914 myLastCreatedElems.Append(newElem);
7916 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7923 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7924 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7925 // find indices of quad and tri faces
7926 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7927 for ( iFace = 0; iFace < 6; iFace++ ) {
7928 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7930 for ( iCur = 0; iCur < 4; iCur++ )
7931 nodeSet.insert( curNodes[ind[ iCur ]] );
7932 nbUniqueNodes = nodeSet.size();
7933 if ( nbUniqueNodes == 3 )
7934 iTriFace[ nbTri++ ] = iFace;
7935 else if ( nbUniqueNodes == 4 )
7936 iQuadFace[ nbQuad++ ] = iFace;
7938 if (nbQuad == 2 && nbTri == 4 &&
7939 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7940 // 2 opposite quadrangles stuck with a diagonal;
7941 // sample groups of merged indices: (0-4)(2-6)
7942 // --------------------------------------------> 2 tetrahedrons
7943 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7944 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7945 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7946 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7947 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7948 // stuck with 0-2 diagonal
7956 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7957 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7958 // stuck with 1-3 diagonal
7970 uniqueNodes[ 0 ] = curNodes [ i0 ];
7971 uniqueNodes[ 1 ] = curNodes [ i1d ];
7972 uniqueNodes[ 2 ] = curNodes [ i3d ];
7973 uniqueNodes[ 3 ] = curNodes [ i0t ];
7976 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7980 myLastCreatedElems.Append(newElem);
7982 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7985 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7986 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7987 // --------------------------------------------> prism
7988 // find 2 opposite triangles
7990 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7991 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7992 // find indices of kept and replaced nodes
7993 // and fill unique nodes of 2 opposite triangles
7994 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7995 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7996 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7997 // fill unique nodes
8000 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
8001 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
8002 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
8004 // iCur of a linked node of the opposite face (make normals co-directed):
8005 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
8006 // check that correspondent corners of triangles are linked
8007 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
8010 uniqueNodes[ iUnique ] = n;
8011 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
8020 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
8023 MESSAGE("MergeNodes() removes hexahedron "<< elem);
8030 } // switch ( nbNodes )
8032 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
8034 if ( isOk ) { // the elem remains valid after sticking nodes
8035 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
8037 // Change nodes of polyedre
8038 const SMDS_VtkVolume* aPolyedre =
8039 dynamic_cast<const SMDS_VtkVolume*>( elem );
8041 int nbFaces = aPolyedre->NbFaces();
8043 vector<const SMDS_MeshNode *> poly_nodes;
8044 vector<int> quantities (nbFaces);
8046 for (int iface = 1; iface <= nbFaces; iface++) {
8047 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
8048 quantities[iface - 1] = nbFaceNodes;
8050 for (inode = 1; inode <= nbFaceNodes; inode++) {
8051 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
8053 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
8054 if (nnIt != nodeNodeMap.end()) { // curNode sticks
8055 curNode = (*nnIt).second;
8057 poly_nodes.push_back(curNode);
8060 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
8063 else // replace non-polyhedron elements
8065 const SMDSAbs_ElementType etyp = elem->GetType();
8066 const int elemId = elem->GetID();
8067 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
8068 uniqueNodes.resize(nbUniqueNodes);
8070 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
8072 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
8073 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
8074 if ( sm && newElem )
8075 sm->AddElement( newElem );
8076 if ( elem != newElem )
8077 ReplaceElemInGroups( elem, newElem, aMesh );
8081 // Remove invalid regular element or invalid polygon
8082 rmElemIds.push_back( elem->GetID() );
8085 } // loop on elements
8087 // Remove bad elements, then equal nodes (order important)
8089 Remove( rmElemIds, false );
8090 Remove( rmNodeIds, true );
8095 // ========================================================
8096 // class : SortableElement
8097 // purpose : allow sorting elements basing on their nodes
8098 // ========================================================
8099 class SortableElement : public set <const SMDS_MeshElement*>
8103 SortableElement( const SMDS_MeshElement* theElem )
8106 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
8107 while ( nodeIt->more() )
8108 this->insert( nodeIt->next() );
8111 const SMDS_MeshElement* Get() const
8114 void Set(const SMDS_MeshElement* e) const
8119 mutable const SMDS_MeshElement* myElem;
8122 //=======================================================================
8123 //function : FindEqualElements
8124 //purpose : Return list of group of elements built on the same nodes.
8125 // Search among theElements or in the whole mesh if theElements is empty
8126 //=======================================================================
8127 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
8128 TListOfListOfElementsID & theGroupsOfElementsID)
8130 myLastCreatedElems.Clear();
8131 myLastCreatedNodes.Clear();
8133 typedef set<const SMDS_MeshElement*> TElemsSet;
8134 typedef map< SortableElement, int > TMapOfNodeSet;
8135 typedef list<int> TGroupOfElems;
8138 if ( theElements.empty() )
8139 { // get all elements in the mesh
8140 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8141 while ( eIt->more() )
8142 elems.insert( elems.end(), eIt->next());
8145 elems = theElements;
8147 vector< TGroupOfElems > arrayOfGroups;
8148 TGroupOfElems groupOfElems;
8149 TMapOfNodeSet mapOfNodeSet;
8151 TElemsSet::iterator elemIt = elems.begin();
8152 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8153 const SMDS_MeshElement* curElem = *elemIt;
8154 SortableElement SE(curElem);
8157 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8158 if( !(pp.second) ) {
8159 TMapOfNodeSet::iterator& itSE = pp.first;
8160 ind = (*itSE).second;
8161 arrayOfGroups[ind].push_back(curElem->GetID());
8164 groupOfElems.clear();
8165 groupOfElems.push_back(curElem->GetID());
8166 arrayOfGroups.push_back(groupOfElems);
8171 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8172 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8173 groupOfElems = *groupIt;
8174 if ( groupOfElems.size() > 1 ) {
8175 groupOfElems.sort();
8176 theGroupsOfElementsID.push_back(groupOfElems);
8181 //=======================================================================
8182 //function : MergeElements
8183 //purpose : In each given group, substitute all elements by the first one.
8184 //=======================================================================
8186 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8188 myLastCreatedElems.Clear();
8189 myLastCreatedNodes.Clear();
8191 typedef list<int> TListOfIDs;
8192 TListOfIDs rmElemIds; // IDs of elems to remove
8194 SMESHDS_Mesh* aMesh = GetMeshDS();
8196 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8197 while ( groupsIt != theGroupsOfElementsID.end() ) {
8198 TListOfIDs& aGroupOfElemID = *groupsIt;
8199 aGroupOfElemID.sort();
8200 int elemIDToKeep = aGroupOfElemID.front();
8201 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8202 aGroupOfElemID.pop_front();
8203 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8204 while ( idIt != aGroupOfElemID.end() ) {
8205 int elemIDToRemove = *idIt;
8206 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8207 // add the kept element in groups of removed one (PAL15188)
8208 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8209 rmElemIds.push_back( elemIDToRemove );
8215 Remove( rmElemIds, false );
8218 //=======================================================================
8219 //function : MergeEqualElements
8220 //purpose : Remove all but one of elements built on the same nodes.
8221 //=======================================================================
8223 void SMESH_MeshEditor::MergeEqualElements()
8225 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8226 to merge equal elements in the whole mesh */
8227 TListOfListOfElementsID aGroupsOfElementsID;
8228 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8229 MergeElements(aGroupsOfElementsID);
8232 //=======================================================================
8233 //function : FindFaceInSet
8234 //purpose : Return a face having linked nodes n1 and n2 and which is
8235 // - not in avoidSet,
8236 // - in elemSet provided that !elemSet.empty()
8237 // i1 and i2 optionally returns indices of n1 and n2
8238 //=======================================================================
8240 const SMDS_MeshElement*
8241 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8242 const SMDS_MeshNode* n2,
8243 const TIDSortedElemSet& elemSet,
8244 const TIDSortedElemSet& avoidSet,
8250 const SMDS_MeshElement* face = 0;
8252 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8253 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8254 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8256 //MESSAGE("in while ( invElemIt->more() && !face )");
8257 const SMDS_MeshElement* elem = invElemIt->next();
8258 if (avoidSet.count( elem ))
8260 if ( !elemSet.empty() && !elemSet.count( elem ))
8263 i1 = elem->GetNodeIndex( n1 );
8264 // find a n2 linked to n1
8265 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8266 for ( int di = -1; di < 2 && !face; di += 2 )
8268 i2 = (i1+di+nbN) % nbN;
8269 if ( elem->GetNode( i2 ) == n2 )
8272 if ( !face && elem->IsQuadratic())
8274 // analysis for quadratic elements using all nodes
8275 const SMDS_VtkFace* F =
8276 dynamic_cast<const SMDS_VtkFace*>(elem);
8277 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8278 // use special nodes iterator
8279 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8280 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8281 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8283 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8284 if ( n1 == prevN && n2 == n )
8288 else if ( n2 == prevN && n1 == n )
8290 face = elem; swap( i1, i2 );
8296 if ( n1ind ) *n1ind = i1;
8297 if ( n2ind ) *n2ind = i2;
8301 //=======================================================================
8302 //function : findAdjacentFace
8304 //=======================================================================
8306 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8307 const SMDS_MeshNode* n2,
8308 const SMDS_MeshElement* elem)
8310 TIDSortedElemSet elemSet, avoidSet;
8312 avoidSet.insert ( elem );
8313 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8316 //=======================================================================
8317 //function : FindFreeBorder
8319 //=======================================================================
8321 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8323 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8324 const SMDS_MeshNode* theSecondNode,
8325 const SMDS_MeshNode* theLastNode,
8326 list< const SMDS_MeshNode* > & theNodes,
8327 list< const SMDS_MeshElement* >& theFaces)
8329 if ( !theFirstNode || !theSecondNode )
8331 // find border face between theFirstNode and theSecondNode
8332 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8336 theFaces.push_back( curElem );
8337 theNodes.push_back( theFirstNode );
8338 theNodes.push_back( theSecondNode );
8340 //vector<const SMDS_MeshNode*> nodes;
8341 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8342 TIDSortedElemSet foundElems;
8343 bool needTheLast = ( theLastNode != 0 );
8345 while ( nStart != theLastNode ) {
8346 if ( nStart == theFirstNode )
8347 return !needTheLast;
8349 // find all free border faces sharing form nStart
8351 list< const SMDS_MeshElement* > curElemList;
8352 list< const SMDS_MeshNode* > nStartList;
8353 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8354 while ( invElemIt->more() ) {
8355 const SMDS_MeshElement* e = invElemIt->next();
8356 if ( e == curElem || foundElems.insert( e ).second ) {
8358 int iNode = 0, nbNodes = e->NbNodes();
8359 //const SMDS_MeshNode* nodes[nbNodes+1];
8360 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8362 if(e->IsQuadratic()) {
8363 const SMDS_VtkFace* F =
8364 dynamic_cast<const SMDS_VtkFace*>(e);
8365 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8366 // use special nodes iterator
8367 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8368 while( anIter->more() ) {
8369 nodes[ iNode++ ] = cast2Node(anIter->next());
8373 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8374 while ( nIt->more() )
8375 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8377 nodes[ iNode ] = nodes[ 0 ];
8379 for ( iNode = 0; iNode < nbNodes; iNode++ )
8380 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8381 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8382 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8384 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8385 curElemList.push_back( e );
8389 // analyse the found
8391 int nbNewBorders = curElemList.size();
8392 if ( nbNewBorders == 0 ) {
8393 // no free border furthermore
8394 return !needTheLast;
8396 else if ( nbNewBorders == 1 ) {
8397 // one more element found
8399 nStart = nStartList.front();
8400 curElem = curElemList.front();
8401 theFaces.push_back( curElem );
8402 theNodes.push_back( nStart );
8405 // several continuations found
8406 list< const SMDS_MeshElement* >::iterator curElemIt;
8407 list< const SMDS_MeshNode* >::iterator nStartIt;
8408 // check if one of them reached the last node
8409 if ( needTheLast ) {
8410 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8411 curElemIt!= curElemList.end();
8412 curElemIt++, nStartIt++ )
8413 if ( *nStartIt == theLastNode ) {
8414 theFaces.push_back( *curElemIt );
8415 theNodes.push_back( *nStartIt );
8419 // find the best free border by the continuations
8420 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8421 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8422 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8423 curElemIt!= curElemList.end();
8424 curElemIt++, nStartIt++ )
8426 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8427 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8428 // find one more free border
8429 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8433 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8434 // choice: clear a worse one
8435 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8436 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8437 contNodes[ iWorse ].clear();
8438 contFaces[ iWorse ].clear();
8441 if ( contNodes[0].empty() && contNodes[1].empty() )
8444 // append the best free border
8445 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8446 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8447 theNodes.pop_back(); // remove nIgnore
8448 theNodes.pop_back(); // remove nStart
8449 theFaces.pop_back(); // remove curElem
8450 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8451 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8452 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8453 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8456 } // several continuations found
8457 } // while ( nStart != theLastNode )
8462 //=======================================================================
8463 //function : CheckFreeBorderNodes
8464 //purpose : Return true if the tree nodes are on a free border
8465 //=======================================================================
8467 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8468 const SMDS_MeshNode* theNode2,
8469 const SMDS_MeshNode* theNode3)
8471 list< const SMDS_MeshNode* > nodes;
8472 list< const SMDS_MeshElement* > faces;
8473 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8476 //=======================================================================
8477 //function : SewFreeBorder
8479 //=======================================================================
8481 SMESH_MeshEditor::Sew_Error
8482 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8483 const SMDS_MeshNode* theBordSecondNode,
8484 const SMDS_MeshNode* theBordLastNode,
8485 const SMDS_MeshNode* theSideFirstNode,
8486 const SMDS_MeshNode* theSideSecondNode,
8487 const SMDS_MeshNode* theSideThirdNode,
8488 const bool theSideIsFreeBorder,
8489 const bool toCreatePolygons,
8490 const bool toCreatePolyedrs)
8492 myLastCreatedElems.Clear();
8493 myLastCreatedNodes.Clear();
8495 MESSAGE("::SewFreeBorder()");
8496 Sew_Error aResult = SEW_OK;
8498 // ====================================
8499 // find side nodes and elements
8500 // ====================================
8502 list< const SMDS_MeshNode* > nSide[ 2 ];
8503 list< const SMDS_MeshElement* > eSide[ 2 ];
8504 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8505 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8509 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8510 nSide[0], eSide[0])) {
8511 MESSAGE(" Free Border 1 not found " );
8512 aResult = SEW_BORDER1_NOT_FOUND;
8514 if (theSideIsFreeBorder) {
8517 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8518 nSide[1], eSide[1])) {
8519 MESSAGE(" Free Border 2 not found " );
8520 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8523 if ( aResult != SEW_OK )
8526 if (!theSideIsFreeBorder) {
8530 // -------------------------------------------------------------------------
8532 // 1. If nodes to merge are not coincident, move nodes of the free border
8533 // from the coord sys defined by the direction from the first to last
8534 // nodes of the border to the correspondent sys of the side 2
8535 // 2. On the side 2, find the links most co-directed with the correspondent
8536 // links of the free border
8537 // -------------------------------------------------------------------------
8539 // 1. Since sewing may break if there are volumes to split on the side 2,
8540 // we wont move nodes but just compute new coordinates for them
8541 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8542 TNodeXYZMap nBordXYZ;
8543 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8544 list< const SMDS_MeshNode* >::iterator nBordIt;
8546 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8547 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8548 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8549 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8550 double tol2 = 1.e-8;
8551 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8552 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8553 // Need node movement.
8555 // find X and Z axes to create trsf
8556 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8558 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8560 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8563 gp_Ax3 toBordAx( Pb1, Zb, X );
8564 gp_Ax3 fromSideAx( Ps1, Zs, X );
8565 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8567 gp_Trsf toBordSys, fromSide2Sys;
8568 toBordSys.SetTransformation( toBordAx );
8569 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8570 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8573 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8574 const SMDS_MeshNode* n = *nBordIt;
8575 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8576 toBordSys.Transforms( xyz );
8577 fromSide2Sys.Transforms( xyz );
8578 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8582 // just insert nodes XYZ in the nBordXYZ map
8583 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8584 const SMDS_MeshNode* n = *nBordIt;
8585 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8589 // 2. On the side 2, find the links most co-directed with the correspondent
8590 // links of the free border
8592 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8593 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8594 sideNodes.push_back( theSideFirstNode );
8596 bool hasVolumes = false;
8597 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8598 set<long> foundSideLinkIDs, checkedLinkIDs;
8599 SMDS_VolumeTool volume;
8600 //const SMDS_MeshNode* faceNodes[ 4 ];
8602 const SMDS_MeshNode* sideNode;
8603 const SMDS_MeshElement* sideElem;
8604 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8605 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8606 nBordIt = bordNodes.begin();
8608 // border node position and border link direction to compare with
8609 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8610 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8611 // choose next side node by link direction or by closeness to
8612 // the current border node:
8613 bool searchByDir = ( *nBordIt != theBordLastNode );
8615 // find the next node on the Side 2
8617 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8619 checkedLinkIDs.clear();
8620 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8622 // loop on inverse elements of current node (prevSideNode) on the Side 2
8623 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8624 while ( invElemIt->more() )
8626 const SMDS_MeshElement* elem = invElemIt->next();
8627 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8628 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8629 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8630 bool isVolume = volume.Set( elem );
8631 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8632 if ( isVolume ) // --volume
8634 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8635 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8636 if(elem->IsQuadratic()) {
8637 const SMDS_VtkFace* F =
8638 dynamic_cast<const SMDS_VtkFace*>(elem);
8639 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8640 // use special nodes iterator
8641 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8642 while( anIter->more() ) {
8643 nodes[ iNode ] = cast2Node(anIter->next());
8644 if ( nodes[ iNode++ ] == prevSideNode )
8645 iPrevNode = iNode - 1;
8649 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8650 while ( nIt->more() ) {
8651 nodes[ iNode ] = cast2Node( nIt->next() );
8652 if ( nodes[ iNode++ ] == prevSideNode )
8653 iPrevNode = iNode - 1;
8656 // there are 2 links to check
8661 // loop on links, to be precise, on the second node of links
8662 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8663 const SMDS_MeshNode* n = nodes[ iNode ];
8665 if ( !volume.IsLinked( n, prevSideNode ))
8669 if ( iNode ) // a node before prevSideNode
8670 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8671 else // a node after prevSideNode
8672 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8674 // check if this link was already used
8675 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8676 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8677 if (!isJustChecked &&
8678 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8680 // test a link geometrically
8681 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8682 bool linkIsBetter = false;
8683 double dot = 0.0, dist = 0.0;
8684 if ( searchByDir ) { // choose most co-directed link
8685 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8686 linkIsBetter = ( dot > maxDot );
8688 else { // choose link with the node closest to bordPos
8689 dist = ( nextXYZ - bordPos ).SquareModulus();
8690 linkIsBetter = ( dist < minDist );
8692 if ( linkIsBetter ) {
8701 } // loop on inverse elements of prevSideNode
8704 MESSAGE(" Cant find path by links of the Side 2 ");
8705 return SEW_BAD_SIDE_NODES;
8707 sideNodes.push_back( sideNode );
8708 sideElems.push_back( sideElem );
8709 foundSideLinkIDs.insert ( linkID );
8710 prevSideNode = sideNode;
8712 if ( *nBordIt == theBordLastNode )
8713 searchByDir = false;
8715 // find the next border link to compare with
8716 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8717 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8718 // move to next border node if sideNode is before forward border node (bordPos)
8719 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8720 prevBordNode = *nBordIt;
8722 bordPos = nBordXYZ[ *nBordIt ];
8723 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8724 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8728 while ( sideNode != theSideSecondNode );
8730 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8731 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8732 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8734 } // end nodes search on the side 2
8736 // ============================
8737 // sew the border to the side 2
8738 // ============================
8740 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8741 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8743 TListOfListOfNodes nodeGroupsToMerge;
8744 if ( nbNodes[0] == nbNodes[1] ||
8745 ( theSideIsFreeBorder && !theSideThirdNode)) {
8747 // all nodes are to be merged
8749 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8750 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8751 nIt[0]++, nIt[1]++ )
8753 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8754 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8755 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8760 // insert new nodes into the border and the side to get equal nb of segments
8762 // get normalized parameters of nodes on the borders
8763 //double param[ 2 ][ maxNbNodes ];
8765 param[0] = new double [ maxNbNodes ];
8766 param[1] = new double [ maxNbNodes ];
8768 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8769 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8770 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8771 const SMDS_MeshNode* nPrev = *nIt;
8772 double bordLength = 0;
8773 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8774 const SMDS_MeshNode* nCur = *nIt;
8775 gp_XYZ segment (nCur->X() - nPrev->X(),
8776 nCur->Y() - nPrev->Y(),
8777 nCur->Z() - nPrev->Z());
8778 double segmentLen = segment.Modulus();
8779 bordLength += segmentLen;
8780 param[ iBord ][ iNode ] = bordLength;
8783 // normalize within [0,1]
8784 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8785 param[ iBord ][ iNode ] /= bordLength;
8789 // loop on border segments
8790 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8791 int i[ 2 ] = { 0, 0 };
8792 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8793 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8795 TElemOfNodeListMap insertMap;
8796 TElemOfNodeListMap::iterator insertMapIt;
8798 // key: elem to insert nodes into
8799 // value: 2 nodes to insert between + nodes to be inserted
8801 bool next[ 2 ] = { false, false };
8803 // find min adjacent segment length after sewing
8804 double nextParam = 10., prevParam = 0;
8805 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8806 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8807 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8808 if ( i[ iBord ] > 0 )
8809 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8811 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8812 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8813 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8815 // choose to insert or to merge nodes
8816 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8817 if ( Abs( du ) <= minSegLen * 0.2 ) {
8820 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8821 const SMDS_MeshNode* n0 = *nIt[0];
8822 const SMDS_MeshNode* n1 = *nIt[1];
8823 nodeGroupsToMerge.back().push_back( n1 );
8824 nodeGroupsToMerge.back().push_back( n0 );
8825 // position of node of the border changes due to merge
8826 param[ 0 ][ i[0] ] += du;
8827 // move n1 for the sake of elem shape evaluation during insertion.
8828 // n1 will be removed by MergeNodes() anyway
8829 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8830 next[0] = next[1] = true;
8835 int intoBord = ( du < 0 ) ? 0 : 1;
8836 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8837 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8838 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8839 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8840 if ( intoBord == 1 ) {
8841 // move node of the border to be on a link of elem of the side
8842 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8843 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8844 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8845 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8846 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8848 insertMapIt = insertMap.find( elem );
8849 bool notFound = ( insertMapIt == insertMap.end() );
8850 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8852 // insert into another link of the same element:
8853 // 1. perform insertion into the other link of the elem
8854 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8855 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8856 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8857 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8858 // 2. perform insertion into the link of adjacent faces
8860 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8862 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8866 if (toCreatePolyedrs) {
8867 // perform insertion into the links of adjacent volumes
8868 UpdateVolumes(n12, n22, nodeList);
8870 // 3. find an element appeared on n1 and n2 after the insertion
8871 insertMap.erase( elem );
8872 elem = findAdjacentFace( n1, n2, 0 );
8874 if ( notFound || otherLink ) {
8875 // add element and nodes of the side into the insertMap
8876 insertMapIt = insertMap.insert
8877 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8878 (*insertMapIt).second.push_back( n1 );
8879 (*insertMapIt).second.push_back( n2 );
8881 // add node to be inserted into elem
8882 (*insertMapIt).second.push_back( nIns );
8883 next[ 1 - intoBord ] = true;
8886 // go to the next segment
8887 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8888 if ( next[ iBord ] ) {
8889 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8891 nPrev[ iBord ] = *nIt[ iBord ];
8892 nIt[ iBord ]++; i[ iBord ]++;
8896 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8898 // perform insertion of nodes into elements
8900 for (insertMapIt = insertMap.begin();
8901 insertMapIt != insertMap.end();
8904 const SMDS_MeshElement* elem = (*insertMapIt).first;
8905 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8906 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8907 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8909 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8911 if ( !theSideIsFreeBorder ) {
8912 // look for and insert nodes into the faces adjacent to elem
8914 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8916 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8921 if (toCreatePolyedrs) {
8922 // perform insertion into the links of adjacent volumes
8923 UpdateVolumes(n1, n2, nodeList);
8929 } // end: insert new nodes
8931 MergeNodes ( nodeGroupsToMerge );
8936 //=======================================================================
8937 //function : InsertNodesIntoLink
8938 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8939 // and theBetweenNode2 and split theElement
8940 //=======================================================================
8942 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8943 const SMDS_MeshNode* theBetweenNode1,
8944 const SMDS_MeshNode* theBetweenNode2,
8945 list<const SMDS_MeshNode*>& theNodesToInsert,
8946 const bool toCreatePoly)
8948 if ( theFace->GetType() != SMDSAbs_Face ) return;
8950 // find indices of 2 link nodes and of the rest nodes
8951 int iNode = 0, il1, il2, i3, i4;
8952 il1 = il2 = i3 = i4 = -1;
8953 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8954 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8956 if(theFace->IsQuadratic()) {
8957 const SMDS_VtkFace* F =
8958 dynamic_cast<const SMDS_VtkFace*>(theFace);
8959 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8960 // use special nodes iterator
8961 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8962 while( anIter->more() ) {
8963 const SMDS_MeshNode* n = cast2Node(anIter->next());
8964 if ( n == theBetweenNode1 )
8966 else if ( n == theBetweenNode2 )
8972 nodes[ iNode++ ] = n;
8976 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8977 while ( nodeIt->more() ) {
8978 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8979 if ( n == theBetweenNode1 )
8981 else if ( n == theBetweenNode2 )
8987 nodes[ iNode++ ] = n;
8990 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8993 // arrange link nodes to go one after another regarding the face orientation
8994 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8995 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
9000 aNodesToInsert.reverse();
9002 // check that not link nodes of a quadrangles are in good order
9003 int nbFaceNodes = theFace->NbNodes();
9004 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
9010 if (toCreatePoly || theFace->IsPoly()) {
9013 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
9015 // add nodes of face up to first node of link
9018 if(theFace->IsQuadratic()) {
9019 const SMDS_VtkFace* F =
9020 dynamic_cast<const SMDS_VtkFace*>(theFace);
9021 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
9022 // use special nodes iterator
9023 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
9024 while( anIter->more() && !isFLN ) {
9025 const SMDS_MeshNode* n = cast2Node(anIter->next());
9026 poly_nodes[iNode++] = n;
9027 if (n == nodes[il1]) {
9031 // add nodes to insert
9032 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9033 for (; nIt != aNodesToInsert.end(); nIt++) {
9034 poly_nodes[iNode++] = *nIt;
9036 // add nodes of face starting from last node of link
9037 while ( anIter->more() ) {
9038 poly_nodes[iNode++] = cast2Node(anIter->next());
9042 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
9043 while ( nodeIt->more() && !isFLN ) {
9044 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9045 poly_nodes[iNode++] = n;
9046 if (n == nodes[il1]) {
9050 // add nodes to insert
9051 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9052 for (; nIt != aNodesToInsert.end(); nIt++) {
9053 poly_nodes[iNode++] = *nIt;
9055 // add nodes of face starting from last node of link
9056 while ( nodeIt->more() ) {
9057 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9058 poly_nodes[iNode++] = n;
9062 // edit or replace the face
9063 SMESHDS_Mesh *aMesh = GetMeshDS();
9065 if (theFace->IsPoly()) {
9066 aMesh->ChangePolygonNodes(theFace, poly_nodes);
9069 int aShapeId = FindShape( theFace );
9071 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
9072 myLastCreatedElems.Append(newElem);
9073 if ( aShapeId && newElem )
9074 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9076 aMesh->RemoveElement(theFace);
9081 SMESHDS_Mesh *aMesh = GetMeshDS();
9082 if( !theFace->IsQuadratic() ) {
9084 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
9085 int nbLinkNodes = 2 + aNodesToInsert.size();
9086 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
9087 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
9088 linkNodes[ 0 ] = nodes[ il1 ];
9089 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
9090 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9091 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9092 linkNodes[ iNode++ ] = *nIt;
9094 // decide how to split a quadrangle: compare possible variants
9095 // and choose which of splits to be a quadrangle
9096 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
9097 if ( nbFaceNodes == 3 ) {
9098 iBestQuad = nbSplits;
9101 else if ( nbFaceNodes == 4 ) {
9102 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
9103 double aBestRate = DBL_MAX;
9104 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
9106 double aBadRate = 0;
9107 // evaluate elements quality
9108 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
9109 if ( iSplit == iQuad ) {
9110 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
9114 aBadRate += getBadRate( &quad, aCrit );
9117 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
9119 nodes[ iSplit < iQuad ? i4 : i3 ]);
9120 aBadRate += getBadRate( &tria, aCrit );
9124 if ( aBadRate < aBestRate ) {
9126 aBestRate = aBadRate;
9131 // create new elements
9132 int aShapeId = FindShape( theFace );
9135 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
9136 SMDS_MeshElement* newElem = 0;
9137 if ( iSplit == iBestQuad )
9138 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9143 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9145 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9146 myLastCreatedElems.Append(newElem);
9147 if ( aShapeId && newElem )
9148 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9151 // change nodes of theFace
9152 const SMDS_MeshNode* newNodes[ 4 ];
9153 newNodes[ 0 ] = linkNodes[ i1 ];
9154 newNodes[ 1 ] = linkNodes[ i2 ];
9155 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9156 newNodes[ 3 ] = nodes[ i4 ];
9157 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9158 const SMDS_MeshElement* newElem = 0;
9159 if (iSplit == iBestQuad)
9160 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9162 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9163 myLastCreatedElems.Append(newElem);
9164 if ( aShapeId && newElem )
9165 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9166 } // end if(!theFace->IsQuadratic())
9167 else { // theFace is quadratic
9168 // we have to split theFace on simple triangles and one simple quadrangle
9170 int nbshift = tmp*2;
9171 // shift nodes in nodes[] by nbshift
9173 for(i=0; i<nbshift; i++) {
9174 const SMDS_MeshNode* n = nodes[0];
9175 for(j=0; j<nbFaceNodes-1; j++) {
9176 nodes[j] = nodes[j+1];
9178 nodes[nbFaceNodes-1] = n;
9180 il1 = il1 - nbshift;
9181 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9182 // n0 n1 n2 n0 n1 n2
9183 // +-----+-----+ +-----+-----+
9192 // create new elements
9193 int aShapeId = FindShape( theFace );
9196 if(nbFaceNodes==6) { // quadratic triangle
9197 SMDS_MeshElement* newElem =
9198 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9199 myLastCreatedElems.Append(newElem);
9200 if ( aShapeId && newElem )
9201 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9202 if(theFace->IsMediumNode(nodes[il1])) {
9203 // create quadrangle
9204 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9205 myLastCreatedElems.Append(newElem);
9206 if ( aShapeId && newElem )
9207 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9213 // create quadrangle
9214 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9215 myLastCreatedElems.Append(newElem);
9216 if ( aShapeId && newElem )
9217 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9223 else { // nbFaceNodes==8 - quadratic quadrangle
9224 SMDS_MeshElement* newElem =
9225 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9226 myLastCreatedElems.Append(newElem);
9227 if ( aShapeId && newElem )
9228 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9229 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9230 myLastCreatedElems.Append(newElem);
9231 if ( aShapeId && newElem )
9232 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9233 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9234 myLastCreatedElems.Append(newElem);
9235 if ( aShapeId && newElem )
9236 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9237 if(theFace->IsMediumNode(nodes[il1])) {
9238 // create quadrangle
9239 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9240 myLastCreatedElems.Append(newElem);
9241 if ( aShapeId && newElem )
9242 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9248 // create quadrangle
9249 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9250 myLastCreatedElems.Append(newElem);
9251 if ( aShapeId && newElem )
9252 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9258 // create needed triangles using n1,n2,n3 and inserted nodes
9259 int nbn = 2 + aNodesToInsert.size();
9260 //const SMDS_MeshNode* aNodes[nbn];
9261 vector<const SMDS_MeshNode*> aNodes(nbn);
9262 aNodes[0] = nodes[n1];
9263 aNodes[nbn-1] = nodes[n2];
9264 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9265 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9266 aNodes[iNode++] = *nIt;
9268 for(i=1; i<nbn; i++) {
9269 SMDS_MeshElement* newElem =
9270 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9271 myLastCreatedElems.Append(newElem);
9272 if ( aShapeId && newElem )
9273 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9277 aMesh->RemoveElement(theFace);
9280 //=======================================================================
9281 //function : UpdateVolumes
9283 //=======================================================================
9284 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9285 const SMDS_MeshNode* theBetweenNode2,
9286 list<const SMDS_MeshNode*>& theNodesToInsert)
9288 myLastCreatedElems.Clear();
9289 myLastCreatedNodes.Clear();
9291 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9292 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9293 const SMDS_MeshElement* elem = invElemIt->next();
9295 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9296 SMDS_VolumeTool aVolume (elem);
9297 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9300 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9301 int iface, nbFaces = aVolume.NbFaces();
9302 vector<const SMDS_MeshNode *> poly_nodes;
9303 vector<int> quantities (nbFaces);
9305 for (iface = 0; iface < nbFaces; iface++) {
9306 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9307 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9308 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9310 for (int inode = 0; inode < nbFaceNodes; inode++) {
9311 poly_nodes.push_back(faceNodes[inode]);
9313 if (nbInserted == 0) {
9314 if (faceNodes[inode] == theBetweenNode1) {
9315 if (faceNodes[inode + 1] == theBetweenNode2) {
9316 nbInserted = theNodesToInsert.size();
9318 // add nodes to insert
9319 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9320 for (; nIt != theNodesToInsert.end(); nIt++) {
9321 poly_nodes.push_back(*nIt);
9325 else if (faceNodes[inode] == theBetweenNode2) {
9326 if (faceNodes[inode + 1] == theBetweenNode1) {
9327 nbInserted = theNodesToInsert.size();
9329 // add nodes to insert in reversed order
9330 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9332 for (; nIt != theNodesToInsert.begin(); nIt--) {
9333 poly_nodes.push_back(*nIt);
9335 poly_nodes.push_back(*nIt);
9342 quantities[iface] = nbFaceNodes + nbInserted;
9345 // Replace or update the volume
9346 SMESHDS_Mesh *aMesh = GetMeshDS();
9348 if (elem->IsPoly()) {
9349 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9353 int aShapeId = FindShape( elem );
9355 SMDS_MeshElement* newElem =
9356 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9357 myLastCreatedElems.Append(newElem);
9358 if (aShapeId && newElem)
9359 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9361 aMesh->RemoveElement(elem);
9366 //=======================================================================
9368 * \brief Convert elements contained in a submesh to quadratic
9369 * \return int - nb of checked elements
9371 //=======================================================================
9373 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9374 SMESH_MesherHelper& theHelper,
9375 const bool theForce3d)
9378 if( !theSm ) return nbElem;
9380 vector<int> nbNodeInFaces;
9381 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9382 while(ElemItr->more())
9385 const SMDS_MeshElement* elem = ElemItr->next();
9386 if( !elem || elem->IsQuadratic() ) continue;
9388 int id = elem->GetID();
9389 int nbNodes = elem->NbNodes();
9390 SMDSAbs_ElementType aType = elem->GetType();
9392 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9393 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9394 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9396 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9398 const SMDS_MeshElement* NewElem = 0;
9404 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9412 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9415 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9418 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9423 case SMDSAbs_Volume :
9428 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9431 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9434 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9437 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9438 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9441 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9448 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9450 theSm->AddElement( NewElem );
9452 // if (!GetMeshDS()->isCompacted())
9453 // GetMeshDS()->compactMesh();
9457 //=======================================================================
9458 //function : ConvertToQuadratic
9460 //=======================================================================
9461 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9463 SMESHDS_Mesh* meshDS = GetMeshDS();
9465 SMESH_MesherHelper aHelper(*myMesh);
9466 aHelper.SetIsQuadratic( true );
9468 int nbCheckedElems = 0;
9469 if ( myMesh->HasShapeToMesh() )
9471 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9473 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9474 while ( smIt->more() ) {
9475 SMESH_subMesh* sm = smIt->next();
9476 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9477 aHelper.SetSubShape( sm->GetSubShape() );
9478 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9483 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9484 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9486 SMESHDS_SubMesh *smDS = 0;
9487 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9488 while(aEdgeItr->more())
9490 const SMDS_MeshEdge* edge = aEdgeItr->next();
9491 if(edge && !edge->IsQuadratic())
9493 int id = edge->GetID();
9494 //MESSAGE("edge->GetID() " << id);
9495 const SMDS_MeshNode* n1 = edge->GetNode(0);
9496 const SMDS_MeshNode* n2 = edge->GetNode(1);
9498 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9500 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9501 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9504 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9505 while(aFaceItr->more())
9507 const SMDS_MeshFace* face = aFaceItr->next();
9508 if(!face || face->IsQuadratic() ) continue;
9510 int id = face->GetID();
9511 int nbNodes = face->NbNodes();
9512 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9514 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9516 SMDS_MeshFace * NewFace = 0;
9520 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9523 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9526 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9528 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9530 vector<int> nbNodeInFaces;
9531 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9532 while(aVolumeItr->more())
9534 const SMDS_MeshVolume* volume = aVolumeItr->next();
9535 if(!volume || volume->IsQuadratic() ) continue;
9537 int id = volume->GetID();
9538 int nbNodes = volume->NbNodes();
9539 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9540 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9541 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9543 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9545 SMDS_MeshVolume * NewVolume = 0;
9549 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9550 nodes[3], id, theForce3d );
9553 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9554 nodes[3], nodes[4], id, theForce3d);
9557 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9558 nodes[3], nodes[4], nodes[5], id, theForce3d);
9561 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9562 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9565 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9567 ReplaceElemInGroups(volume, NewVolume, meshDS);
9572 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9573 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9574 aHelper.FixQuadraticElements();
9578 //================================================================================
9580 * \brief Makes given elements quadratic
9581 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9582 * \param theElements - elements to make quadratic
9584 //================================================================================
9586 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9587 TIDSortedElemSet& theElements)
9589 if ( theElements.empty() ) return;
9591 // we believe that all theElements are of the same type
9592 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9594 // get all nodes shared by theElements
9595 TIDSortedNodeSet allNodes;
9596 TIDSortedElemSet::iterator eIt = theElements.begin();
9597 for ( ; eIt != theElements.end(); ++eIt )
9598 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9600 // complete theElements with elements of lower dim whose all nodes are in allNodes
9602 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9603 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9604 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9605 for ( ; nIt != allNodes.end(); ++nIt )
9607 const SMDS_MeshNode* n = *nIt;
9608 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9609 while ( invIt->more() )
9611 const SMDS_MeshElement* e = invIt->next();
9612 if ( e->IsQuadratic() )
9614 quadAdjacentElems[ e->GetType() ].insert( e );
9617 if ( e->GetType() >= elemType )
9619 continue; // same type of more complex linear element
9622 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9623 continue; // e is already checked
9627 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9628 while ( nodeIt->more() && allIn )
9629 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9631 theElements.insert(e );
9635 SMESH_MesherHelper helper(*myMesh);
9636 helper.SetIsQuadratic( true );
9638 // add links of quadratic adjacent elements to the helper
9640 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9641 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9642 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9644 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9646 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9647 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9648 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9650 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9652 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9653 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9654 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9656 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9659 // make quadratic elements instead of linear ones
9661 SMESHDS_Mesh* meshDS = GetMeshDS();
9662 SMESHDS_SubMesh* smDS = 0;
9663 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9665 const SMDS_MeshElement* elem = *eIt;
9666 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9669 int id = elem->GetID();
9670 SMDSAbs_ElementType type = elem->GetType();
9671 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9673 if ( !smDS || !smDS->Contains( elem ))
9674 smDS = meshDS->MeshElements( elem->getshapeId() );
9675 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9677 SMDS_MeshElement * newElem = 0;
9678 switch( nodes.size() )
9680 case 4: // cases for most multiple element types go first (for optimization)
9681 if ( type == SMDSAbs_Volume )
9682 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9684 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9687 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9688 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9691 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9694 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9697 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9698 nodes[4], id, theForce3d);
9701 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9702 nodes[4], nodes[5], id, theForce3d);
9706 ReplaceElemInGroups( elem, newElem, meshDS);
9707 if( newElem && smDS )
9708 smDS->AddElement( newElem );
9711 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9712 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9713 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9714 helper.FixQuadraticElements();
9718 //=======================================================================
9720 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9721 * \return int - nb of checked elements
9723 //=======================================================================
9725 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9726 SMDS_ElemIteratorPtr theItr,
9727 const int theShapeID)
9730 SMESHDS_Mesh* meshDS = GetMeshDS();
9732 while( theItr->more() )
9734 const SMDS_MeshElement* elem = theItr->next();
9736 if( elem && elem->IsQuadratic())
9738 int id = elem->GetID();
9739 int nbCornerNodes = elem->NbCornerNodes();
9740 SMDSAbs_ElementType aType = elem->GetType();
9742 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9744 //remove a quadratic element
9745 if ( !theSm || !theSm->Contains( elem ))
9746 theSm = meshDS->MeshElements( elem->getshapeId() );
9747 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9749 // remove medium nodes
9750 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9751 if ( nodes[i]->NbInverseElements() == 0 )
9752 meshDS->RemoveFreeNode( nodes[i], theSm );
9754 // add a linear element
9755 nodes.resize( nbCornerNodes );
9756 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9757 ReplaceElemInGroups(elem, newElem, meshDS);
9758 if( theSm && newElem )
9759 theSm->AddElement( newElem );
9765 //=======================================================================
9766 //function : ConvertFromQuadratic
9768 //=======================================================================
9770 bool SMESH_MeshEditor::ConvertFromQuadratic()
9772 int nbCheckedElems = 0;
9773 if ( myMesh->HasShapeToMesh() )
9775 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9777 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9778 while ( smIt->more() ) {
9779 SMESH_subMesh* sm = smIt->next();
9780 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9781 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9787 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9788 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9790 SMESHDS_SubMesh *aSM = 0;
9791 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9799 //================================================================================
9801 * \brief Return true if all medium nodes of the element are in the node set
9803 //================================================================================
9805 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9807 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9808 if ( !nodeSet.count( elem->GetNode(i) ))
9814 //================================================================================
9816 * \brief Makes given elements linear
9818 //================================================================================
9820 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9822 if ( theElements.empty() ) return;
9824 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9825 set<int> mediumNodeIDs;
9826 TIDSortedElemSet::iterator eIt = theElements.begin();
9827 for ( ; eIt != theElements.end(); ++eIt )
9829 const SMDS_MeshElement* e = *eIt;
9830 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9831 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9834 // replace given elements by linear ones
9835 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9836 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9837 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9839 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9840 // except those elements sharing medium nodes of quadratic element whose medium nodes
9841 // are not all in mediumNodeIDs
9843 // get remaining medium nodes
9844 TIDSortedNodeSet mediumNodes;
9845 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9846 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9847 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9848 mediumNodes.insert( mediumNodes.end(), n );
9850 // find more quadratic elements to convert
9851 TIDSortedElemSet moreElemsToConvert;
9852 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9853 for ( ; nIt != mediumNodes.end(); ++nIt )
9855 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9856 while ( invIt->more() )
9858 const SMDS_MeshElement* e = invIt->next();
9859 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9861 // find a more complex element including e and
9862 // whose medium nodes are not in mediumNodes
9863 bool complexFound = false;
9864 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9866 SMDS_ElemIteratorPtr invIt2 =
9867 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9868 while ( invIt2->more() )
9870 const SMDS_MeshElement* eComplex = invIt2->next();
9871 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9873 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9874 if ( nbCommonNodes == e->NbNodes())
9876 complexFound = true;
9877 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9883 if ( !complexFound )
9884 moreElemsToConvert.insert( e );
9888 elemIt = SMDS_ElemIteratorPtr
9889 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9890 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9893 //=======================================================================
9894 //function : SewSideElements
9896 //=======================================================================
9898 SMESH_MeshEditor::Sew_Error
9899 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9900 TIDSortedElemSet& theSide2,
9901 const SMDS_MeshNode* theFirstNode1,
9902 const SMDS_MeshNode* theFirstNode2,
9903 const SMDS_MeshNode* theSecondNode1,
9904 const SMDS_MeshNode* theSecondNode2)
9906 myLastCreatedElems.Clear();
9907 myLastCreatedNodes.Clear();
9909 MESSAGE ("::::SewSideElements()");
9910 if ( theSide1.size() != theSide2.size() )
9911 return SEW_DIFF_NB_OF_ELEMENTS;
9913 Sew_Error aResult = SEW_OK;
9915 // 1. Build set of faces representing each side
9916 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9917 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9919 // =======================================================================
9920 // 1. Build set of faces representing each side:
9921 // =======================================================================
9922 // a. build set of nodes belonging to faces
9923 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9924 // c. create temporary faces representing side of volumes if correspondent
9925 // face does not exist
9927 SMESHDS_Mesh* aMesh = GetMeshDS();
9928 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9929 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9930 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9931 set<const SMDS_MeshElement*> volSet1, volSet2;
9932 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9933 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9934 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9935 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9936 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9937 int iSide, iFace, iNode;
9939 list<const SMDS_MeshElement* > tempFaceList;
9940 for ( iSide = 0; iSide < 2; iSide++ ) {
9941 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9942 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9943 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9944 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9945 set<const SMDS_MeshElement*>::iterator vIt;
9946 TIDSortedElemSet::iterator eIt;
9947 set<const SMDS_MeshNode*>::iterator nIt;
9949 // check that given nodes belong to given elements
9950 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9951 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9952 int firstIndex = -1, secondIndex = -1;
9953 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9954 const SMDS_MeshElement* elem = *eIt;
9955 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9956 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9957 if ( firstIndex > -1 && secondIndex > -1 ) break;
9959 if ( firstIndex < 0 || secondIndex < 0 ) {
9960 // we can simply return until temporary faces created
9961 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9964 // -----------------------------------------------------------
9965 // 1a. Collect nodes of existing faces
9966 // and build set of face nodes in order to detect missing
9967 // faces corresponding to sides of volumes
9968 // -----------------------------------------------------------
9970 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9972 // loop on the given element of a side
9973 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9974 //const SMDS_MeshElement* elem = *eIt;
9975 const SMDS_MeshElement* elem = *eIt;
9976 if ( elem->GetType() == SMDSAbs_Face ) {
9977 faceSet->insert( elem );
9978 set <const SMDS_MeshNode*> faceNodeSet;
9979 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9980 while ( nodeIt->more() ) {
9981 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9982 nodeSet->insert( n );
9983 faceNodeSet.insert( n );
9985 setOfFaceNodeSet.insert( faceNodeSet );
9987 else if ( elem->GetType() == SMDSAbs_Volume )
9988 volSet->insert( elem );
9990 // ------------------------------------------------------------------------------
9991 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9992 // ------------------------------------------------------------------------------
9994 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9995 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9996 while ( fIt->more() ) { // loop on faces sharing a node
9997 const SMDS_MeshElement* f = fIt->next();
9998 if ( faceSet->find( f ) == faceSet->end() ) {
9999 // check if all nodes are in nodeSet and
10000 // complete setOfFaceNodeSet if they are
10001 set <const SMDS_MeshNode*> faceNodeSet;
10002 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10003 bool allInSet = true;
10004 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10005 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10006 if ( nodeSet->find( n ) == nodeSet->end() )
10009 faceNodeSet.insert( n );
10012 faceSet->insert( f );
10013 setOfFaceNodeSet.insert( faceNodeSet );
10019 // -------------------------------------------------------------------------
10020 // 1c. Create temporary faces representing sides of volumes if correspondent
10021 // face does not exist
10022 // -------------------------------------------------------------------------
10024 if ( !volSet->empty() ) {
10025 //int nodeSetSize = nodeSet->size();
10027 // loop on given volumes
10028 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
10029 SMDS_VolumeTool vol (*vIt);
10030 // loop on volume faces: find free faces
10031 // --------------------------------------
10032 list<const SMDS_MeshElement* > freeFaceList;
10033 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
10034 if ( !vol.IsFreeFace( iFace ))
10036 // check if there is already a face with same nodes in a face set
10037 const SMDS_MeshElement* aFreeFace = 0;
10038 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
10039 int nbNodes = vol.NbFaceNodes( iFace );
10040 set <const SMDS_MeshNode*> faceNodeSet;
10041 vol.GetFaceNodes( iFace, faceNodeSet );
10042 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
10044 // no such a face is given but it still can exist, check it
10045 if ( nbNodes == 3 ) {
10046 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
10048 else if ( nbNodes == 4 ) {
10049 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10052 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10053 aFreeFace = aMesh->FindFace(poly_nodes);
10056 if ( !aFreeFace ) {
10057 // create a temporary face
10058 if ( nbNodes == 3 ) {
10059 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
10060 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
10062 else if ( nbNodes == 4 ) {
10063 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10064 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
10067 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
10068 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
10069 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
10073 freeFaceList.push_back( aFreeFace );
10074 tempFaceList.push_back( aFreeFace );
10077 } // loop on faces of a volume
10079 // choose one of several free faces
10080 // --------------------------------------
10081 if ( freeFaceList.size() > 1 ) {
10082 // choose a face having max nb of nodes shared by other elems of a side
10083 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
10084 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
10085 while ( fIt != freeFaceList.end() ) { // loop on free faces
10086 int nbSharedNodes = 0;
10087 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10088 while ( nodeIt->more() ) { // loop on free face nodes
10089 const SMDS_MeshNode* n =
10090 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10091 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
10092 while ( invElemIt->more() ) {
10093 const SMDS_MeshElement* e = invElemIt->next();
10094 if ( faceSet->find( e ) != faceSet->end() )
10096 if ( elemSet->find( e ) != elemSet->end() )
10100 if ( nbSharedNodes >= maxNbNodes ) {
10101 maxNbNodes = nbSharedNodes;
10105 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
10107 if ( freeFaceList.size() > 1 )
10109 // could not choose one face, use another way
10110 // choose a face most close to the bary center of the opposite side
10111 gp_XYZ aBC( 0., 0., 0. );
10112 set <const SMDS_MeshNode*> addedNodes;
10113 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
10114 eIt = elemSet2->begin();
10115 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
10116 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
10117 while ( nodeIt->more() ) { // loop on free face nodes
10118 const SMDS_MeshNode* n =
10119 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10120 if ( addedNodes.insert( n ).second )
10121 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
10124 aBC /= addedNodes.size();
10125 double minDist = DBL_MAX;
10126 fIt = freeFaceList.begin();
10127 while ( fIt != freeFaceList.end() ) { // loop on free faces
10129 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
10130 while ( nodeIt->more() ) { // loop on free face nodes
10131 const SMDS_MeshNode* n =
10132 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10133 gp_XYZ p( n->X(),n->Y(),n->Z() );
10134 dist += ( aBC - p ).SquareModulus();
10136 if ( dist < minDist ) {
10138 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10141 fIt = freeFaceList.erase( fIt++ );
10144 } // choose one of several free faces of a volume
10146 if ( freeFaceList.size() == 1 ) {
10147 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10148 faceSet->insert( aFreeFace );
10149 // complete a node set with nodes of a found free face
10150 // for ( iNode = 0; iNode < ; iNode++ )
10151 // nodeSet->insert( fNodes[ iNode ] );
10154 } // loop on volumes of a side
10156 // // complete a set of faces if new nodes in a nodeSet appeared
10157 // // ----------------------------------------------------------
10158 // if ( nodeSetSize != nodeSet->size() ) {
10159 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10160 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10161 // while ( fIt->more() ) { // loop on faces sharing a node
10162 // const SMDS_MeshElement* f = fIt->next();
10163 // if ( faceSet->find( f ) == faceSet->end() ) {
10164 // // check if all nodes are in nodeSet and
10165 // // complete setOfFaceNodeSet if they are
10166 // set <const SMDS_MeshNode*> faceNodeSet;
10167 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10168 // bool allInSet = true;
10169 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10170 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10171 // if ( nodeSet->find( n ) == nodeSet->end() )
10172 // allInSet = false;
10174 // faceNodeSet.insert( n );
10176 // if ( allInSet ) {
10177 // faceSet->insert( f );
10178 // setOfFaceNodeSet.insert( faceNodeSet );
10184 } // Create temporary faces, if there are volumes given
10187 if ( faceSet1.size() != faceSet2.size() ) {
10188 // delete temporary faces: they are in reverseElements of actual nodes
10189 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10190 // while ( tmpFaceIt->more() )
10191 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10192 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10193 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10194 // aMesh->RemoveElement(*tmpFaceIt);
10195 MESSAGE("Diff nb of faces");
10196 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10199 // ============================================================
10200 // 2. Find nodes to merge:
10201 // bind a node to remove to a node to put instead
10202 // ============================================================
10204 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10205 if ( theFirstNode1 != theFirstNode2 )
10206 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10207 if ( theSecondNode1 != theSecondNode2 )
10208 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10210 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10211 set< long > linkIdSet; // links to process
10212 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10214 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10215 list< NLink > linkList[2];
10216 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10217 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10218 // loop on links in linkList; find faces by links and append links
10219 // of the found faces to linkList
10220 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10221 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10222 NLink link[] = { *linkIt[0], *linkIt[1] };
10223 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10224 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10227 // by links, find faces in the face sets,
10228 // and find indices of link nodes in the found faces;
10229 // in a face set, there is only one or no face sharing a link
10230 // ---------------------------------------------------------------
10232 const SMDS_MeshElement* face[] = { 0, 0 };
10233 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10234 vector<const SMDS_MeshNode*> fnodes1(9);
10235 vector<const SMDS_MeshNode*> fnodes2(9);
10236 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10237 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10238 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10239 int iLinkNode[2][2];
10240 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10241 const SMDS_MeshNode* n1 = link[iSide].first;
10242 const SMDS_MeshNode* n2 = link[iSide].second;
10243 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10244 set< const SMDS_MeshElement* > fMap;
10245 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10246 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10247 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10248 while ( fIt->more() ) { // loop on faces sharing a node
10249 const SMDS_MeshElement* f = fIt->next();
10250 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10251 ! fMap.insert( f ).second ) // f encounters twice
10253 if ( face[ iSide ] ) {
10254 MESSAGE( "2 faces per link " );
10255 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10259 faceSet->erase( f );
10260 // get face nodes and find ones of a link
10265 fnodes1.resize(f->NbNodes()+1);
10266 notLinkNodes1.resize(f->NbNodes()-2);
10269 fnodes2.resize(f->NbNodes()+1);
10270 notLinkNodes2.resize(f->NbNodes()-2);
10273 if(!f->IsQuadratic()) {
10274 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10275 while ( nIt->more() ) {
10276 const SMDS_MeshNode* n =
10277 static_cast<const SMDS_MeshNode*>( nIt->next() );
10279 iLinkNode[ iSide ][ 0 ] = iNode;
10281 else if ( n == n2 ) {
10282 iLinkNode[ iSide ][ 1 ] = iNode;
10284 //else if ( notLinkNodes[ iSide ][ 0 ] )
10285 // notLinkNodes[ iSide ][ 1 ] = n;
10287 // notLinkNodes[ iSide ][ 0 ] = n;
10291 notLinkNodes1[nbl] = n;
10292 //notLinkNodes1.push_back(n);
10294 notLinkNodes2[nbl] = n;
10295 //notLinkNodes2.push_back(n);
10297 //faceNodes[ iSide ][ iNode++ ] = n;
10299 fnodes1[iNode++] = n;
10302 fnodes2[iNode++] = n;
10306 else { // f->IsQuadratic()
10307 const SMDS_VtkFace* F =
10308 dynamic_cast<const SMDS_VtkFace*>(f);
10309 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10310 // use special nodes iterator
10311 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10312 while ( anIter->more() ) {
10313 const SMDS_MeshNode* n =
10314 static_cast<const SMDS_MeshNode*>( anIter->next() );
10316 iLinkNode[ iSide ][ 0 ] = iNode;
10318 else if ( n == n2 ) {
10319 iLinkNode[ iSide ][ 1 ] = iNode;
10324 notLinkNodes1[nbl] = n;
10327 notLinkNodes2[nbl] = n;
10331 fnodes1[iNode++] = n;
10334 fnodes2[iNode++] = n;
10338 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10340 fnodes1[iNode] = fnodes1[0];
10343 fnodes2[iNode] = fnodes1[0];
10350 // check similarity of elements of the sides
10351 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10352 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10353 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10354 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10357 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10359 break; // do not return because it s necessary to remove tmp faces
10362 // set nodes to merge
10363 // -------------------
10365 if ( face[0] && face[1] ) {
10366 int nbNodes = face[0]->NbNodes();
10367 if ( nbNodes != face[1]->NbNodes() ) {
10368 MESSAGE("Diff nb of face nodes");
10369 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10370 break; // do not return because it s necessary to remove tmp faces
10372 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10373 if ( nbNodes == 3 ) {
10374 //nReplaceMap.insert( TNodeNodeMap::value_type
10375 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10376 nReplaceMap.insert( TNodeNodeMap::value_type
10377 ( notLinkNodes1[0], notLinkNodes2[0] ));
10380 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10381 // analyse link orientation in faces
10382 int i1 = iLinkNode[ iSide ][ 0 ];
10383 int i2 = iLinkNode[ iSide ][ 1 ];
10384 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10385 // if notLinkNodes are the first and the last ones, then
10386 // their order does not correspond to the link orientation
10387 if (( i1 == 1 && i2 == 2 ) ||
10388 ( i1 == 2 && i2 == 1 ))
10389 reverse[ iSide ] = !reverse[ iSide ];
10391 if ( reverse[0] == reverse[1] ) {
10392 //nReplaceMap.insert( TNodeNodeMap::value_type
10393 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10394 //nReplaceMap.insert( TNodeNodeMap::value_type
10395 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10396 for(int nn=0; nn<nbNodes-2; nn++) {
10397 nReplaceMap.insert( TNodeNodeMap::value_type
10398 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10402 //nReplaceMap.insert( TNodeNodeMap::value_type
10403 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10404 //nReplaceMap.insert( TNodeNodeMap::value_type
10405 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10406 for(int nn=0; nn<nbNodes-2; nn++) {
10407 nReplaceMap.insert( TNodeNodeMap::value_type
10408 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10413 // add other links of the faces to linkList
10414 // -----------------------------------------
10416 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10417 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10418 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10419 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10420 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10421 if ( !iter_isnew.second ) { // already in a set: no need to process
10422 linkIdSet.erase( iter_isnew.first );
10424 else // new in set == encountered for the first time: add
10426 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10427 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10428 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10429 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10430 linkList[0].push_back ( NLink( n1, n2 ));
10431 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10435 } // loop on link lists
10437 if ( aResult == SEW_OK &&
10438 ( linkIt[0] != linkList[0].end() ||
10439 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10440 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10441 " " << (faceSetPtr[1]->empty()));
10442 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10445 // ====================================================================
10446 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10447 // ====================================================================
10449 // delete temporary faces: they are in reverseElements of actual nodes
10450 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10451 // while ( tmpFaceIt->more() )
10452 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10453 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10454 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10455 // aMesh->RemoveElement(*tmpFaceIt);
10457 if ( aResult != SEW_OK)
10460 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10461 // loop on nodes replacement map
10462 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10463 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10464 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10465 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10466 nodeIDsToRemove.push_back( nToRemove->GetID() );
10467 // loop on elements sharing nToRemove
10468 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10469 while ( invElemIt->more() ) {
10470 const SMDS_MeshElement* e = invElemIt->next();
10471 // get a new suite of nodes: make replacement
10472 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10473 vector< const SMDS_MeshNode*> nodes( nbNodes );
10474 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10475 while ( nIt->more() ) {
10476 const SMDS_MeshNode* n =
10477 static_cast<const SMDS_MeshNode*>( nIt->next() );
10478 nnIt = nReplaceMap.find( n );
10479 if ( nnIt != nReplaceMap.end() ) {
10481 n = (*nnIt).second;
10485 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10486 // elemIDsToRemove.push_back( e->GetID() );
10490 SMDSAbs_ElementType etyp = e->GetType();
10491 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10494 myLastCreatedElems.Append(newElem);
10495 AddToSameGroups(newElem, e, aMesh);
10496 int aShapeId = e->getshapeId();
10499 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10502 aMesh->RemoveElement(e);
10507 Remove( nodeIDsToRemove, true );
10512 //================================================================================
10514 * \brief Find corresponding nodes in two sets of faces
10515 * \param theSide1 - first face set
10516 * \param theSide2 - second first face
10517 * \param theFirstNode1 - a boundary node of set 1
10518 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10519 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10520 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10521 * \param nReplaceMap - output map of corresponding nodes
10522 * \return bool - is a success or not
10524 //================================================================================
10527 //#define DEBUG_MATCHING_NODES
10530 SMESH_MeshEditor::Sew_Error
10531 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10532 set<const SMDS_MeshElement*>& theSide2,
10533 const SMDS_MeshNode* theFirstNode1,
10534 const SMDS_MeshNode* theFirstNode2,
10535 const SMDS_MeshNode* theSecondNode1,
10536 const SMDS_MeshNode* theSecondNode2,
10537 TNodeNodeMap & nReplaceMap)
10539 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10541 nReplaceMap.clear();
10542 if ( theFirstNode1 != theFirstNode2 )
10543 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10544 if ( theSecondNode1 != theSecondNode2 )
10545 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10547 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10548 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10550 list< NLink > linkList[2];
10551 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10552 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10554 // loop on links in linkList; find faces by links and append links
10555 // of the found faces to linkList
10556 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10557 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10558 NLink link[] = { *linkIt[0], *linkIt[1] };
10559 if ( linkSet.find( link[0] ) == linkSet.end() )
10562 // by links, find faces in the face sets,
10563 // and find indices of link nodes in the found faces;
10564 // in a face set, there is only one or no face sharing a link
10565 // ---------------------------------------------------------------
10567 const SMDS_MeshElement* face[] = { 0, 0 };
10568 list<const SMDS_MeshNode*> notLinkNodes[2];
10569 //bool reverse[] = { false, false }; // order of notLinkNodes
10571 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10573 const SMDS_MeshNode* n1 = link[iSide].first;
10574 const SMDS_MeshNode* n2 = link[iSide].second;
10575 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10576 set< const SMDS_MeshElement* > facesOfNode1;
10577 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10579 // during a loop of the first node, we find all faces around n1,
10580 // during a loop of the second node, we find one face sharing both n1 and n2
10581 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10582 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10583 while ( fIt->more() ) { // loop on faces sharing a node
10584 const SMDS_MeshElement* f = fIt->next();
10585 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10586 ! facesOfNode1.insert( f ).second ) // f encounters twice
10588 if ( face[ iSide ] ) {
10589 MESSAGE( "2 faces per link " );
10590 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10593 faceSet->erase( f );
10595 // get not link nodes
10596 int nbN = f->NbNodes();
10597 if ( f->IsQuadratic() )
10599 nbNodes[ iSide ] = nbN;
10600 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10601 int i1 = f->GetNodeIndex( n1 );
10602 int i2 = f->GetNodeIndex( n2 );
10603 int iEnd = nbN, iBeg = -1, iDelta = 1;
10604 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10606 std::swap( iEnd, iBeg ); iDelta = -1;
10611 if ( i == iEnd ) i = iBeg + iDelta;
10612 if ( i == i1 ) break;
10613 nodes.push_back ( f->GetNode( i ) );
10619 // check similarity of elements of the sides
10620 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10621 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10622 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10623 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10626 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10630 // set nodes to merge
10631 // -------------------
10633 if ( face[0] && face[1] ) {
10634 if ( nbNodes[0] != nbNodes[1] ) {
10635 MESSAGE("Diff nb of face nodes");
10636 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10638 #ifdef DEBUG_MATCHING_NODES
10639 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10640 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10641 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10643 int nbN = nbNodes[0];
10645 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10646 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10647 for ( int i = 0 ; i < nbN - 2; ++i ) {
10648 #ifdef DEBUG_MATCHING_NODES
10649 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10651 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10655 // add other links of the face 1 to linkList
10656 // -----------------------------------------
10658 const SMDS_MeshElement* f0 = face[0];
10659 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10660 for ( int i = 0; i < nbN; i++ )
10662 const SMDS_MeshNode* n2 = f0->GetNode( i );
10663 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10664 linkSet.insert( SMESH_TLink( n1, n2 ));
10665 if ( !iter_isnew.second ) { // already in a set: no need to process
10666 linkSet.erase( iter_isnew.first );
10668 else // new in set == encountered for the first time: add
10670 #ifdef DEBUG_MATCHING_NODES
10671 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10672 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10674 linkList[0].push_back ( NLink( n1, n2 ));
10675 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10680 } // loop on link lists
10685 //================================================================================
10687 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10688 \param theElems - the list of elements (edges or faces) to be replicated
10689 The nodes for duplication could be found from these elements
10690 \param theNodesNot - list of nodes to NOT replicate
10691 \param theAffectedElems - the list of elements (cells and edges) to which the
10692 replicated nodes should be associated to.
10693 \return TRUE if operation has been completed successfully, FALSE otherwise
10695 //================================================================================
10697 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10698 const TIDSortedElemSet& theNodesNot,
10699 const TIDSortedElemSet& theAffectedElems )
10701 myLastCreatedElems.Clear();
10702 myLastCreatedNodes.Clear();
10704 if ( theElems.size() == 0 )
10707 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10712 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10713 // duplicate elements and nodes
10714 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10715 // replce nodes by duplications
10716 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10720 //================================================================================
10722 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10723 \param theMeshDS - mesh instance
10724 \param theElems - the elements replicated or modified (nodes should be changed)
10725 \param theNodesNot - nodes to NOT replicate
10726 \param theNodeNodeMap - relation of old node to new created node
10727 \param theIsDoubleElem - flag os to replicate element or modify
10728 \return TRUE if operation has been completed successfully, FALSE otherwise
10730 //================================================================================
10732 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10733 const TIDSortedElemSet& theElems,
10734 const TIDSortedElemSet& theNodesNot,
10735 std::map< const SMDS_MeshNode*,
10736 const SMDS_MeshNode* >& theNodeNodeMap,
10737 const bool theIsDoubleElem )
10739 MESSAGE("doubleNodes");
10740 // iterate on through element and duplicate them (by nodes duplication)
10742 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10743 for ( ; elemItr != theElems.end(); ++elemItr )
10745 const SMDS_MeshElement* anElem = *elemItr;
10749 bool isDuplicate = false;
10750 // duplicate nodes to duplicate element
10751 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10752 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10754 while ( anIter->more() )
10757 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10758 SMDS_MeshNode* aNewNode = aCurrNode;
10759 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10760 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10761 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10764 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10765 theNodeNodeMap[ aCurrNode ] = aNewNode;
10766 myLastCreatedNodes.Append( aNewNode );
10768 isDuplicate |= (aCurrNode != aNewNode);
10769 newNodes[ ind++ ] = aNewNode;
10771 if ( !isDuplicate )
10774 if ( theIsDoubleElem )
10775 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10778 MESSAGE("ChangeElementNodes");
10779 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10786 //================================================================================
10788 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10789 \param theNodes - identifiers of nodes to be doubled
10790 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10791 nodes. If list of element identifiers is empty then nodes are doubled but
10792 they not assigned to elements
10793 \return TRUE if operation has been completed successfully, FALSE otherwise
10795 //================================================================================
10797 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10798 const std::list< int >& theListOfModifiedElems )
10800 MESSAGE("DoubleNodes");
10801 myLastCreatedElems.Clear();
10802 myLastCreatedNodes.Clear();
10804 if ( theListOfNodes.size() == 0 )
10807 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10811 // iterate through nodes and duplicate them
10813 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10815 std::list< int >::const_iterator aNodeIter;
10816 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10818 int aCurr = *aNodeIter;
10819 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10825 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10828 anOldNodeToNewNode[ aNode ] = aNewNode;
10829 myLastCreatedNodes.Append( aNewNode );
10833 // Create map of new nodes for modified elements
10835 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10837 std::list< int >::const_iterator anElemIter;
10838 for ( anElemIter = theListOfModifiedElems.begin();
10839 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10841 int aCurr = *anElemIter;
10842 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10846 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10848 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10850 while ( anIter->more() )
10852 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10853 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10855 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10856 aNodeArr[ ind++ ] = aNewNode;
10859 aNodeArr[ ind++ ] = aCurrNode;
10861 anElemToNodes[ anElem ] = aNodeArr;
10864 // Change nodes of elements
10866 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10867 anElemToNodesIter = anElemToNodes.begin();
10868 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10870 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10871 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10874 MESSAGE("ChangeElementNodes");
10875 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10884 //================================================================================
10886 \brief Check if element located inside shape
10887 \return TRUE if IN or ON shape, FALSE otherwise
10889 //================================================================================
10891 template<class Classifier>
10892 bool isInside(const SMDS_MeshElement* theElem,
10893 Classifier& theClassifier,
10894 const double theTol)
10896 gp_XYZ centerXYZ (0, 0, 0);
10897 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10898 while (aNodeItr->more())
10899 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10901 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10902 theClassifier.Perform(aPnt, theTol);
10903 TopAbs_State aState = theClassifier.State();
10904 return (aState == TopAbs_IN || aState == TopAbs_ON );
10907 //================================================================================
10909 * \brief Classifier of the 3D point on the TopoDS_Face
10910 * with interaface suitable for isInside()
10912 //================================================================================
10914 struct _FaceClassifier
10916 Extrema_ExtPS _extremum;
10917 BRepAdaptor_Surface _surface;
10918 TopAbs_State _state;
10920 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10922 _extremum.Initialize( _surface,
10923 _surface.FirstUParameter(), _surface.LastUParameter(),
10924 _surface.FirstVParameter(), _surface.LastVParameter(),
10925 _surface.Tolerance(), _surface.Tolerance() );
10927 void Perform(const gp_Pnt& aPnt, double theTol)
10929 _state = TopAbs_OUT;
10930 _extremum.Perform(aPnt);
10931 if ( _extremum.IsDone() )
10932 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10933 #if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
10934 _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10936 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10939 TopAbs_State State() const
10946 //================================================================================
10948 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10949 \param theElems - group of of elements (edges or faces) to be replicated
10950 \param theNodesNot - group of nodes not to replicate
10951 \param theShape - shape to detect affected elements (element which geometric center
10952 located on or inside shape).
10953 The replicated nodes should be associated to affected elements.
10954 \return TRUE if operation has been completed successfully, FALSE otherwise
10956 //================================================================================
10958 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10959 const TIDSortedElemSet& theNodesNot,
10960 const TopoDS_Shape& theShape )
10962 if ( theShape.IsNull() )
10965 const double aTol = Precision::Confusion();
10966 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10967 auto_ptr<_FaceClassifier> aFaceClassifier;
10968 if ( theShape.ShapeType() == TopAbs_SOLID )
10970 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10971 bsc3d->PerformInfinitePoint(aTol);
10973 else if (theShape.ShapeType() == TopAbs_FACE )
10975 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10978 // iterates on indicated elements and get elements by back references from their nodes
10979 TIDSortedElemSet anAffected;
10980 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10981 for ( ; elemItr != theElems.end(); ++elemItr )
10983 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10987 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10988 while ( nodeItr->more() )
10990 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10991 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10993 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10994 while ( backElemItr->more() )
10996 const SMDS_MeshElement* curElem = backElemItr->next();
10997 if ( curElem && theElems.find(curElem) == theElems.end() &&
10999 isInside( curElem, *bsc3d, aTol ) :
11000 isInside( curElem, *aFaceClassifier, aTol )))
11001 anAffected.insert( curElem );
11005 return DoubleNodes( theElems, theNodesNot, anAffected );
11009 * \brief compute an oriented angle between two planes defined by four points.
11010 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
11011 * @param p0 base of the rotation axe
11012 * @param p1 extremity of the rotation axe
11013 * @param g1 belongs to the first plane
11014 * @param g2 belongs to the second plane
11016 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
11018 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
11019 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
11020 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
11021 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
11022 gp_Vec vref(p0, p1);
11025 gp_Vec n1 = vref.Crossed(v1);
11026 gp_Vec n2 = vref.Crossed(v2);
11027 return n2.AngleWithRef(n1, vref);
11031 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
11032 * The list of groups must describe a partition of the mesh volumes.
11033 * The nodes of the internal faces at the boundaries of the groups are doubled.
11034 * In option, the internal faces are replaced by flat elements.
11035 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11036 * The flat elements are stored in groups of volumes.
11037 * @param theElems - list of groups of volumes, where a group of volume is a set of
11038 * SMDS_MeshElements sorted by Id.
11039 * @param createJointElems - if TRUE, create the elements
11040 * @return TRUE if operation has been completed successfully, FALSE otherwise
11042 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
11043 bool createJointElems)
11045 MESSAGE("----------------------------------------------");
11046 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
11047 MESSAGE("----------------------------------------------");
11049 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11050 meshDS->BuildDownWardConnectivity(true);
11052 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
11054 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
11055 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
11056 // build the list of nodes shared by 2 or more domains, with their domain indexes
11058 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
11059 std::map<int,int>celldom; // cell vtkId --> domain
11060 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
11061 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
11062 faceDomains.clear();
11064 cellDomains.clear();
11065 nodeDomains.clear();
11066 std::map<int,int> emptyMap;
11067 std::set<int> emptySet;
11070 for (int idom = 0; idom < theElems.size(); idom++)
11073 // --- build a map (face to duplicate --> volume to modify)
11074 // with all the faces shared by 2 domains (group of elements)
11075 // and corresponding volume of this domain, for each shared face.
11076 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
11078 const TIDSortedElemSet& domain = theElems[idom];
11079 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11080 for (; elemItr != domain.end(); ++elemItr)
11082 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11085 int vtkId = anElem->getVtkId();
11086 int neighborsVtkIds[NBMAXNEIGHBORS];
11087 int downIds[NBMAXNEIGHBORS];
11088 unsigned char downTypes[NBMAXNEIGHBORS];
11089 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
11090 for (int n = 0; n < nbNeighbors; n++)
11092 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
11093 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
11094 if (! domain.count(elem)) // neighbor is in another domain : face is shared
11096 DownIdType face(downIds[n], downTypes[n]);
11097 if (!faceDomains.count(face))
11098 faceDomains[face] = emptyMap; // create an empty entry for face
11099 if (!faceDomains[face].count(idom))
11101 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
11102 celldom[vtkId] = idom;
11109 //MESSAGE("Number of shared faces " << faceDomains.size());
11110 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
11112 // --- explore the shared faces domain by domain,
11113 // explore the nodes of the face and see if they belong to a cell in the domain,
11114 // which has only a node or an edge on the border (not a shared face)
11116 for (int idomain = 0; idomain < theElems.size(); idomain++)
11118 const TIDSortedElemSet& domain = theElems[idomain];
11119 itface = faceDomains.begin();
11120 for (; itface != faceDomains.end(); ++itface)
11122 std::map<int, int> domvol = itface->second;
11123 if (!domvol.count(idomain))
11125 DownIdType face = itface->first;
11126 //MESSAGE(" --- face " << face.cellId);
11127 std::set<int> oldNodes;
11129 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11130 std::set<int>::iterator itn = oldNodes.begin();
11131 for (; itn != oldNodes.end(); ++itn)
11134 //MESSAGE(" node " << oldId);
11135 std::set<int> cells;
11137 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11138 for (int i=0; i<l.ncells; i++)
11140 int vtkId = l.cells[i];
11141 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11142 if (!domain.count(anElem))
11144 int vtkType = grid->GetCellType(vtkId);
11145 int downId = grid->CellIdToDownId(vtkId);
11148 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11149 continue; // not OK at this stage of the algorithm:
11150 //no cells created after BuildDownWardConnectivity
11152 DownIdType aCell(downId, vtkType);
11153 if (celldom.count(vtkId))
11155 cellDomains[aCell][idomain] = vtkId;
11156 celldom[vtkId] = idomain;
11162 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11163 // for each shared face, get the nodes
11164 // for each node, for each domain of the face, create a clone of the node
11166 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11167 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11168 // the value is the ordered domain ids. (more than 4 domains not taken into account)
11170 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11171 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11173 for (int idomain = 0; idomain < theElems.size(); idomain++)
11175 itface = faceDomains.begin();
11176 for (; itface != faceDomains.end(); ++itface)
11178 std::map<int, int> domvol = itface->second;
11179 if (!domvol.count(idomain))
11181 DownIdType face = itface->first;
11182 //MESSAGE(" --- face " << face.cellId);
11183 std::set<int> oldNodes;
11185 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11186 bool isMultipleDetected = false;
11187 std::set<int>::iterator itn = oldNodes.begin();
11188 for (; itn != oldNodes.end(); ++itn)
11191 //MESSAGE(" node " << oldId);
11192 if (!nodeDomains.count(oldId))
11193 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11194 if (nodeDomains[oldId].empty())
11195 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11196 std::map<int, int>::iterator itdom = domvol.begin();
11197 for (; itdom != domvol.end(); ++itdom)
11199 int idom = itdom->first;
11200 //MESSAGE(" domain " << idom);
11201 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11203 if (nodeDomains[oldId].size() >= 2) // a multiple node
11205 vector<int> orderedDoms;
11206 //MESSAGE("multiple node " << oldId);
11207 isMultipleDetected =true;
11208 if (mutipleNodes.count(oldId))
11209 orderedDoms = mutipleNodes[oldId];
11212 map<int,int>::iterator it = nodeDomains[oldId].begin();
11213 for (; it != nodeDomains[oldId].end(); ++it)
11214 orderedDoms.push_back(it->first);
11216 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11217 //stringstream txt;
11218 //for (int i=0; i<orderedDoms.size(); i++)
11219 // txt << orderedDoms[i] << " ";
11220 //MESSAGE("orderedDoms " << txt.str());
11221 mutipleNodes[oldId] = orderedDoms;
11223 double *coords = grid->GetPoint(oldId);
11224 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11225 int newId = newNode->getVtkId();
11226 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11227 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11229 if (nodeDomains[oldId].size() >= 3)
11231 //MESSAGE("confirm multiple node " << oldId);
11232 isMultipleDetected =true;
11236 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11238 //MESSAGE("multiple Nodes detected on a shared face");
11239 int downId = itface->first.cellId;
11240 unsigned char cellType = itface->first.cellType;
11241 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11242 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11243 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11244 for (int ie =0; ie < nbEdges; ie++)
11247 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11248 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11250 vector<int> vn0 = mutipleNodes[nodes[0]];
11251 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11252 sort( vn0.begin(), vn0.end() );
11253 sort( vn1.begin(), vn1.end() );
11256 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11257 double *coords = grid->GetPoint(nodes[0]);
11258 gp_Pnt p0(coords[0], coords[1], coords[2]);
11259 coords = grid->GetPoint(nodes[nbNodes - 1]);
11260 gp_Pnt p1(coords[0], coords[1], coords[2]);
11262 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11263 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11264 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11265 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11266 for (int id=0; id < vn0.size(); id++)
11268 int idom = vn0[id];
11269 for (int ivol=0; ivol<nbvol; ivol++)
11271 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11272 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11273 if (theElems[idom].count(elem))
11275 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11276 domvol[idom] = svol;
11277 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11279 vtkIdType npts = 0;
11280 vtkIdType* pts = 0;
11281 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11282 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11285 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11286 angleDom[idom] = 0;
11290 gp_Pnt g(values[0], values[1], values[2]);
11291 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11292 //MESSAGE(" angle=" << angleDom[idom]);
11298 map<double, int> sortedDom; // sort domains by angle
11299 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11300 sortedDom[ia->second] = ia->first;
11301 vector<int> vnodes;
11303 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11305 vdom.push_back(ib->second);
11306 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11308 for (int ino = 0; ino < nbNodes; ino++)
11309 vnodes.push_back(nodes[ino]);
11310 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11318 // --- iterate on shared faces (volumes to modify, face to extrude)
11319 // get node id's of the face (id SMDS = id VTK)
11320 // create flat element with old and new nodes if requested
11322 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11323 // (domain1 X domain2) = domain1 + MAXINT*domain2
11325 std::map<int, std::map<long,int> > nodeQuadDomains;
11326 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11328 if (createJointElems)
11330 itface = faceDomains.begin();
11331 for (; itface != faceDomains.end(); ++itface)
11333 DownIdType face = itface->first;
11334 std::set<int> oldNodes;
11335 std::set<int>::iterator itn;
11337 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11339 std::map<int, int> domvol = itface->second;
11340 std::map<int, int>::iterator itdom = domvol.begin();
11341 int dom1 = itdom->first;
11342 int vtkVolId = itdom->second;
11344 int dom2 = itdom->first;
11345 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11347 stringstream grpname;
11350 grpname << dom1 << "_" << dom2;
11352 grpname << dom2 << "_" << dom1;
11354 string namegrp = grpname.str();
11355 if (!mapOfJunctionGroups.count(namegrp))
11356 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11357 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11359 sgrp->Add(vol->GetID());
11363 // --- create volumes on multiple domain intersection if requested
11364 // iterate on edgesMultiDomains
11366 if (createJointElems)
11368 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11369 for (; ite != edgesMultiDomains.end(); ++ite)
11371 vector<int> nodes = ite->first;
11372 vector<int> orderDom = ite->second;
11373 vector<vtkIdType> orderedNodes;
11374 if (nodes.size() == 2)
11376 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11377 for (int ino=0; ino < nodes.size(); ino++)
11378 if (orderDom.size() == 3)
11379 for (int idom = 0; idom <orderDom.size(); idom++)
11380 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11382 for (int idom = orderDom.size()-1; idom >=0; idom--)
11383 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11384 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11386 stringstream grpname;
11388 grpname << 0 << "_" << 0;
11390 string namegrp = grpname.str();
11391 if (!mapOfJunctionGroups.count(namegrp))
11392 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11393 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11395 sgrp->Add(vol->GetID());
11399 //MESSAGE("Quadratic multiple joints not implemented");
11400 // TODO quadratic nodes
11405 // --- list the explicit faces and edges of the mesh that need to be modified,
11406 // i.e. faces and edges built with one or more duplicated nodes.
11407 // associate these faces or edges to their corresponding domain.
11408 // only the first domain found is kept when a face or edge is shared
11410 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11411 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11412 faceOrEdgeDom.clear();
11415 for (int idomain = 0; idomain < theElems.size(); idomain++)
11417 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11418 for (; itnod != nodeDomains.end(); ++itnod)
11420 int oldId = itnod->first;
11421 //MESSAGE(" node " << oldId);
11422 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11423 for (int i = 0; i < l.ncells; i++)
11425 int vtkId = l.cells[i];
11426 int vtkType = grid->GetCellType(vtkId);
11427 int downId = grid->CellIdToDownId(vtkId);
11429 continue; // new cells: not to be modified
11430 DownIdType aCell(downId, vtkType);
11431 int volParents[1000];
11432 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11433 for (int j = 0; j < nbvol; j++)
11434 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11435 if (!feDom.count(vtkId))
11437 feDom[vtkId] = idomain;
11438 faceOrEdgeDom[aCell] = emptyMap;
11439 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11440 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11441 // << " type " << vtkType << " downId " << downId);
11447 // --- iterate on shared faces (volumes to modify, face to extrude)
11448 // get node id's of the face
11449 // replace old nodes by new nodes in volumes, and update inverse connectivity
11451 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11452 for (int m=0; m<3; m++)
11454 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11455 itface = (*amap).begin();
11456 for (; itface != (*amap).end(); ++itface)
11458 DownIdType face = itface->first;
11459 std::set<int> oldNodes;
11460 std::set<int>::iterator itn;
11462 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11463 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11464 std::map<int, int> localClonedNodeIds;
11466 std::map<int, int> domvol = itface->second;
11467 std::map<int, int>::iterator itdom = domvol.begin();
11468 for (; itdom != domvol.end(); ++itdom)
11470 int idom = itdom->first;
11471 int vtkVolId = itdom->second;
11472 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11473 localClonedNodeIds.clear();
11474 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11477 if (nodeDomains[oldId].count(idom))
11479 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11480 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11483 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11488 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11489 grid->BuildLinks();
11497 * \brief Double nodes on some external faces and create flat elements.
11498 * Flat elements are mainly used by some types of mechanic calculations.
11500 * Each group of the list must be constituted of faces.
11501 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11502 * @param theElems - list of groups of faces, where a group of faces is a set of
11503 * SMDS_MeshElements sorted by Id.
11504 * @return TRUE if operation has been completed successfully, FALSE otherwise
11506 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11508 MESSAGE("-------------------------------------------------");
11509 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11510 MESSAGE("-------------------------------------------------");
11512 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11514 // --- For each group of faces
11515 // duplicate the nodes, create a flat element based on the face
11516 // replace the nodes of the faces by their clones
11518 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11519 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11520 clonedNodes.clear();
11521 intermediateNodes.clear();
11522 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11523 mapOfJunctionGroups.clear();
11525 for (int idom = 0; idom < theElems.size(); idom++)
11527 const TIDSortedElemSet& domain = theElems[idom];
11528 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11529 for (; elemItr != domain.end(); ++elemItr)
11531 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11532 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11535 // MESSAGE("aFace=" << aFace->GetID());
11536 bool isQuad = aFace->IsQuadratic();
11537 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11539 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11541 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11542 while (nodeIt->more())
11544 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11545 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11547 ln2.push_back(node);
11549 ln0.push_back(node);
11551 const SMDS_MeshNode* clone = 0;
11552 if (!clonedNodes.count(node))
11554 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11555 clonedNodes[node] = clone;
11558 clone = clonedNodes[node];
11561 ln3.push_back(clone);
11563 ln1.push_back(clone);
11565 const SMDS_MeshNode* inter = 0;
11566 if (isQuad && (!isMedium))
11568 if (!intermediateNodes.count(node))
11570 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11571 intermediateNodes[node] = inter;
11574 inter = intermediateNodes[node];
11575 ln4.push_back(inter);
11579 // --- extrude the face
11581 vector<const SMDS_MeshNode*> ln;
11582 SMDS_MeshVolume* vol = 0;
11583 vtkIdType aType = aFace->GetVtkType();
11587 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11588 // MESSAGE("vol prism " << vol->GetID());
11589 ln.push_back(ln1[0]);
11590 ln.push_back(ln1[1]);
11591 ln.push_back(ln1[2]);
11594 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11595 // MESSAGE("vol hexa " << vol->GetID());
11596 ln.push_back(ln1[0]);
11597 ln.push_back(ln1[1]);
11598 ln.push_back(ln1[2]);
11599 ln.push_back(ln1[3]);
11601 case VTK_QUADRATIC_TRIANGLE:
11602 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11603 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11604 // MESSAGE("vol quad prism " << vol->GetID());
11605 ln.push_back(ln1[0]);
11606 ln.push_back(ln1[1]);
11607 ln.push_back(ln1[2]);
11608 ln.push_back(ln3[0]);
11609 ln.push_back(ln3[1]);
11610 ln.push_back(ln3[2]);
11612 case VTK_QUADRATIC_QUAD:
11613 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11614 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11615 // ln4[0], ln4[1], ln4[2], ln4[3]);
11616 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11617 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11618 ln4[0], ln4[1], ln4[2], ln4[3]);
11619 // MESSAGE("vol quad hexa " << vol->GetID());
11620 ln.push_back(ln1[0]);
11621 ln.push_back(ln1[1]);
11622 ln.push_back(ln1[2]);
11623 ln.push_back(ln1[3]);
11624 ln.push_back(ln3[0]);
11625 ln.push_back(ln3[1]);
11626 ln.push_back(ln3[2]);
11627 ln.push_back(ln3[3]);
11637 stringstream grpname;
11641 string namegrp = grpname.str();
11642 if (!mapOfJunctionGroups.count(namegrp))
11643 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11644 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11646 sgrp->Add(vol->GetID());
11649 // --- modify the face
11651 aFace->ChangeNodes(&ln[0], ln.size());
11657 //================================================================================
11659 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11660 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11661 * \return TRUE if operation has been completed successfully, FALSE otherwise
11663 //================================================================================
11665 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11667 // iterates on volume elements and detect all free faces on them
11668 SMESHDS_Mesh* aMesh = GetMeshDS();
11671 //bool res = false;
11672 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11673 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11676 const SMDS_MeshVolume* volume = vIt->next();
11677 SMDS_VolumeTool vTool( volume );
11678 vTool.SetExternalNormal();
11679 const bool isPoly = volume->IsPoly();
11680 const bool isQuad = volume->IsQuadratic();
11681 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11683 if (!vTool.IsFreeFace(iface))
11686 vector<const SMDS_MeshNode *> nodes;
11687 int nbFaceNodes = vTool.NbFaceNodes(iface);
11688 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11690 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11691 nodes.push_back(faceNodes[inode]);
11693 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11694 nodes.push_back(faceNodes[inode]);
11696 // add new face based on volume nodes
11697 if (aMesh->FindFace( nodes ) ) {
11699 continue; // face already exsist
11701 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11705 return ( nbFree==(nbExisted+nbCreated) );
11710 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11712 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11714 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11717 //================================================================================
11719 * \brief Creates missing boundary elements
11720 * \param elements - elements whose boundary is to be checked
11721 * \param dimension - defines type of boundary elements to create
11722 * \param group - a group to store created boundary elements in
11723 * \param targetMesh - a mesh to store created boundary elements in
11724 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11725 * \param toCopyExistingBoundary - if true, not only new but also pre-existing
11726 * boundary elements will be copied into the targetMesh
11727 * \param toAddExistingBondary - if true, not only new but also pre-existing
11728 * boundary elements will be added into the new group
11729 * \param aroundElements - if true, elements will be created on boundary of given
11730 * elements else, on boundary of the whole mesh.
11731 * \return nb of added boundary elements
11733 //================================================================================
11735 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11736 Bnd_Dimension dimension,
11737 SMESH_Group* group/*=0*/,
11738 SMESH_Mesh* targetMesh/*=0*/,
11739 bool toCopyElements/*=false*/,
11740 bool toCopyExistingBoundary/*=false*/,
11741 bool toAddExistingBondary/*= false*/,
11742 bool aroundElements/*= false*/)
11744 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11745 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11746 // hope that all elements are of the same type, do not check them all
11747 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11748 throw SALOME_Exception(LOCALIZED("wrong element type"));
11751 toCopyElements = toCopyExistingBoundary = false;
11753 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11754 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11755 int nbAddedBnd = 0;
11757 // editor adding present bnd elements and optionally holding elements to add to the group
11758 SMESH_MeshEditor* presentEditor;
11759 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11760 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11762 SMDS_VolumeTool vTool;
11763 TIDSortedElemSet avoidSet;
11764 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11767 typedef vector<const SMDS_MeshNode*> TConnectivity;
11769 SMDS_ElemIteratorPtr eIt;
11770 if (elements.empty())
11771 eIt = aMesh->elementsIterator(elemType);
11773 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11775 while (eIt->more())
11777 const SMDS_MeshElement* elem = eIt->next();
11778 const int iQuad = elem->IsQuadratic();
11780 // ------------------------------------------------------------------------------------
11781 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11782 // ------------------------------------------------------------------------------------
11783 vector<const SMDS_MeshElement*> presentBndElems;
11784 vector<TConnectivity> missingBndElems;
11785 TConnectivity nodes;
11786 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11788 vTool.SetExternalNormal();
11789 const SMDS_MeshElement* otherVol = 0;
11790 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11792 if ( !vTool.IsFreeFace(iface, &otherVol) &&
11793 ( !aroundElements || elements.count( otherVol )))
11795 const int nbFaceNodes = vTool.NbFaceNodes(iface);
11796 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11797 if ( missType == SMDSAbs_Edge ) // boundary edges
11799 nodes.resize( 2+iQuad );
11800 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11802 for ( int j = 0; j < nodes.size(); ++j )
11804 if ( const SMDS_MeshElement* edge =
11805 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11806 presentBndElems.push_back( edge );
11808 missingBndElems.push_back( nodes );
11811 else // boundary face
11814 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11815 nodes.push_back( nn[inode] );
11817 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11818 nodes.push_back( nn[inode] );
11820 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11821 presentBndElems.push_back( f );
11823 missingBndElems.push_back( nodes );
11825 if ( targetMesh != myMesh )
11827 // add 1D elements on face boundary to be added to a new mesh
11828 const SMDS_MeshElement* edge;
11829 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11832 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11834 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11835 if ( edge && avoidSet.insert( edge ).second )
11836 presentBndElems.push_back( edge );
11842 else // elem is a face ------------------------------------------
11844 avoidSet.clear(), avoidSet.insert( elem );
11845 int nbNodes = elem->NbCornerNodes();
11846 nodes.resize( 2 /*+ iQuad*/);
11847 for ( int i = 0; i < nbNodes; i++ )
11849 nodes[0] = elem->GetNode(i);
11850 nodes[1] = elem->GetNode((i+1)%nbNodes);
11851 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11852 continue; // not free link
11855 //nodes[2] = elem->GetNode( i + nbNodes );
11856 if ( const SMDS_MeshElement* edge =
11857 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11858 presentBndElems.push_back( edge );
11860 missingBndElems.push_back( nodes );
11864 // ---------------------------------
11865 // 2. Add missing boundary elements
11866 // ---------------------------------
11867 if ( targetMesh != myMesh )
11868 // instead of making a map of nodes in this mesh and targetMesh,
11869 // we create nodes with same IDs.
11870 for ( int i = 0; i < missingBndElems.size(); ++i )
11872 TConnectivity& srcNodes = missingBndElems[i];
11873 TConnectivity nodes( srcNodes.size() );
11874 for ( inode = 0; inode < nodes.size(); ++inode )
11875 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11876 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11878 /*noMedium=*/true))
11880 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11884 for ( int i = 0; i < missingBndElems.size(); ++i )
11886 TConnectivity& nodes = missingBndElems[i];
11887 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11889 /*noMedium=*/true))
11891 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11895 // ----------------------------------
11896 // 3. Copy present boundary elements
11897 // ----------------------------------
11898 if ( toCopyExistingBoundary )
11899 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11901 const SMDS_MeshElement* e = presentBndElems[i];
11902 TConnectivity nodes( e->NbNodes() );
11903 for ( inode = 0; inode < nodes.size(); ++inode )
11904 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11905 presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11907 else // store present elements to add them to a group
11908 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11910 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11913 } // loop on given elements
11915 // ---------------------------------------------
11916 // 4. Fill group with boundary elements
11917 // ---------------------------------------------
11920 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11921 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11922 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11924 tgtEditor.myLastCreatedElems.Clear();
11925 tgtEditor2.myLastCreatedElems.Clear();
11927 // -----------------------
11928 // 5. Copy given elements
11929 // -----------------------
11930 if ( toCopyElements && targetMesh != myMesh )
11932 if (elements.empty())
11933 eIt = aMesh->elementsIterator(elemType);
11935 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11936 while (eIt->more())
11938 const SMDS_MeshElement* elem = eIt->next();
11939 TConnectivity nodes( elem->NbNodes() );
11940 for ( inode = 0; inode < nodes.size(); ++inode )
11941 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11942 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11944 tgtEditor.myLastCreatedElems.Clear();