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
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
103 using namespace SMESH::Controls;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
110 //=======================================================================
111 //function : SMESH_MeshEditor
113 //=======================================================================
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116 :myMesh( theMesh ) // theMesh may be NULL
120 //=======================================================================
124 //=======================================================================
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128 const SMDSAbs_ElementType type,
132 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133 SMDS_MeshElement* e = 0;
134 int nbnode = node.size();
135 SMESHDS_Mesh* mesh = GetMeshDS();
140 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141 else e = mesh->AddFace (node[0], node[1], node[2] );
143 else if (nbnode == 4) {
144 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
147 else if (nbnode == 6) {
148 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149 node[4], node[5], ID);
150 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
153 else if (nbnode == 8) {
154 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7], ID);
156 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7] );
160 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161 else e = mesh->AddPolygonalFace (node );
168 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
171 else if (nbnode == 5) {
172 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
174 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
177 else if (nbnode == 6) {
178 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 node[4], node[5], ID);
180 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 else if (nbnode == 8) {
184 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7], ID);
186 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7] );
189 else if (nbnode == 10) {
190 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191 node[4], node[5], node[6], node[7],
192 node[8], node[9], ID);
193 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7],
197 else if (nbnode == 13) {
198 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199 node[4], node[5], node[6], node[7],
200 node[8], node[9], node[10],node[11],
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
207 else if (nbnode == 15) {
208 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209 node[4], node[5], node[6], node[7],
210 node[8], node[9], node[10],node[11],
211 node[12],node[13],node[14],ID);
212 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
213 node[4], node[5], node[6], node[7],
214 node[8], node[9], node[10],node[11],
215 node[12],node[13],node[14] );
217 else if (nbnode == 20) {
218 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219 node[4], node[5], node[6], node[7],
220 node[8], node[9], node[10],node[11],
221 node[12],node[13],node[14],node[15],
222 node[16],node[17],node[18],node[19],ID);
223 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
224 node[4], node[5], node[6], node[7],
225 node[8], node[9], node[10],node[11],
226 node[12],node[13],node[14],node[15],
227 node[16],node[17],node[18],node[19] );
234 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235 else e = mesh->AddEdge (node[0], node[1] );
237 else if ( nbnode == 3 ) {
238 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239 else e = mesh->AddEdge (node[0], node[1], node[2] );
243 case SMDSAbs_0DElement:
245 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246 else e = mesh->Add0DElement (node[0] );
251 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
257 if ( e ) myLastCreatedElems.Append( e );
261 //=======================================================================
265 //=======================================================================
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
268 const SMDSAbs_ElementType type,
272 vector<const SMDS_MeshNode*> nodes;
273 nodes.reserve( nodeIDs.size() );
274 vector<int>::const_iterator id = nodeIDs.begin();
275 while ( id != nodeIDs.end() ) {
276 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277 nodes.push_back( node );
281 return AddElement( nodes, type, isPoly, ID );
284 //=======================================================================
286 //purpose : Remove a node or an element.
287 // Modify a compute state of sub-meshes which become empty
288 //=======================================================================
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
293 myLastCreatedElems.Clear();
294 myLastCreatedNodes.Clear();
296 SMESHDS_Mesh* aMesh = GetMeshDS();
297 set< SMESH_subMesh *> smmap;
300 list<int>::const_iterator it = theIDs.begin();
301 for ( ; it != theIDs.end(); it++ ) {
302 const SMDS_MeshElement * elem;
304 elem = aMesh->FindNode( *it );
306 elem = aMesh->FindElement( *it );
310 // Notify VERTEX sub-meshes about modification
312 const SMDS_MeshNode* node = cast2Node( elem );
313 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314 if ( int aShapeID = node->getshapeId() )
315 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
318 // Find sub-meshes to notify about modification
319 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320 // while ( nodeIt->more() ) {
321 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322 // const SMDS_PositionPtr& aPosition = node->GetPosition();
323 // if ( aPosition.get() ) {
324 // if ( int aShapeID = aPosition->GetShapeId() ) {
325 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326 // smmap.insert( sm );
333 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
335 aMesh->RemoveElement( elem );
339 // Notify sub-meshes about modification
340 if ( !smmap.empty() ) {
341 set< SMESH_subMesh *>::iterator smIt;
342 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
346 // // Check if the whole mesh becomes empty
347 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
353 //=======================================================================
354 //function : FindShape
355 //purpose : Return an index of the shape theElem is on
356 // or zero if a shape not found
357 //=======================================================================
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
361 myLastCreatedElems.Clear();
362 myLastCreatedNodes.Clear();
364 SMESHDS_Mesh * aMesh = GetMeshDS();
365 if ( aMesh->ShapeToMesh().IsNull() )
368 int aShapeID = theElem->getshapeId();
372 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
373 if ( sm->Contains( theElem ))
376 if ( theElem->GetType() == SMDSAbs_Node ) {
377 MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
380 MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
383 TopoDS_Shape aShape; // the shape a node of theElem is on
384 if ( theElem->GetType() != SMDSAbs_Node )
386 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
387 while ( nodeIt->more() ) {
388 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
389 if ((aShapeID = node->getshapeId()) > 0) {
390 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
391 if ( sm->Contains( theElem ))
393 if ( aShape.IsNull() )
394 aShape = aMesh->IndexToShape( aShapeID );
400 // None of nodes is on a proper shape,
401 // find the shape among ancestors of aShape on which a node is
402 if ( !aShape.IsNull() ) {
403 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
404 for ( ; ancIt.More(); ancIt.Next() ) {
405 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
406 if ( sm && sm->Contains( theElem ))
407 return aMesh->ShapeToIndex( ancIt.Value() );
412 const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
413 map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
414 for ( ; id_sm != id2sm.end(); ++id_sm )
415 if ( id_sm->second->Contains( theElem ))
419 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
423 //=======================================================================
424 //function : IsMedium
426 //=======================================================================
428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
429 const SMDSAbs_ElementType typeToCheck)
431 bool isMedium = false;
432 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
433 while (it->more() && !isMedium ) {
434 const SMDS_MeshElement* elem = it->next();
435 isMedium = elem->IsMediumNode(node);
440 //=======================================================================
441 //function : ShiftNodesQuadTria
443 // Shift nodes in the array corresponded to quadratic triangle
444 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
445 //=======================================================================
446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
448 const SMDS_MeshNode* nd1 = aNodes[0];
449 aNodes[0] = aNodes[1];
450 aNodes[1] = aNodes[2];
452 const SMDS_MeshNode* nd2 = aNodes[3];
453 aNodes[3] = aNodes[4];
454 aNodes[4] = aNodes[5];
458 //=======================================================================
459 //function : GetNodesFromTwoTria
461 // Shift nodes in the array corresponded to quadratic triangle
462 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
463 //=======================================================================
464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
465 const SMDS_MeshElement * theTria2,
466 const SMDS_MeshNode* N1[],
467 const SMDS_MeshNode* N2[])
469 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
472 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
475 if(it->more()) return false;
476 it = theTria2->nodesIterator();
479 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
482 if(it->more()) return false;
484 int sames[3] = {-1,-1,-1};
496 if(nbsames!=2) return false;
498 ShiftNodesQuadTria(N1);
500 ShiftNodesQuadTria(N1);
503 i = sames[0] + sames[1] + sames[2];
505 ShiftNodesQuadTria(N2);
507 // now we receive following N1 and N2 (using numeration as above image)
508 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
509 // i.e. first nodes from both arrays determ new diagonal
513 //=======================================================================
514 //function : InverseDiag
515 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
516 // but having other common link.
517 // Return False if args are improper
518 //=======================================================================
520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
521 const SMDS_MeshElement * theTria2 )
523 MESSAGE("InverseDiag");
524 myLastCreatedElems.Clear();
525 myLastCreatedNodes.Clear();
527 if (!theTria1 || !theTria2)
530 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
531 if (!F1) return false;
532 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
533 if (!F2) return false;
534 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
535 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
537 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
538 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
542 // put nodes in array and find out indices of the same ones
543 const SMDS_MeshNode* aNodes [6];
544 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
546 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
547 while ( it->more() ) {
548 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
550 if ( i > 2 ) // theTria2
551 // find same node of theTria1
552 for ( int j = 0; j < 3; j++ )
553 if ( aNodes[ i ] == aNodes[ j ]) {
562 return false; // theTria1 is not a triangle
563 it = theTria2->nodesIterator();
565 if ( i == 6 && it->more() )
566 return false; // theTria2 is not a triangle
569 // find indices of 1,2 and of A,B in theTria1
570 int iA = 0, iB = 0, i1 = 0, i2 = 0;
571 for ( i = 0; i < 6; i++ ) {
572 if ( sameInd [ i ] == 0 ) {
581 // nodes 1 and 2 should not be the same
582 if ( aNodes[ i1 ] == aNodes[ i2 ] )
586 aNodes[ iA ] = aNodes[ i2 ];
588 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
590 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
591 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
595 } // end if(F1 && F2)
597 // check case of quadratic faces
598 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
600 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
604 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
605 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
613 const SMDS_MeshNode* N1 [6];
614 const SMDS_MeshNode* N2 [6];
615 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
617 // now we receive following N1 and N2 (using numeration as above image)
618 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
619 // i.e. first nodes from both arrays determ new diagonal
621 const SMDS_MeshNode* N1new [6];
622 const SMDS_MeshNode* N2new [6];
635 // replaces nodes in faces
636 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
637 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
642 //=======================================================================
643 //function : findTriangles
644 //purpose : find triangles sharing theNode1-theNode2 link
645 //=======================================================================
647 static bool findTriangles(const SMDS_MeshNode * theNode1,
648 const SMDS_MeshNode * theNode2,
649 const SMDS_MeshElement*& theTria1,
650 const SMDS_MeshElement*& theTria2)
652 if ( !theNode1 || !theNode2 ) return false;
654 theTria1 = theTria2 = 0;
656 set< const SMDS_MeshElement* > emap;
657 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
659 const SMDS_MeshElement* elem = it->next();
660 if ( elem->NbNodes() == 3 )
663 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
665 const SMDS_MeshElement* elem = it->next();
666 if ( emap.find( elem ) != emap.end() ) {
668 // theTria1 must be element with minimum ID
669 if( theTria1->GetID() < elem->GetID() ) {
683 return ( theTria1 && theTria2 );
686 //=======================================================================
687 //function : InverseDiag
688 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
689 // with ones built on the same 4 nodes but having other common link.
690 // Return false if proper faces not found
691 //=======================================================================
693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
694 const SMDS_MeshNode * theNode2)
696 myLastCreatedElems.Clear();
697 myLastCreatedNodes.Clear();
699 MESSAGE( "::InverseDiag()" );
701 const SMDS_MeshElement *tr1, *tr2;
702 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
705 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
706 if (!F1) return false;
707 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
708 if (!F2) return false;
709 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
710 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
712 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
713 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
717 // put nodes in array
718 // and find indices of 1,2 and of A in tr1 and of B in tr2
719 int i, iA1 = 0, i1 = 0;
720 const SMDS_MeshNode* aNodes1 [3];
721 SMDS_ElemIteratorPtr it;
722 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
723 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
724 if ( aNodes1[ i ] == theNode1 )
725 iA1 = i; // node A in tr1
726 else if ( aNodes1[ i ] != theNode2 )
730 const SMDS_MeshNode* aNodes2 [3];
731 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
732 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
733 if ( aNodes2[ i ] == theNode2 )
734 iB2 = i; // node B in tr2
735 else if ( aNodes2[ i ] != theNode1 )
739 // nodes 1 and 2 should not be the same
740 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
744 aNodes1[ iA1 ] = aNodes2[ i2 ];
746 aNodes2[ iB2 ] = aNodes1[ i1 ];
748 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
749 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
754 // check case of quadratic faces
755 return InverseDiag(tr1,tr2);
758 //=======================================================================
759 //function : getQuadrangleNodes
760 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
761 // fusion of triangles tr1 and tr2 having shared link on
762 // theNode1 and theNode2
763 //=======================================================================
765 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
766 const SMDS_MeshNode * theNode1,
767 const SMDS_MeshNode * theNode2,
768 const SMDS_MeshElement * tr1,
769 const SMDS_MeshElement * tr2 )
771 if( tr1->NbNodes() != tr2->NbNodes() )
773 // find the 4-th node to insert into tr1
774 const SMDS_MeshNode* n4 = 0;
775 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
777 while ( !n4 && i<3 ) {
778 const SMDS_MeshNode * n = cast2Node( it->next() );
780 bool isDiag = ( n == theNode1 || n == theNode2 );
784 // Make an array of nodes to be in a quadrangle
785 int iNode = 0, iFirstDiag = -1;
786 it = tr1->nodesIterator();
789 const SMDS_MeshNode * n = cast2Node( it->next() );
791 bool isDiag = ( n == theNode1 || n == theNode2 );
793 if ( iFirstDiag < 0 )
795 else if ( iNode - iFirstDiag == 1 )
796 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
798 else if ( n == n4 ) {
799 return false; // tr1 and tr2 should not have all the same nodes
801 theQuadNodes[ iNode++ ] = n;
803 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
804 theQuadNodes[ iNode ] = n4;
809 //=======================================================================
810 //function : DeleteDiag
811 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
812 // with a quadrangle built on the same 4 nodes.
813 // Return false if proper faces not found
814 //=======================================================================
816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
817 const SMDS_MeshNode * theNode2)
819 myLastCreatedElems.Clear();
820 myLastCreatedNodes.Clear();
822 MESSAGE( "::DeleteDiag()" );
824 const SMDS_MeshElement *tr1, *tr2;
825 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
828 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
829 if (!F1) return false;
830 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
831 if (!F2) return false;
832 SMESHDS_Mesh * aMesh = GetMeshDS();
834 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
835 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
837 const SMDS_MeshNode* aNodes [ 4 ];
838 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
841 const SMDS_MeshElement* newElem = 0;
842 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
843 myLastCreatedElems.Append(newElem);
844 AddToSameGroups( newElem, tr1, aMesh );
845 int aShapeId = tr1->getshapeId();
848 aMesh->SetMeshElementOnShape( newElem, aShapeId );
850 aMesh->RemoveElement( tr1 );
851 aMesh->RemoveElement( tr2 );
856 // check case of quadratic faces
857 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
859 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
863 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
864 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
872 const SMDS_MeshNode* N1 [6];
873 const SMDS_MeshNode* N2 [6];
874 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
876 // now we receive following N1 and N2 (using numeration as above image)
877 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
878 // i.e. first nodes from both arrays determ new diagonal
880 const SMDS_MeshNode* aNodes[8];
890 const SMDS_MeshElement* newElem = 0;
891 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
892 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
893 myLastCreatedElems.Append(newElem);
894 AddToSameGroups( newElem, tr1, aMesh );
895 int aShapeId = tr1->getshapeId();
898 aMesh->SetMeshElementOnShape( newElem, aShapeId );
900 aMesh->RemoveElement( tr1 );
901 aMesh->RemoveElement( tr2 );
903 // remove middle node (9)
904 GetMeshDS()->RemoveNode( N1[4] );
909 //=======================================================================
910 //function : Reorient
911 //purpose : Reverse theElement orientation
912 //=======================================================================
914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
917 myLastCreatedElems.Clear();
918 myLastCreatedNodes.Clear();
922 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
923 if ( !it || !it->more() )
926 switch ( theElem->GetType() ) {
930 if(!theElem->IsQuadratic()) {
931 int i = theElem->NbNodes();
932 vector<const SMDS_MeshNode*> aNodes( i );
934 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
935 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
938 // quadratic elements
939 if(theElem->GetType()==SMDSAbs_Edge) {
940 vector<const SMDS_MeshNode*> aNodes(3);
941 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
942 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
943 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
944 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
947 int nbn = theElem->NbNodes();
948 vector<const SMDS_MeshNode*> aNodes(nbn);
949 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
951 for(; i<nbn/2; i++) {
952 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
954 for(i=0; i<nbn/2; i++) {
955 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
957 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
961 case SMDSAbs_Volume: {
962 if (theElem->IsPoly()) {
963 // TODO reorient vtk polyhedron
964 MESSAGE("reorient vtk polyhedron ?");
965 const SMDS_VtkVolume* aPolyedre =
966 dynamic_cast<const SMDS_VtkVolume*>( theElem );
968 MESSAGE("Warning: bad volumic element");
972 int nbFaces = aPolyedre->NbFaces();
973 vector<const SMDS_MeshNode *> poly_nodes;
974 vector<int> quantities (nbFaces);
976 // reverse each face of the polyedre
977 for (int iface = 1; iface <= nbFaces; iface++) {
978 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
979 quantities[iface - 1] = nbFaceNodes;
981 for (inode = nbFaceNodes; inode >= 1; inode--) {
982 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
983 poly_nodes.push_back(curNode);
987 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
991 SMDS_VolumeTool vTool;
992 if ( !vTool.Set( theElem ))
995 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
996 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1005 //=======================================================================
1006 //function : getBadRate
1008 //=======================================================================
1010 static double getBadRate (const SMDS_MeshElement* theElem,
1011 SMESH::Controls::NumericalFunctorPtr& theCrit)
1013 SMESH::Controls::TSequenceOfXYZ P;
1014 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1016 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1017 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1020 //=======================================================================
1021 //function : QuadToTri
1022 //purpose : Cut quadrangles into triangles.
1023 // theCrit is used to select a diagonal to cut
1024 //=======================================================================
1026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1027 SMESH::Controls::NumericalFunctorPtr theCrit)
1029 myLastCreatedElems.Clear();
1030 myLastCreatedNodes.Clear();
1032 MESSAGE( "::QuadToTri()" );
1034 if ( !theCrit.get() )
1037 SMESHDS_Mesh * aMesh = GetMeshDS();
1039 Handle(Geom_Surface) surface;
1040 SMESH_MesherHelper helper( *GetMesh() );
1042 TIDSortedElemSet::iterator itElem;
1043 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1044 const SMDS_MeshElement* elem = *itElem;
1045 if ( !elem || elem->GetType() != SMDSAbs_Face )
1047 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1050 // retrieve element nodes
1051 const SMDS_MeshNode* aNodes [8];
1052 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1054 while ( itN->more() )
1055 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1057 // compare two sets of possible triangles
1058 double aBadRate1, aBadRate2; // to what extent a set is bad
1059 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1060 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1061 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1063 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1064 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1065 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1067 int aShapeId = FindShape( elem );
1068 const SMDS_MeshElement* newElem1 = 0;
1069 const SMDS_MeshElement* newElem2 = 0;
1071 if( !elem->IsQuadratic() ) {
1073 // split liner quadrangle
1074 if ( aBadRate1 <= aBadRate2 ) {
1075 // tr1 + tr2 is better
1076 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1077 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1080 // tr3 + tr4 is better
1081 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1082 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1087 // split quadratic quadrangle
1089 // get surface elem is on
1090 if ( aShapeId != helper.GetSubShapeID() ) {
1094 shape = aMesh->IndexToShape( aShapeId );
1095 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1096 TopoDS_Face face = TopoDS::Face( shape );
1097 surface = BRep_Tool::Surface( face );
1098 if ( !surface.IsNull() )
1099 helper.SetSubShape( shape );
1103 const SMDS_MeshNode* aNodes [8];
1104 const SMDS_MeshNode* inFaceNode = 0;
1105 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1107 while ( itN->more() ) {
1108 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1109 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1110 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1112 inFaceNode = aNodes[ i-1 ];
1115 // find middle point for (0,1,2,3)
1116 // and create a node in this point;
1118 if ( surface.IsNull() ) {
1120 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1124 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1127 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1129 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1131 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1132 myLastCreatedNodes.Append(newN);
1134 // create a new element
1135 if ( aBadRate1 <= aBadRate2 ) {
1136 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1137 aNodes[6], aNodes[7], newN );
1138 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1139 newN, aNodes[4], aNodes[5] );
1142 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1143 aNodes[7], aNodes[4], newN );
1144 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1145 newN, aNodes[5], aNodes[6] );
1149 // care of a new element
1151 myLastCreatedElems.Append(newElem1);
1152 myLastCreatedElems.Append(newElem2);
1153 AddToSameGroups( newElem1, elem, aMesh );
1154 AddToSameGroups( newElem2, elem, aMesh );
1156 // put a new triangle on the same shape
1159 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1160 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1162 aMesh->RemoveElement( elem );
1167 //=======================================================================
1168 //function : BestSplit
1169 //purpose : Find better diagonal for cutting.
1170 //=======================================================================
1172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1173 SMESH::Controls::NumericalFunctorPtr theCrit)
1175 myLastCreatedElems.Clear();
1176 myLastCreatedNodes.Clear();
1181 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1184 if( theQuad->NbNodes()==4 ||
1185 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1187 // retrieve element nodes
1188 const SMDS_MeshNode* aNodes [4];
1189 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1191 //while (itN->more())
1193 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1195 // compare two sets of possible triangles
1196 double aBadRate1, aBadRate2; // to what extent a set is bad
1197 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1198 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1199 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1202 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1203 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1206 return 1; // diagonal 1-3
1208 return 2; // diagonal 2-4
1215 // Methods of splitting volumes into tetra
1217 const int theHexTo5_1[5*4+1] =
1219 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1221 const int theHexTo5_2[5*4+1] =
1223 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1225 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1227 const int theHexTo6_1[6*4+1] =
1229 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
1231 const int theHexTo6_2[6*4+1] =
1233 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
1235 const int theHexTo6_3[6*4+1] =
1237 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
1239 const int theHexTo6_4[6*4+1] =
1241 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
1243 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1245 const int thePyraTo2_1[2*4+1] =
1247 0, 1, 2, 4, 0, 2, 3, 4, -1
1249 const int thePyraTo2_2[2*4+1] =
1251 1, 2, 3, 4, 1, 3, 0, 4, -1
1253 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1255 const int thePentaTo3_1[3*4+1] =
1257 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1259 const int thePentaTo3_2[3*4+1] =
1261 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1263 const int thePentaTo3_3[3*4+1] =
1265 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1267 const int thePentaTo3_4[3*4+1] =
1269 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1271 const int thePentaTo3_5[3*4+1] =
1273 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1275 const int thePentaTo3_6[3*4+1] =
1277 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1279 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1280 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1282 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1285 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1286 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1287 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1292 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1293 bool _baryNode; //!< additional node is to be created at cell barycenter
1294 bool _ownConn; //!< to delete _connectivity in destructor
1295 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1297 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1298 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1299 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1300 bool hasFacet( const TTriangleFacet& facet ) const
1302 const int* tetConn = _connectivity;
1303 for ( ; tetConn[0] >= 0; tetConn += 4 )
1304 if (( facet.contains( tetConn[0] ) +
1305 facet.contains( tetConn[1] ) +
1306 facet.contains( tetConn[2] ) +
1307 facet.contains( tetConn[3] )) == 3 )
1313 //=======================================================================
1315 * \brief return TSplitMethod for the given element
1317 //=======================================================================
1319 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1321 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1323 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1324 // an edge and a face barycenter; tertaherdons are based on triangles and
1325 // a volume barycenter
1326 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1328 // Find out how adjacent volumes are split
1330 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1331 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1332 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1334 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1335 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1336 if ( nbNodes < 4 ) continue;
1338 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1339 const int* nInd = vol.GetFaceNodesIndices( iF );
1342 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1343 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1344 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1345 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1349 int iCom = 0; // common node of triangle faces to split into
1350 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1352 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1353 nInd[ iQ * ( (iCom+1)%nbNodes )],
1354 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1355 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1356 nInd[ iQ * ( (iCom+2)%nbNodes )],
1357 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1358 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1360 triaSplits.push_back( t012 );
1361 triaSplits.push_back( t023 );
1366 if ( !triaSplits.empty() )
1367 hasAdjacentSplits = true;
1370 // Among variants of split method select one compliant with adjacent volumes
1372 TSplitMethod method;
1373 if ( !vol.Element()->IsPoly() && !is24TetMode )
1375 int nbVariants = 2, nbTet = 0;
1376 const int** connVariants = 0;
1377 switch ( vol.Element()->GetEntityType() )
1379 case SMDSEntity_Hexa:
1380 case SMDSEntity_Quad_Hexa:
1381 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1382 connVariants = theHexTo5, nbTet = 5;
1384 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1386 case SMDSEntity_Pyramid:
1387 case SMDSEntity_Quad_Pyramid:
1388 connVariants = thePyraTo2; nbTet = 2;
1390 case SMDSEntity_Penta:
1391 case SMDSEntity_Quad_Penta:
1392 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1397 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1399 // check method compliancy with adjacent tetras,
1400 // all found splits must be among facets of tetras described by this method
1401 method = TSplitMethod( nbTet, connVariants[variant] );
1402 if ( hasAdjacentSplits && method._nbTetra > 0 )
1404 bool facetCreated = true;
1405 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1407 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1408 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1409 facetCreated = method.hasFacet( *facet );
1411 if ( !facetCreated )
1412 method = TSplitMethod(0); // incompatible method
1416 if ( method._nbTetra < 1 )
1418 // No standard method is applicable, use a generic solution:
1419 // each facet of a volume is split into triangles and
1420 // each of triangles and a volume barycenter form a tetrahedron.
1422 int* connectivity = new int[ maxTetConnSize + 1 ];
1423 method._connectivity = connectivity;
1424 method._ownConn = true;
1425 method._baryNode = true;
1428 int baryCenInd = vol.NbNodes();
1429 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1431 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1432 const int* nInd = vol.GetFaceNodesIndices( iF );
1433 // find common node of triangle facets of tetra to create
1434 int iCommon = 0; // index in linear numeration
1435 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1436 if ( !triaSplits.empty() )
1439 const TTriangleFacet* facet = &triaSplits.front();
1440 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1441 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1442 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1445 else if ( nbNodes > 3 && !is24TetMode )
1447 // find the best method of splitting into triangles by aspect ratio
1448 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1449 map< double, int > badness2iCommon;
1450 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1451 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1452 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1453 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1455 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1456 nodes[ iQ*((iLast-1)%nbNodes)],
1457 nodes[ iQ*((iLast )%nbNodes)]);
1458 double badness = getBadRate( &tria, aspectRatio );
1459 badness2iCommon.insert( make_pair( badness, iCommon ));
1461 // use iCommon with lowest badness
1462 iCommon = badness2iCommon.begin()->second;
1464 if ( iCommon >= nbNodes )
1465 iCommon = 0; // something wrong
1467 // fill connectivity of tetrahedra based on a current face
1468 int nbTet = nbNodes - 2;
1469 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1471 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1472 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1474 for ( int i = 0; i < nbTet; ++i )
1476 int i1 = i, i2 = (i+1) % nbNodes;
1477 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1478 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1479 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1480 connectivity[ connSize++ ] = faceBaryCenInd;
1481 connectivity[ connSize++ ] = baryCenInd;
1486 for ( int i = 0; i < nbTet; ++i )
1488 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1489 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1490 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1491 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493 connectivity[ connSize++ ] = baryCenInd;
1496 method._nbTetra += nbTet;
1498 connectivity[ connSize++ ] = -1;
1502 //================================================================================
1504 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1506 //================================================================================
1508 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1510 // find the tetrahedron including the three nodes of facet
1511 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1512 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1513 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1514 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1515 while ( volIt1->more() )
1517 const SMDS_MeshElement* v = volIt1->next();
1518 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1520 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1521 while ( volIt2->more() )
1522 if ( v != volIt2->next() )
1524 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1525 while ( volIt3->more() )
1526 if ( v == volIt3->next() )
1532 //=======================================================================
1534 * \brief A key of a face of volume
1536 //=======================================================================
1538 struct TVolumeFaceKey: pair< int, pair< int, int> >
1540 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1542 TIDSortedNodeSet sortedNodes;
1543 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1544 int nbNodes = vol.NbFaceNodes( iF );
1545 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1546 for ( int i = 0; i < nbNodes; i += iQ )
1547 sortedNodes.insert( fNodes[i] );
1548 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1549 first = (*(n++))->GetID();
1550 second.first = (*(n++))->GetID();
1551 second.second = (*(n++))->GetID();
1556 //=======================================================================
1557 //function : SplitVolumesIntoTetra
1558 //purpose : Split volumic elements into tetrahedra.
1559 //=======================================================================
1561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1562 const int theMethodFlags)
1564 // std-like iterator on coordinates of nodes of mesh element
1565 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1566 NXyzIterator xyzEnd;
1568 SMDS_VolumeTool volTool;
1569 SMESH_MesherHelper helper( *GetMesh());
1571 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1572 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1574 SMESH_SequenceOfElemPtr newNodes, newElems;
1576 // map face of volume to it's baricenrtic node
1577 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1580 TIDSortedElemSet::const_iterator elem = theElems.begin();
1581 for ( ; elem != theElems.end(); ++elem )
1583 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1584 if ( geomType <= SMDSEntity_Quad_Tetra )
1585 continue; // tetra or face or ...
1587 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1589 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1590 if ( splitMethod._nbTetra < 1 ) continue;
1592 // find submesh to add new tetras to
1593 if ( !subMesh || !subMesh->Contains( *elem ))
1595 int shapeID = FindShape( *elem );
1596 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1597 subMesh = GetMeshDS()->MeshElements( shapeID );
1600 if ( (*elem)->IsQuadratic() )
1603 // add quadratic links to the helper
1604 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1606 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1607 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1608 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1610 helper.SetIsQuadratic( true );
1615 helper.SetIsQuadratic( false );
1617 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1618 helper.SetElementsOnShape( true );
1619 if ( splitMethod._baryNode )
1621 // make a node at barycenter
1622 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1623 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1624 nodes.push_back( gcNode );
1625 newNodes.Append( gcNode );
1627 if ( !splitMethod._faceBaryNode.empty() )
1629 // make or find baricentric nodes of faces
1630 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1631 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1633 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1634 volFace2BaryNode.insert
1635 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1638 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1639 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1641 nodes.push_back( iF_n->second = f_n->second );
1646 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1647 const int* tetConn = splitMethod._connectivity;
1648 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1649 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1650 nodes[ tetConn[1] ],
1651 nodes[ tetConn[2] ],
1652 nodes[ tetConn[3] ]));
1654 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1656 // Split faces on sides of the split volume
1658 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1659 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1661 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1662 if ( nbNodes < 4 ) continue;
1664 // find an existing face
1665 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1666 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1667 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1670 helper.SetElementsOnShape( false );
1671 vector< const SMDS_MeshElement* > triangles;
1673 // find submesh to add new triangles in
1674 if ( !fSubMesh || !fSubMesh->Contains( face ))
1676 int shapeID = FindShape( face );
1677 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1679 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1680 if ( iF_n != splitMethod._faceBaryNode.end() )
1682 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1684 const SMDS_MeshNode* n1 = fNodes[iN];
1685 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1686 const SMDS_MeshNode *n3 = iF_n->second;
1687 if ( !volTool.IsFaceExternal( iF ))
1689 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1691 if ( n3->getshapeId() < 1 )
1692 fSubMesh->AddNode( n3 );
1697 // among possible triangles create ones discribed by split method
1698 const int* nInd = volTool.GetFaceNodesIndices( iF );
1699 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1700 int iCom = 0; // common node of triangle faces to split into
1701 list< TTriangleFacet > facets;
1702 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1704 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1705 nInd[ iQ * ( (iCom+1)%nbNodes )],
1706 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1707 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1708 nInd[ iQ * ( (iCom+2)%nbNodes )],
1709 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1710 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1712 facets.push_back( t012 );
1713 facets.push_back( t023 );
1714 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1715 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1716 nInd[ iQ * ((iLast-1)%nbNodes )],
1717 nInd[ iQ * ((iLast )%nbNodes )]));
1721 list< TTriangleFacet >::iterator facet = facets.begin();
1722 for ( ; facet != facets.end(); ++facet )
1724 if ( !volTool.IsFaceExternal( iF ))
1725 swap( facet->_n2, facet->_n3 );
1726 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1727 volNodes[ facet->_n2 ],
1728 volNodes[ facet->_n3 ]));
1731 for ( int i = 0; i < triangles.size(); ++i )
1733 if ( !triangles[i] ) continue;
1735 fSubMesh->AddElement( triangles[i]);
1736 newElems.Append( triangles[i] );
1738 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1739 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1742 } // loop on volume faces to split them into triangles
1744 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1746 } // loop on volumes to split
1748 myLastCreatedNodes = newNodes;
1749 myLastCreatedElems = newElems;
1752 //=======================================================================
1753 //function : AddToSameGroups
1754 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1755 //=======================================================================
1757 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1758 const SMDS_MeshElement* elemInGroups,
1759 SMESHDS_Mesh * aMesh)
1761 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1762 if (!groups.empty()) {
1763 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1764 for ( ; grIt != groups.end(); grIt++ ) {
1765 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1766 if ( group && group->Contains( elemInGroups ))
1767 group->SMDSGroup().Add( elemToAdd );
1773 //=======================================================================
1774 //function : RemoveElemFromGroups
1775 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1776 //=======================================================================
1777 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1778 SMESHDS_Mesh * aMesh)
1780 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1781 if (!groups.empty())
1783 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1784 for (; GrIt != groups.end(); GrIt++)
1786 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1787 if (!grp || grp->IsEmpty()) continue;
1788 grp->SMDSGroup().Remove(removeelem);
1793 //================================================================================
1795 * \brief Replace elemToRm by elemToAdd in the all groups
1797 //================================================================================
1799 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1800 const SMDS_MeshElement* elemToAdd,
1801 SMESHDS_Mesh * aMesh)
1803 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1804 if (!groups.empty()) {
1805 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1806 for ( ; grIt != groups.end(); grIt++ ) {
1807 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1808 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1809 group->SMDSGroup().Add( elemToAdd );
1814 //================================================================================
1816 * \brief Replace elemToRm by elemToAdd in the all groups
1818 //================================================================================
1820 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1821 const vector<const SMDS_MeshElement*>& elemToAdd,
1822 SMESHDS_Mesh * aMesh)
1824 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1825 if (!groups.empty())
1827 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1828 for ( ; grIt != groups.end(); grIt++ ) {
1829 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1830 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1831 for ( int i = 0; i < elemToAdd.size(); ++i )
1832 group->SMDSGroup().Add( elemToAdd[ i ] );
1837 //=======================================================================
1838 //function : QuadToTri
1839 //purpose : Cut quadrangles into triangles.
1840 // theCrit is used to select a diagonal to cut
1841 //=======================================================================
1843 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1844 const bool the13Diag)
1846 myLastCreatedElems.Clear();
1847 myLastCreatedNodes.Clear();
1849 MESSAGE( "::QuadToTri()" );
1851 SMESHDS_Mesh * aMesh = GetMeshDS();
1853 Handle(Geom_Surface) surface;
1854 SMESH_MesherHelper helper( *GetMesh() );
1856 TIDSortedElemSet::iterator itElem;
1857 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1858 const SMDS_MeshElement* elem = *itElem;
1859 if ( !elem || elem->GetType() != SMDSAbs_Face )
1861 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1862 if(!isquad) continue;
1864 if(elem->NbNodes()==4) {
1865 // retrieve element nodes
1866 const SMDS_MeshNode* aNodes [4];
1867 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1869 while ( itN->more() )
1870 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1872 int aShapeId = FindShape( elem );
1873 const SMDS_MeshElement* newElem1 = 0;
1874 const SMDS_MeshElement* newElem2 = 0;
1876 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1877 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1880 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1881 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1883 myLastCreatedElems.Append(newElem1);
1884 myLastCreatedElems.Append(newElem2);
1885 // put a new triangle on the same shape and add to the same groups
1888 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1889 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1891 AddToSameGroups( newElem1, elem, aMesh );
1892 AddToSameGroups( newElem2, elem, aMesh );
1893 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1894 aMesh->RemoveElement( elem );
1897 // Quadratic quadrangle
1899 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1901 // get surface elem is on
1902 int aShapeId = FindShape( elem );
1903 if ( aShapeId != helper.GetSubShapeID() ) {
1907 shape = aMesh->IndexToShape( aShapeId );
1908 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1909 TopoDS_Face face = TopoDS::Face( shape );
1910 surface = BRep_Tool::Surface( face );
1911 if ( !surface.IsNull() )
1912 helper.SetSubShape( shape );
1916 const SMDS_MeshNode* aNodes [8];
1917 const SMDS_MeshNode* inFaceNode = 0;
1918 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1920 while ( itN->more() ) {
1921 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1922 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1923 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1925 inFaceNode = aNodes[ i-1 ];
1929 // find middle point for (0,1,2,3)
1930 // and create a node in this point;
1932 if ( surface.IsNull() ) {
1934 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1938 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1941 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1943 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1945 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1946 myLastCreatedNodes.Append(newN);
1948 // create a new element
1949 const SMDS_MeshElement* newElem1 = 0;
1950 const SMDS_MeshElement* newElem2 = 0;
1952 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1953 aNodes[6], aNodes[7], newN );
1954 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1955 newN, aNodes[4], aNodes[5] );
1958 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1959 aNodes[7], aNodes[4], newN );
1960 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1961 newN, aNodes[5], aNodes[6] );
1963 myLastCreatedElems.Append(newElem1);
1964 myLastCreatedElems.Append(newElem2);
1965 // put a new triangle on the same shape and add to the same groups
1968 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1969 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1971 AddToSameGroups( newElem1, elem, aMesh );
1972 AddToSameGroups( newElem2, elem, aMesh );
1973 aMesh->RemoveElement( elem );
1980 //=======================================================================
1981 //function : getAngle
1983 //=======================================================================
1985 double getAngle(const SMDS_MeshElement * tr1,
1986 const SMDS_MeshElement * tr2,
1987 const SMDS_MeshNode * n1,
1988 const SMDS_MeshNode * n2)
1990 double angle = 2*PI; // bad angle
1993 SMESH::Controls::TSequenceOfXYZ P1, P2;
1994 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1995 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1998 if(!tr1->IsQuadratic())
1999 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2001 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2002 if ( N1.SquareMagnitude() <= gp::Resolution() )
2004 if(!tr2->IsQuadratic())
2005 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2007 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2008 if ( N2.SquareMagnitude() <= gp::Resolution() )
2011 // find the first diagonal node n1 in the triangles:
2012 // take in account a diagonal link orientation
2013 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2014 for ( int t = 0; t < 2; t++ ) {
2015 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2016 int i = 0, iDiag = -1;
2017 while ( it->more()) {
2018 const SMDS_MeshElement *n = it->next();
2019 if ( n == n1 || n == n2 ) {
2023 if ( i - iDiag == 1 )
2024 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2033 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2036 angle = N1.Angle( N2 );
2041 // =================================================
2042 // class generating a unique ID for a pair of nodes
2043 // and able to return nodes by that ID
2044 // =================================================
2048 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2049 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2052 long GetLinkID (const SMDS_MeshNode * n1,
2053 const SMDS_MeshNode * n2) const
2055 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2058 bool GetNodes (const long theLinkID,
2059 const SMDS_MeshNode* & theNode1,
2060 const SMDS_MeshNode* & theNode2) const
2062 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2063 if ( !theNode1 ) return false;
2064 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2065 if ( !theNode2 ) return false;
2071 const SMESHDS_Mesh* myMesh;
2076 //=======================================================================
2077 //function : TriToQuad
2078 //purpose : Fuse neighbour triangles into quadrangles.
2079 // theCrit is used to select a neighbour to fuse with.
2080 // theMaxAngle is a max angle between element normals at which
2081 // fusion is still performed.
2082 //=======================================================================
2084 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2085 SMESH::Controls::NumericalFunctorPtr theCrit,
2086 const double theMaxAngle)
2088 myLastCreatedElems.Clear();
2089 myLastCreatedNodes.Clear();
2091 MESSAGE( "::TriToQuad()" );
2093 if ( !theCrit.get() )
2096 SMESHDS_Mesh * aMesh = GetMeshDS();
2098 // Prepare data for algo: build
2099 // 1. map of elements with their linkIDs
2100 // 2. map of linkIDs with their elements
2102 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2103 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2104 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2105 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2107 TIDSortedElemSet::iterator itElem;
2108 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2109 const SMDS_MeshElement* elem = *itElem;
2110 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2111 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2112 if(!IsTria) continue;
2114 // retrieve element nodes
2115 const SMDS_MeshNode* aNodes [4];
2116 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2119 aNodes[ i++ ] = cast2Node( itN->next() );
2120 aNodes[ 3 ] = aNodes[ 0 ];
2123 for ( i = 0; i < 3; i++ ) {
2124 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2125 // check if elements sharing a link can be fused
2126 itLE = mapLi_listEl.find( link );
2127 if ( itLE != mapLi_listEl.end() ) {
2128 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2130 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2131 //if ( FindShape( elem ) != FindShape( elem2 ))
2132 // continue; // do not fuse triangles laying on different shapes
2133 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2134 continue; // avoid making badly shaped quads
2135 (*itLE).second.push_back( elem );
2138 mapLi_listEl[ link ].push_back( elem );
2140 mapEl_setLi [ elem ].insert( link );
2143 // Clean the maps from the links shared by a sole element, ie
2144 // links to which only one element is bound in mapLi_listEl
2146 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2147 int nbElems = (*itLE).second.size();
2148 if ( nbElems < 2 ) {
2149 const SMDS_MeshElement* elem = (*itLE).second.front();
2150 SMESH_TLink link = (*itLE).first;
2151 mapEl_setLi[ elem ].erase( link );
2152 if ( mapEl_setLi[ elem ].empty() )
2153 mapEl_setLi.erase( elem );
2157 // Algo: fuse triangles into quadrangles
2159 while ( ! mapEl_setLi.empty() ) {
2160 // Look for the start element:
2161 // the element having the least nb of shared links
2162 const SMDS_MeshElement* startElem = 0;
2164 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2165 int nbLinks = (*itEL).second.size();
2166 if ( nbLinks < minNbLinks ) {
2167 startElem = (*itEL).first;
2168 minNbLinks = nbLinks;
2169 if ( minNbLinks == 1 )
2174 // search elements to fuse starting from startElem or links of elements
2175 // fused earlyer - startLinks
2176 list< SMESH_TLink > startLinks;
2177 while ( startElem || !startLinks.empty() ) {
2178 while ( !startElem && !startLinks.empty() ) {
2179 // Get an element to start, by a link
2180 SMESH_TLink linkId = startLinks.front();
2181 startLinks.pop_front();
2182 itLE = mapLi_listEl.find( linkId );
2183 if ( itLE != mapLi_listEl.end() ) {
2184 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2185 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2186 for ( ; itE != listElem.end() ; itE++ )
2187 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2189 mapLi_listEl.erase( itLE );
2194 // Get candidates to be fused
2195 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2196 const SMESH_TLink *link12, *link13;
2198 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2199 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2200 ASSERT( !setLi.empty() );
2201 set< SMESH_TLink >::iterator itLi;
2202 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2204 const SMESH_TLink & link = (*itLi);
2205 itLE = mapLi_listEl.find( link );
2206 if ( itLE == mapLi_listEl.end() )
2209 const SMDS_MeshElement* elem = (*itLE).second.front();
2211 elem = (*itLE).second.back();
2212 mapLi_listEl.erase( itLE );
2213 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2224 // add other links of elem to list of links to re-start from
2225 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2226 set< SMESH_TLink >::iterator it;
2227 for ( it = links.begin(); it != links.end(); it++ ) {
2228 const SMESH_TLink& link2 = (*it);
2229 if ( link2 != link )
2230 startLinks.push_back( link2 );
2234 // Get nodes of possible quadrangles
2235 const SMDS_MeshNode *n12 [4], *n13 [4];
2236 bool Ok12 = false, Ok13 = false;
2237 const SMDS_MeshNode *linkNode1, *linkNode2;
2239 linkNode1 = link12->first;
2240 linkNode2 = link12->second;
2241 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2245 linkNode1 = link13->first;
2246 linkNode2 = link13->second;
2247 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2251 // Choose a pair to fuse
2252 if ( Ok12 && Ok13 ) {
2253 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2254 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2255 double aBadRate12 = getBadRate( &quad12, theCrit );
2256 double aBadRate13 = getBadRate( &quad13, theCrit );
2257 if ( aBadRate13 < aBadRate12 )
2264 // and remove fused elems and removed links from the maps
2265 mapEl_setLi.erase( tr1 );
2267 mapEl_setLi.erase( tr2 );
2268 mapLi_listEl.erase( *link12 );
2269 if(tr1->NbNodes()==3) {
2270 const SMDS_MeshElement* newElem = 0;
2271 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2272 myLastCreatedElems.Append(newElem);
2273 AddToSameGroups( newElem, tr1, aMesh );
2274 int aShapeId = tr1->getshapeId();
2277 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2279 aMesh->RemoveElement( tr1 );
2280 aMesh->RemoveElement( tr2 );
2283 const SMDS_MeshNode* N1 [6];
2284 const SMDS_MeshNode* N2 [6];
2285 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2286 // now we receive following N1 and N2 (using numeration as above image)
2287 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2288 // i.e. first nodes from both arrays determ new diagonal
2289 const SMDS_MeshNode* aNodes[8];
2298 const SMDS_MeshElement* newElem = 0;
2299 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2300 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2301 myLastCreatedElems.Append(newElem);
2302 AddToSameGroups( newElem, tr1, aMesh );
2303 int aShapeId = tr1->getshapeId();
2306 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2308 aMesh->RemoveElement( tr1 );
2309 aMesh->RemoveElement( tr2 );
2310 // remove middle node (9)
2311 GetMeshDS()->RemoveNode( N1[4] );
2315 mapEl_setLi.erase( tr3 );
2316 mapLi_listEl.erase( *link13 );
2317 if(tr1->NbNodes()==3) {
2318 const SMDS_MeshElement* newElem = 0;
2319 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2320 myLastCreatedElems.Append(newElem);
2321 AddToSameGroups( newElem, tr1, aMesh );
2322 int aShapeId = tr1->getshapeId();
2325 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2327 aMesh->RemoveElement( tr1 );
2328 aMesh->RemoveElement( tr3 );
2331 const SMDS_MeshNode* N1 [6];
2332 const SMDS_MeshNode* N2 [6];
2333 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2334 // now we receive following N1 and N2 (using numeration as above image)
2335 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2336 // i.e. first nodes from both arrays determ new diagonal
2337 const SMDS_MeshNode* aNodes[8];
2346 const SMDS_MeshElement* newElem = 0;
2347 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2348 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2349 myLastCreatedElems.Append(newElem);
2350 AddToSameGroups( newElem, tr1, aMesh );
2351 int aShapeId = tr1->getshapeId();
2354 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2356 aMesh->RemoveElement( tr1 );
2357 aMesh->RemoveElement( tr3 );
2358 // remove middle node (9)
2359 GetMeshDS()->RemoveNode( N1[4] );
2363 // Next element to fuse: the rejected one
2365 startElem = Ok12 ? tr3 : tr2;
2367 } // if ( startElem )
2368 } // while ( startElem || !startLinks.empty() )
2369 } // while ( ! mapEl_setLi.empty() )
2375 /*#define DUMPSO(txt) \
2376 // cout << txt << endl;
2377 //=============================================================================
2381 //=============================================================================
2382 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2386 int tmp = idNodes[ i1 ];
2387 idNodes[ i1 ] = idNodes[ i2 ];
2388 idNodes[ i2 ] = tmp;
2389 gp_Pnt Ptmp = P[ i1 ];
2392 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2395 //=======================================================================
2396 //function : SortQuadNodes
2397 //purpose : Set 4 nodes of a quadrangle face in a good order.
2398 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2400 //=======================================================================
2402 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2407 for ( i = 0; i < 4; i++ ) {
2408 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2410 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2413 gp_Vec V1(P[0], P[1]);
2414 gp_Vec V2(P[0], P[2]);
2415 gp_Vec V3(P[0], P[3]);
2417 gp_Vec Cross1 = V1 ^ V2;
2418 gp_Vec Cross2 = V2 ^ V3;
2421 if (Cross1.Dot(Cross2) < 0)
2426 if (Cross1.Dot(Cross2) < 0)
2430 swap ( i, i + 1, idNodes, P );
2432 // for ( int ii = 0; ii < 4; ii++ ) {
2433 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2434 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2440 //=======================================================================
2441 //function : SortHexaNodes
2442 //purpose : Set 8 nodes of a hexahedron in a good order.
2443 // Return success status
2444 //=======================================================================
2446 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2451 DUMPSO( "INPUT: ========================================");
2452 for ( i = 0; i < 8; i++ ) {
2453 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2454 if ( !n ) return false;
2455 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2456 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2458 DUMPSO( "========================================");
2461 set<int> faceNodes; // ids of bottom face nodes, to be found
2462 set<int> checkedId1; // ids of tried 2-nd nodes
2463 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2464 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2465 int iMin, iLoop1 = 0;
2467 // Loop to try the 2-nd nodes
2469 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2471 // Find not checked 2-nd node
2472 for ( i = 1; i < 8; i++ )
2473 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2474 int id1 = idNodes[i];
2475 swap ( 1, i, idNodes, P );
2476 checkedId1.insert ( id1 );
2480 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2481 // ie that all but meybe one (id3 which is on the same face) nodes
2482 // lay on the same side from the triangle plane.
2484 bool manyInPlane = false; // more than 4 nodes lay in plane
2486 while ( ++iLoop2 < 6 ) {
2488 // get 1-2-3 plane coeffs
2489 Standard_Real A, B, C, D;
2490 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2491 if ( N.SquareMagnitude() > gp::Resolution() )
2493 gp_Pln pln ( P[0], N );
2494 pln.Coefficients( A, B, C, D );
2496 // find the node (iMin) closest to pln
2497 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2499 for ( i = 3; i < 8; i++ ) {
2500 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2501 if ( fabs( dist[i] ) < minDist ) {
2502 minDist = fabs( dist[i] );
2505 if ( fabs( dist[i] ) <= tol )
2506 idInPln.insert( idNodes[i] );
2509 // there should not be more than 4 nodes in bottom plane
2510 if ( idInPln.size() > 1 )
2512 DUMPSO( "### idInPln.size() = " << idInPln.size());
2513 // idInPlane does not contain the first 3 nodes
2514 if ( manyInPlane || idInPln.size() == 5)
2515 return false; // all nodes in one plane
2518 // set the 1-st node to be not in plane
2519 for ( i = 3; i < 8; i++ ) {
2520 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2521 DUMPSO( "### Reset 0-th node");
2522 swap( 0, i, idNodes, P );
2527 // reset to re-check second nodes
2528 leastDist = DBL_MAX;
2532 break; // from iLoop2;
2535 // check that the other 4 nodes are on the same side
2536 bool sameSide = true;
2537 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2538 for ( i = 3; sameSide && i < 8; i++ ) {
2540 sameSide = ( isNeg == dist[i] <= 0.);
2543 // keep best solution
2544 if ( sameSide && minDist < leastDist ) {
2545 leastDist = minDist;
2547 faceNodes.insert( idNodes[ 1 ] );
2548 faceNodes.insert( idNodes[ 2 ] );
2549 faceNodes.insert( idNodes[ iMin ] );
2550 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2551 << " leastDist = " << leastDist);
2552 if ( leastDist <= DBL_MIN )
2557 // set next 3-d node to check
2558 int iNext = 2 + iLoop2;
2560 DUMPSO( "Try 2-nd");
2561 swap ( 2, iNext, idNodes, P );
2563 } // while ( iLoop2 < 6 )
2566 if ( faceNodes.empty() ) return false;
2568 // Put the faceNodes in proper places
2569 for ( i = 4; i < 8; i++ ) {
2570 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2571 // find a place to put
2573 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2575 DUMPSO( "Set faceNodes");
2576 swap ( iTo, i, idNodes, P );
2581 // Set nodes of the found bottom face in good order
2582 DUMPSO( " Found bottom face: ");
2583 i = SortQuadNodes( theMesh, idNodes );
2585 gp_Pnt Ptmp = P[ i ];
2590 // for ( int ii = 0; ii < 4; ii++ ) {
2591 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2592 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2595 // Gravity center of the top and bottom faces
2596 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2597 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2599 // Get direction from the bottom to the top face
2600 gp_Vec upDir ( aGCb, aGCt );
2601 Standard_Real upDirSize = upDir.Magnitude();
2602 if ( upDirSize <= gp::Resolution() ) return false;
2605 // Assure that the bottom face normal points up
2606 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2607 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2608 if ( Nb.Dot( upDir ) < 0 ) {
2609 DUMPSO( "Reverse bottom face");
2610 swap( 1, 3, idNodes, P );
2613 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2614 Standard_Real minDist = DBL_MAX;
2615 for ( i = 4; i < 8; i++ ) {
2616 // projection of P[i] to the plane defined by P[0] and upDir
2617 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2618 Standard_Real sqDist = P[0].SquareDistance( Pp );
2619 if ( sqDist < minDist ) {
2624 DUMPSO( "Set 4-th");
2625 swap ( 4, iMin, idNodes, P );
2627 // Set nodes of the top face in good order
2628 DUMPSO( "Sort top face");
2629 i = SortQuadNodes( theMesh, &idNodes[4] );
2632 gp_Pnt Ptmp = P[ i ];
2637 // Assure that direction of the top face normal is from the bottom face
2638 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2639 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2640 if ( Nt.Dot( upDir ) < 0 ) {
2641 DUMPSO( "Reverse top face");
2642 swap( 5, 7, idNodes, P );
2645 // DUMPSO( "OUTPUT: ========================================");
2646 // for ( i = 0; i < 8; i++ ) {
2647 // float *p = ugrid->GetPoint(idNodes[i]);
2648 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2654 //================================================================================
2656 * \brief Return nodes linked to the given one
2657 * \param theNode - the node
2658 * \param linkedNodes - the found nodes
2659 * \param type - the type of elements to check
2661 * Medium nodes are ignored
2663 //================================================================================
2665 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2666 TIDSortedElemSet & linkedNodes,
2667 SMDSAbs_ElementType type )
2669 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2670 while ( elemIt->more() )
2672 const SMDS_MeshElement* elem = elemIt->next();
2673 if(elem->GetType() == SMDSAbs_0DElement)
2676 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2677 if ( elem->GetType() == SMDSAbs_Volume )
2679 SMDS_VolumeTool vol( elem );
2680 while ( nodeIt->more() ) {
2681 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2682 if ( theNode != n && vol.IsLinked( theNode, n ))
2683 linkedNodes.insert( n );
2688 for ( int i = 0; nodeIt->more(); ++i ) {
2689 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2690 if ( n == theNode ) {
2691 int iBefore = i - 1;
2693 if ( elem->IsQuadratic() ) {
2694 int nb = elem->NbNodes() / 2;
2695 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2696 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2698 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2699 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2706 //=======================================================================
2707 //function : laplacianSmooth
2708 //purpose : pulls theNode toward the center of surrounding nodes directly
2709 // connected to that node along an element edge
2710 //=======================================================================
2712 void laplacianSmooth(const SMDS_MeshNode* theNode,
2713 const Handle(Geom_Surface)& theSurface,
2714 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2716 // find surrounding nodes
2718 TIDSortedElemSet nodeSet;
2719 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2721 // compute new coodrs
2723 double coord[] = { 0., 0., 0. };
2724 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2725 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2726 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2727 if ( theSurface.IsNull() ) { // smooth in 3D
2728 coord[0] += node->X();
2729 coord[1] += node->Y();
2730 coord[2] += node->Z();
2732 else { // smooth in 2D
2733 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2734 gp_XY* uv = theUVMap[ node ];
2735 coord[0] += uv->X();
2736 coord[1] += uv->Y();
2739 int nbNodes = nodeSet.size();
2742 coord[0] /= nbNodes;
2743 coord[1] /= nbNodes;
2745 if ( !theSurface.IsNull() ) {
2746 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2747 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2748 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2754 coord[2] /= nbNodes;
2758 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2761 //=======================================================================
2762 //function : centroidalSmooth
2763 //purpose : pulls theNode toward the element-area-weighted centroid of the
2764 // surrounding elements
2765 //=======================================================================
2767 void centroidalSmooth(const SMDS_MeshNode* theNode,
2768 const Handle(Geom_Surface)& theSurface,
2769 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2771 gp_XYZ aNewXYZ(0.,0.,0.);
2772 SMESH::Controls::Area anAreaFunc;
2773 double totalArea = 0.;
2778 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2779 while ( elemIt->more() )
2781 const SMDS_MeshElement* elem = elemIt->next();
2784 gp_XYZ elemCenter(0.,0.,0.);
2785 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2786 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2787 int nn = elem->NbNodes();
2788 if(elem->IsQuadratic()) nn = nn/2;
2790 //while ( itN->more() ) {
2792 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2794 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2795 aNodePoints.push_back( aP );
2796 if ( !theSurface.IsNull() ) { // smooth in 2D
2797 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2798 gp_XY* uv = theUVMap[ aNode ];
2799 aP.SetCoord( uv->X(), uv->Y(), 0. );
2803 double elemArea = anAreaFunc.GetValue( aNodePoints );
2804 totalArea += elemArea;
2806 aNewXYZ += elemCenter * elemArea;
2808 aNewXYZ /= totalArea;
2809 if ( !theSurface.IsNull() ) {
2810 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2811 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2816 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2819 //=======================================================================
2820 //function : getClosestUV
2821 //purpose : return UV of closest projection
2822 //=======================================================================
2824 static bool getClosestUV (Extrema_GenExtPS& projector,
2825 const gp_Pnt& point,
2828 projector.Perform( point );
2829 if ( projector.IsDone() ) {
2830 double u, v, minVal = DBL_MAX;
2831 for ( int i = projector.NbExt(); i > 0; i-- )
2832 if ( projector.Value( i ) < minVal ) {
2833 minVal = projector.Value( i );
2834 projector.Point( i ).Parameter( u, v );
2836 result.SetCoord( u, v );
2842 //=======================================================================
2844 //purpose : Smooth theElements during theNbIterations or until a worst
2845 // element has aspect ratio <= theTgtAspectRatio.
2846 // Aspect Ratio varies in range [1.0, inf].
2847 // If theElements is empty, the whole mesh is smoothed.
2848 // theFixedNodes contains additionally fixed nodes. Nodes built
2849 // on edges and boundary nodes are always fixed.
2850 //=======================================================================
2852 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2853 set<const SMDS_MeshNode*> & theFixedNodes,
2854 const SmoothMethod theSmoothMethod,
2855 const int theNbIterations,
2856 double theTgtAspectRatio,
2859 myLastCreatedElems.Clear();
2860 myLastCreatedNodes.Clear();
2862 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2864 if ( theTgtAspectRatio < 1.0 )
2865 theTgtAspectRatio = 1.0;
2867 const double disttol = 1.e-16;
2869 SMESH::Controls::AspectRatio aQualityFunc;
2871 SMESHDS_Mesh* aMesh = GetMeshDS();
2873 if ( theElems.empty() ) {
2874 // add all faces to theElems
2875 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2876 while ( fIt->more() ) {
2877 const SMDS_MeshElement* face = fIt->next();
2878 theElems.insert( face );
2881 // get all face ids theElems are on
2882 set< int > faceIdSet;
2883 TIDSortedElemSet::iterator itElem;
2885 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2886 int fId = FindShape( *itElem );
2887 // check that corresponding submesh exists and a shape is face
2889 faceIdSet.find( fId ) == faceIdSet.end() &&
2890 aMesh->MeshElements( fId )) {
2891 TopoDS_Shape F = aMesh->IndexToShape( fId );
2892 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2893 faceIdSet.insert( fId );
2896 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2898 // ===============================================
2899 // smooth elements on each TopoDS_Face separately
2900 // ===============================================
2902 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2903 for ( ; fId != faceIdSet.rend(); ++fId ) {
2904 // get face surface and submesh
2905 Handle(Geom_Surface) surface;
2906 SMESHDS_SubMesh* faceSubMesh = 0;
2908 double fToler2 = 0, f,l;
2909 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2910 bool isUPeriodic = false, isVPeriodic = false;
2912 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2913 surface = BRep_Tool::Surface( face );
2914 faceSubMesh = aMesh->MeshElements( *fId );
2915 fToler2 = BRep_Tool::Tolerance( face );
2916 fToler2 *= fToler2 * 10.;
2917 isUPeriodic = surface->IsUPeriodic();
2920 isVPeriodic = surface->IsVPeriodic();
2923 surface->Bounds( u1, u2, v1, v2 );
2925 // ---------------------------------------------------------
2926 // for elements on a face, find movable and fixed nodes and
2927 // compute UV for them
2928 // ---------------------------------------------------------
2929 bool checkBoundaryNodes = false;
2930 bool isQuadratic = false;
2931 set<const SMDS_MeshNode*> setMovableNodes;
2932 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2933 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2934 list< const SMDS_MeshElement* > elemsOnFace;
2936 Extrema_GenExtPS projector;
2937 GeomAdaptor_Surface surfAdaptor;
2938 if ( !surface.IsNull() ) {
2939 surfAdaptor.Load( surface );
2940 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2942 int nbElemOnFace = 0;
2943 itElem = theElems.begin();
2944 // loop on not yet smoothed elements: look for elems on a face
2945 while ( itElem != theElems.end() ) {
2946 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2947 break; // all elements found
2949 const SMDS_MeshElement* elem = *itElem;
2950 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2951 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2955 elemsOnFace.push_back( elem );
2956 theElems.erase( itElem++ );
2960 isQuadratic = elem->IsQuadratic();
2962 // get movable nodes of elem
2963 const SMDS_MeshNode* node;
2964 SMDS_TypeOfPosition posType;
2965 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2966 int nn = 0, nbn = elem->NbNodes();
2967 if(elem->IsQuadratic())
2969 while ( nn++ < nbn ) {
2970 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2971 const SMDS_PositionPtr& pos = node->GetPosition();
2972 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2973 if (posType != SMDS_TOP_EDGE &&
2974 posType != SMDS_TOP_VERTEX &&
2975 theFixedNodes.find( node ) == theFixedNodes.end())
2977 // check if all faces around the node are on faceSubMesh
2978 // because a node on edge may be bound to face
2979 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2981 if ( faceSubMesh ) {
2982 while ( eIt->more() && all ) {
2983 const SMDS_MeshElement* e = eIt->next();
2984 all = faceSubMesh->Contains( e );
2988 setMovableNodes.insert( node );
2990 checkBoundaryNodes = true;
2992 if ( posType == SMDS_TOP_3DSPACE )
2993 checkBoundaryNodes = true;
2996 if ( surface.IsNull() )
2999 // get nodes to check UV
3000 list< const SMDS_MeshNode* > uvCheckNodes;
3001 itN = elem->nodesIterator();
3002 nn = 0; nbn = elem->NbNodes();
3003 if(elem->IsQuadratic())
3005 while ( nn++ < nbn ) {
3006 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3007 if ( uvMap.find( node ) == uvMap.end() )
3008 uvCheckNodes.push_back( node );
3009 // add nodes of elems sharing node
3010 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3011 // while ( eIt->more() ) {
3012 // const SMDS_MeshElement* e = eIt->next();
3013 // if ( e != elem ) {
3014 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3015 // while ( nIt->more() ) {
3016 // const SMDS_MeshNode* n =
3017 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3018 // if ( uvMap.find( n ) == uvMap.end() )
3019 // uvCheckNodes.push_back( n );
3025 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3026 for ( ; n != uvCheckNodes.end(); ++n ) {
3029 const SMDS_PositionPtr& pos = node->GetPosition();
3030 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3032 switch ( posType ) {
3033 case SMDS_TOP_FACE: {
3034 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3035 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3038 case SMDS_TOP_EDGE: {
3039 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3040 Handle(Geom2d_Curve) pcurve;
3041 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3042 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3043 if ( !pcurve.IsNull() ) {
3044 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3045 uv = pcurve->Value( u ).XY();
3049 case SMDS_TOP_VERTEX: {
3050 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3051 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3052 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3057 // check existing UV
3058 bool project = true;
3059 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3060 double dist1 = DBL_MAX, dist2 = 0;
3061 if ( posType != SMDS_TOP_3DSPACE ) {
3062 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3063 project = dist1 > fToler2;
3065 if ( project ) { // compute new UV
3067 if ( !getClosestUV( projector, pNode, newUV )) {
3068 MESSAGE("Node Projection Failed " << node);
3072 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3074 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3076 if ( posType != SMDS_TOP_3DSPACE )
3077 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3078 if ( dist2 < dist1 )
3082 // store UV in the map
3083 listUV.push_back( uv );
3084 uvMap.insert( make_pair( node, &listUV.back() ));
3086 } // loop on not yet smoothed elements
3088 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3089 checkBoundaryNodes = true;
3091 // fix nodes on mesh boundary
3093 if ( checkBoundaryNodes ) {
3094 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3095 map< NLink, int >::iterator link_nb;
3096 // put all elements links to linkNbMap
3097 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3098 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3099 const SMDS_MeshElement* elem = (*elemIt);
3100 int nbn = elem->NbNodes();
3101 if(elem->IsQuadratic())
3103 // loop on elem links: insert them in linkNbMap
3104 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3105 for ( int iN = 0; iN < nbn; ++iN ) {
3106 curNode = elem->GetNode( iN );
3108 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3109 else link = make_pair( prevNode , curNode );
3111 link_nb = linkNbMap.find( link );
3112 if ( link_nb == linkNbMap.end() )
3113 linkNbMap.insert( make_pair ( link, 1 ));
3118 // remove nodes that are in links encountered only once from setMovableNodes
3119 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3120 if ( link_nb->second == 1 ) {
3121 setMovableNodes.erase( link_nb->first.first );
3122 setMovableNodes.erase( link_nb->first.second );
3127 // -----------------------------------------------------
3128 // for nodes on seam edge, compute one more UV ( uvMap2 );
3129 // find movable nodes linked to nodes on seam and which
3130 // are to be smoothed using the second UV ( uvMap2 )
3131 // -----------------------------------------------------
3133 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3134 if ( !surface.IsNull() ) {
3135 TopExp_Explorer eExp( face, TopAbs_EDGE );
3136 for ( ; eExp.More(); eExp.Next() ) {
3137 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3138 if ( !BRep_Tool::IsClosed( edge, face ))
3140 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3141 if ( !sm ) continue;
3142 // find out which parameter varies for a node on seam
3145 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3146 if ( pcurve.IsNull() ) continue;
3147 uv1 = pcurve->Value( f );
3149 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3150 if ( pcurve.IsNull() ) continue;
3151 uv2 = pcurve->Value( f );
3152 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3154 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3155 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3157 // get nodes on seam and its vertices
3158 list< const SMDS_MeshNode* > seamNodes;
3159 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3160 while ( nSeamIt->more() ) {
3161 const SMDS_MeshNode* node = nSeamIt->next();
3162 if ( !isQuadratic || !IsMedium( node ))
3163 seamNodes.push_back( node );
3165 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3166 for ( ; vExp.More(); vExp.Next() ) {
3167 sm = aMesh->MeshElements( vExp.Current() );
3169 nSeamIt = sm->GetNodes();
3170 while ( nSeamIt->more() )
3171 seamNodes.push_back( nSeamIt->next() );
3174 // loop on nodes on seam
3175 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3176 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3177 const SMDS_MeshNode* nSeam = *noSeIt;
3178 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3179 if ( n_uv == uvMap.end() )
3182 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3183 // set the second UV
3184 listUV.push_back( *n_uv->second );
3185 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3186 if ( uvMap2.empty() )
3187 uvMap2 = uvMap; // copy the uvMap contents
3188 uvMap2[ nSeam ] = &listUV.back();
3190 // collect movable nodes linked to ones on seam in nodesNearSeam
3191 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3192 while ( eIt->more() ) {
3193 const SMDS_MeshElement* e = eIt->next();
3194 int nbUseMap1 = 0, nbUseMap2 = 0;
3195 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3196 int nn = 0, nbn = e->NbNodes();
3197 if(e->IsQuadratic()) nbn = nbn/2;
3198 while ( nn++ < nbn )
3200 const SMDS_MeshNode* n =
3201 static_cast<const SMDS_MeshNode*>( nIt->next() );
3203 setMovableNodes.find( n ) == setMovableNodes.end() )
3205 // add only nodes being closer to uv2 than to uv1
3206 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3207 0.5 * ( n->Y() + nSeam->Y() ),
3208 0.5 * ( n->Z() + nSeam->Z() ));
3210 getClosestUV( projector, pMid, uv );
3211 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3212 nodesNearSeam.insert( n );
3218 // for centroidalSmooth all element nodes must
3219 // be on one side of a seam
3220 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3221 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3223 while ( nn++ < nbn ) {
3224 const SMDS_MeshNode* n =
3225 static_cast<const SMDS_MeshNode*>( nIt->next() );
3226 setMovableNodes.erase( n );
3230 } // loop on nodes on seam
3231 } // loop on edge of a face
3232 } // if ( !face.IsNull() )
3234 if ( setMovableNodes.empty() ) {
3235 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3236 continue; // goto next face
3244 double maxRatio = -1., maxDisplacement = -1.;
3245 set<const SMDS_MeshNode*>::iterator nodeToMove;
3246 for ( it = 0; it < theNbIterations; it++ ) {
3247 maxDisplacement = 0.;
3248 nodeToMove = setMovableNodes.begin();
3249 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3250 const SMDS_MeshNode* node = (*nodeToMove);
3251 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3254 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3255 if ( theSmoothMethod == LAPLACIAN )
3256 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3258 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3260 // node displacement
3261 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3262 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3263 if ( aDispl > maxDisplacement )
3264 maxDisplacement = aDispl;
3266 // no node movement => exit
3267 //if ( maxDisplacement < 1.e-16 ) {
3268 if ( maxDisplacement < disttol ) {
3269 MESSAGE("-- no node movement --");
3273 // check elements quality
3275 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3276 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3277 const SMDS_MeshElement* elem = (*elemIt);
3278 if ( !elem || elem->GetType() != SMDSAbs_Face )
3280 SMESH::Controls::TSequenceOfXYZ aPoints;
3281 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3282 double aValue = aQualityFunc.GetValue( aPoints );
3283 if ( aValue > maxRatio )
3287 if ( maxRatio <= theTgtAspectRatio ) {
3288 MESSAGE("-- quality achived --");
3291 if (it+1 == theNbIterations) {
3292 MESSAGE("-- Iteration limit exceeded --");
3294 } // smoothing iterations
3296 MESSAGE(" Face id: " << *fId <<
3297 " Nb iterstions: " << it <<
3298 " Displacement: " << maxDisplacement <<
3299 " Aspect Ratio " << maxRatio);
3301 // ---------------------------------------
3302 // new nodes positions are computed,
3303 // record movement in DS and set new UV
3304 // ---------------------------------------
3305 nodeToMove = setMovableNodes.begin();
3306 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3307 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3308 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3309 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3310 if ( node_uv != uvMap.end() ) {
3311 gp_XY* uv = node_uv->second;
3313 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3317 // move medium nodes of quadratic elements
3320 SMESH_MesherHelper helper( *GetMesh() );
3321 if ( !face.IsNull() )
3322 helper.SetSubShape( face );
3323 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3324 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3325 const SMDS_VtkFace* QF =
3326 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3327 if(QF && QF->IsQuadratic()) {
3328 vector<const SMDS_MeshNode*> Ns;
3329 Ns.reserve(QF->NbNodes()+1);
3330 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3331 while ( anIter->more() )
3332 Ns.push_back( cast2Node(anIter->next()) );
3333 Ns.push_back( Ns[0] );
3335 for(int i=0; i<QF->NbNodes(); i=i+2) {
3336 if ( !surface.IsNull() ) {
3337 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3338 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3339 gp_XY uv = ( uv1 + uv2 ) / 2.;
3340 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3341 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3344 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3345 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3346 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3348 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3349 fabs( Ns[i+1]->Y() - y ) > disttol ||
3350 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3351 // we have to move i+1 node
3352 aMesh->MoveNode( Ns[i+1], x, y, z );
3359 } // loop on face ids
3363 //=======================================================================
3364 //function : isReverse
3365 //purpose : Return true if normal of prevNodes is not co-directied with
3366 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3367 // iNotSame is where prevNodes and nextNodes are different
3368 //=======================================================================
3370 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3371 vector<const SMDS_MeshNode*> nextNodes,
3375 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3376 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3378 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3379 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3380 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3381 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3383 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3384 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3385 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3386 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3388 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3390 return (vA ^ vB) * vN < 0.0;
3393 //=======================================================================
3395 * \brief Create elements by sweeping an element
3396 * \param elem - element to sweep
3397 * \param newNodesItVec - nodes generated from each node of the element
3398 * \param newElems - generated elements
3399 * \param nbSteps - number of sweeping steps
3400 * \param srcElements - to append elem for each generated element
3402 //=======================================================================
3404 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3405 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3406 list<const SMDS_MeshElement*>& newElems,
3408 SMESH_SequenceOfElemPtr& srcElements)
3410 //MESSAGE("sweepElement " << nbSteps);
3411 SMESHDS_Mesh* aMesh = GetMeshDS();
3413 // Loop on elem nodes:
3414 // find new nodes and detect same nodes indices
3415 int nbNodes = elem->NbNodes();
3416 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3417 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3418 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3419 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3421 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3422 vector<int> sames(nbNodes);
3423 vector<bool> issimple(nbNodes);
3425 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3426 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3427 const SMDS_MeshNode* node = nnIt->first;
3428 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3429 if ( listNewNodes.empty() ) {
3433 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3435 itNN[ iNode ] = listNewNodes.begin();
3436 prevNod[ iNode ] = node;
3437 nextNod[ iNode ] = listNewNodes.front();
3438 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3439 if ( prevNod[ iNode ] != nextNod [ iNode ])
3440 iNotSameNode = iNode;
3444 sames[nbSame++] = iNode;
3449 //cerr<<" nbSame = "<<nbSame<<endl;
3450 if ( nbSame == nbNodes || nbSame > 2) {
3451 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3452 //INFOS( " Too many same nodes of element " << elem->GetID() );
3456 // if( elem->IsQuadratic() && nbSame>0 ) {
3457 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3461 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3462 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3464 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3465 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3466 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3470 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3471 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3472 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3473 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3475 // check element orientation
3477 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3478 //MESSAGE("Reversed elem " << elem );
3482 std::swap( iBeforeSame, iAfterSame );
3485 // make new elements
3486 const SMDS_MeshElement* lastElem = elem;
3487 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3489 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3490 if(issimple[iNode]) {
3491 nextNod[ iNode ] = *itNN[ iNode ];
3495 if( elem->GetType()==SMDSAbs_Node ) {
3496 // we have to use two nodes
3497 midlNod[ iNode ] = *itNN[ iNode ];
3499 nextNod[ iNode ] = *itNN[ iNode ];
3502 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3503 // we have to use each second node
3505 nextNod[ iNode ] = *itNN[ iNode ];
3509 // we have to use two nodes
3510 midlNod[ iNode ] = *itNN[ iNode ];
3512 nextNod[ iNode ] = *itNN[ iNode ];
3517 SMDS_MeshElement* aNewElem = 0;
3518 if(!elem->IsPoly()) {
3519 switch ( nbNodes ) {
3523 if ( nbSame == 0 ) {
3525 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3527 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3533 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534 nextNod[ 1 ], nextNod[ 0 ] );
3536 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3537 nextNod[ iNotSameNode ] );
3541 case 3: { // TRIANGLE or quadratic edge
3542 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3544 if ( nbSame == 0 ) // --- pentahedron
3545 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3546 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3548 else if ( nbSame == 1 ) // --- pyramid
3549 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3550 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3551 nextNod[ iSameNode ]);
3553 else // 2 same nodes: --- tetrahedron
3554 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3555 nextNod[ iNotSameNode ]);
3557 else { // quadratic edge
3558 if(nbSame==0) { // quadratic quadrangle
3559 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3560 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3562 else if(nbSame==1) { // quadratic triangle
3564 return; // medium node on axis
3566 else if(sames[0]==0) {
3567 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3568 nextNod[2], midlNod[1], prevNod[2]);
3570 else { // sames[0]==1
3571 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3572 midlNod[0], nextNod[2], prevNod[2]);
3581 case 4: { // QUADRANGLE
3583 if ( nbSame == 0 ) // --- hexahedron
3584 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3585 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3587 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3588 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3589 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3590 nextNod[ iSameNode ]);
3591 newElems.push_back( aNewElem );
3592 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3593 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3594 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3596 else if ( nbSame == 2 ) { // pentahedron
3597 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3598 // iBeforeSame is same too
3599 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3600 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3601 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3603 // iAfterSame is same too
3604 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3605 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3606 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3610 case 6: { // quadratic triangle
3611 // create pentahedron with 15 nodes
3613 if(i0>0) { // reversed case
3614 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3615 nextNod[0], nextNod[2], nextNod[1],
3616 prevNod[5], prevNod[4], prevNod[3],
3617 nextNod[5], nextNod[4], nextNod[3],
3618 midlNod[0], midlNod[2], midlNod[1]);
3620 else { // not reversed case
3621 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3622 nextNod[0], nextNod[1], nextNod[2],
3623 prevNod[3], prevNod[4], prevNod[5],
3624 nextNod[3], nextNod[4], nextNod[5],
3625 midlNod[0], midlNod[1], midlNod[2]);
3628 else if(nbSame==1) {
3629 // 2d order pyramid of 13 nodes
3630 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3631 // int n12,int n23,int n34,int n41,
3632 // int n15,int n25,int n35,int n45, int ID);
3634 int n1,n4,n41,n15,n45;
3635 if(i0>0) { // reversed case
3636 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3637 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3643 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3644 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3649 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3650 nextNod[n4], prevNod[n4], prevNod[n5],
3651 midlNod[n1], nextNod[n41],
3652 midlNod[n4], prevNod[n41],
3653 prevNod[n15], nextNod[n15],
3654 nextNod[n45], prevNod[n45]);
3656 else if(nbSame==2) {
3657 // 2d order tetrahedron of 10 nodes
3658 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3659 // int n12,int n23,int n31,
3660 // int n14,int n24,int n34, int ID);
3661 int n1 = iNotSameNode;
3662 int n2,n3,n12,n23,n31;
3663 if(i0>0) { // reversed case
3664 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3665 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3671 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3672 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3677 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3678 prevNod[n12], prevNod[n23], prevNod[n31],
3679 midlNod[n1], nextNod[n12], nextNod[n31]);
3683 case 8: { // quadratic quadrangle
3685 // create hexahedron with 20 nodes
3686 if(i0>0) { // reversed case
3687 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3688 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3689 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3690 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3691 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3693 else { // not reversed case
3694 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3695 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3696 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3697 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3698 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3701 else if(nbSame==1) {
3702 // --- pyramid + pentahedron - can not be created since it is needed
3703 // additional middle node ot the center of face
3704 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3707 else if(nbSame==2) {
3708 // 2d order Pentahedron with 15 nodes
3709 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3710 // int n12,int n23,int n31,int n45,int n56,int n64,
3711 // int n14,int n25,int n36, int ID);
3713 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3714 // iBeforeSame is same too
3721 // iAfterSame is same too
3727 int n12,n45,n14,n25;
3728 if(i0>0) { //reversed case
3740 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3741 prevNod[n4], prevNod[n5], nextNod[n5],
3742 prevNod[n12], midlNod[n2], nextNod[n12],
3743 prevNod[n45], midlNod[n5], nextNod[n45],
3744 prevNod[n14], prevNod[n25], nextNod[n25]);
3749 // realized for extrusion only
3750 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3751 //vector<int> quantities (nbNodes + 2);
3753 //quantities[0] = nbNodes; // bottom of prism
3754 //for (int inode = 0; inode < nbNodes; inode++) {
3755 // polyedre_nodes[inode] = prevNod[inode];
3758 //quantities[1] = nbNodes; // top of prism
3759 //for (int inode = 0; inode < nbNodes; inode++) {
3760 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3763 //for (int iface = 0; iface < nbNodes; iface++) {
3764 // quantities[iface + 2] = 4;
3765 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3766 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3767 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3768 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3769 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3771 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3778 // realized for extrusion only
3779 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3780 vector<int> quantities (nbNodes + 2);
3782 quantities[0] = nbNodes; // bottom of prism
3783 for (int inode = 0; inode < nbNodes; inode++) {
3784 polyedre_nodes[inode] = prevNod[inode];
3787 quantities[1] = nbNodes; // top of prism
3788 for (int inode = 0; inode < nbNodes; inode++) {
3789 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3792 for (int iface = 0; iface < nbNodes; iface++) {
3793 quantities[iface + 2] = 4;
3794 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3795 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3796 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3797 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3798 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3800 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3804 newElems.push_back( aNewElem );
3805 myLastCreatedElems.Append(aNewElem);
3806 srcElements.Append( elem );
3807 lastElem = aNewElem;
3810 // set new prev nodes
3811 for ( iNode = 0; iNode < nbNodes; iNode++ )
3812 prevNod[ iNode ] = nextNod[ iNode ];
3817 //=======================================================================
3819 * \brief Create 1D and 2D elements around swept elements
3820 * \param mapNewNodes - source nodes and ones generated from them
3821 * \param newElemsMap - source elements and ones generated from them
3822 * \param elemNewNodesMap - nodes generated from each node of each element
3823 * \param elemSet - all swept elements
3824 * \param nbSteps - number of sweeping steps
3825 * \param srcElements - to append elem for each generated element
3827 //=======================================================================
3829 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3830 TElemOfElemListMap & newElemsMap,
3831 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3832 TIDSortedElemSet& elemSet,
3834 SMESH_SequenceOfElemPtr& srcElements)
3836 MESSAGE("makeWalls");
3837 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3838 SMESHDS_Mesh* aMesh = GetMeshDS();
3840 // Find nodes belonging to only one initial element - sweep them to get edges.
3842 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3843 for ( ; nList != mapNewNodes.end(); nList++ ) {
3844 const SMDS_MeshNode* node =
3845 static_cast<const SMDS_MeshNode*>( nList->first );
3846 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3847 int nbInitElems = 0;
3848 const SMDS_MeshElement* el = 0;
3849 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3850 while ( eIt->more() && nbInitElems < 2 ) {
3852 SMDSAbs_ElementType type = el->GetType();
3853 if ( type == SMDSAbs_Volume || type < highType ) continue;
3854 if ( type > highType ) {
3858 if ( elemSet.find(el) != elemSet.end() )
3861 if ( nbInitElems < 2 ) {
3862 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3863 if(!NotCreateEdge) {
3864 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3865 list<const SMDS_MeshElement*> newEdges;
3866 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3871 // Make a ceiling for each element ie an equal element of last new nodes.
3872 // Find free links of faces - make edges and sweep them into faces.
3874 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3875 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3876 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3877 const SMDS_MeshElement* elem = itElem->first;
3878 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3880 if(itElem->second.size()==0) continue;
3882 if ( elem->GetType() == SMDSAbs_Edge ) {
3883 // create a ceiling edge
3884 if (!elem->IsQuadratic()) {
3885 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3886 vecNewNodes[ 1 ]->second.back())) {
3887 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3888 vecNewNodes[ 1 ]->second.back()));
3889 srcElements.Append( myLastCreatedElems.Last() );
3893 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3894 vecNewNodes[ 1 ]->second.back(),
3895 vecNewNodes[ 2 ]->second.back())) {
3896 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3897 vecNewNodes[ 1 ]->second.back(),
3898 vecNewNodes[ 2 ]->second.back()));
3899 srcElements.Append( myLastCreatedElems.Last() );
3903 if ( elem->GetType() != SMDSAbs_Face )
3906 bool hasFreeLinks = false;
3908 TIDSortedElemSet avoidSet;
3909 avoidSet.insert( elem );
3911 set<const SMDS_MeshNode*> aFaceLastNodes;
3912 int iNode, nbNodes = vecNewNodes.size();
3913 if(!elem->IsQuadratic()) {
3914 // loop on the face nodes
3915 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3916 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3917 // look for free links of the face
3918 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3919 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3920 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3921 // check if a link is free
3922 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3923 hasFreeLinks = true;
3924 // make an edge and a ceiling for a new edge
3925 if ( !aMesh->FindEdge( n1, n2 )) {
3926 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3927 srcElements.Append( myLastCreatedElems.Last() );
3929 n1 = vecNewNodes[ iNode ]->second.back();
3930 n2 = vecNewNodes[ iNext ]->second.back();
3931 if ( !aMesh->FindEdge( n1, n2 )) {
3932 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3933 srcElements.Append( myLastCreatedElems.Last() );
3938 else { // elem is quadratic face
3939 int nbn = nbNodes/2;
3940 for ( iNode = 0; iNode < nbn; iNode++ ) {
3941 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3942 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3943 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3944 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3945 // check if a link is free
3946 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3947 hasFreeLinks = true;
3948 // make an edge and a ceiling for a new edge
3950 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3951 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3952 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3953 srcElements.Append( myLastCreatedElems.Last() );
3955 n1 = vecNewNodes[ iNode ]->second.back();
3956 n2 = vecNewNodes[ iNext ]->second.back();
3957 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3958 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3959 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3960 srcElements.Append( myLastCreatedElems.Last() );
3964 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3965 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3969 // sweep free links into faces
3971 if ( hasFreeLinks ) {
3972 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3973 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3975 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3976 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3977 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3978 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3980 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3981 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3983 while ( iVol++ < volNb ) v++;
3984 // find indices of free faces of a volume and their source edges
3985 list< int > freeInd;
3986 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3987 SMDS_VolumeTool vTool( *v );
3988 int iF, nbF = vTool.NbFaces();
3989 for ( iF = 0; iF < nbF; iF ++ ) {
3990 if (vTool.IsFreeFace( iF ) &&
3991 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3992 initNodeSet != faceNodeSet) // except an initial face
3994 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3996 freeInd.push_back( iF );
3997 // find source edge of a free face iF
3998 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3999 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4000 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4001 initNodeSet.begin(), initNodeSet.end(),
4002 commonNodes.begin());
4003 if ( (*v)->IsQuadratic() )
4004 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4006 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4008 if ( !srcEdges.back() )
4010 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4011 << iF << " of volume #" << vTool.ID() << endl;
4016 if ( freeInd.empty() )
4019 // create faces for all steps;
4020 // if such a face has been already created by sweep of edge,
4021 // assure that its orientation is OK
4022 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4024 vTool.SetExternalNormal();
4025 const int nextShift = vTool.IsForward() ? +1 : -1;
4026 list< int >::iterator ind = freeInd.begin();
4027 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4028 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4030 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4031 int nbn = vTool.NbFaceNodes( *ind );
4032 if ( ! (*v)->IsPoly() )
4034 case 3: { ///// triangle
4035 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4037 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4039 const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
4041 nodes[ 1 + nextShift ] };
4043 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4045 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4050 case 4: { ///// quadrangle
4051 const SMDS_MeshFace * f =
4052 aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4054 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
4056 const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
4057 nodes[ 2 ], nodes[ 2+nextShift ] };
4059 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4061 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
4062 newOrder[ 2 ], newOrder[ 3 ]));
4066 case 6: { /////// quadratic triangle
4067 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4068 nodes[1], nodes[3], nodes[5] );
4070 nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
4072 const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
4074 nodes[2 + 2*nextShift],
4075 nodes[3 - 2*nextShift],
4077 nodes[3 + 2*nextShift]};
4079 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4081 myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
4090 default: /////// quadratic quadrangle
4091 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4092 nodes[1], nodes[3], nodes[5], nodes[7] );
4094 nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
4096 const SMDS_MeshNode* newOrder[8] = { nodes[0],
4097 nodes[4 - 2*nextShift],
4099 nodes[4 + 2*nextShift],
4101 nodes[5 - 2*nextShift],
4103 nodes[5 + 2*nextShift] };
4105 aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
4107 myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
4108 newOrder[ 2 ], newOrder[ 3 ],
4109 newOrder[ 4 ], newOrder[ 5 ],
4110 newOrder[ 6 ], newOrder[ 7 ]));
4114 else { //////// polygon
4116 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4117 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4119 nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
4121 if ( !vTool.IsForward() )
4122 std::reverse( polygon_nodes.begin(), polygon_nodes.end());
4124 aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
4126 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4130 while ( srcElements.Length() < myLastCreatedElems.Length() )
4131 srcElements.Append( *srcEdge );
4133 } // loop on free faces
4135 // go to the next volume
4137 while ( iVol++ < nbVolumesByStep ) v++;
4140 } // loop on volumes of one step
4141 } // sweep free links into faces
4143 // Make a ceiling face with a normal external to a volume
4145 SMDS_VolumeTool lastVol( itElem->second.back() );
4147 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4149 lastVol.SetExternalNormal();
4150 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4151 int nbn = lastVol.NbFaceNodes( iF );
4154 if (!hasFreeLinks ||
4155 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4156 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4159 if (!hasFreeLinks ||
4160 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4161 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4164 if(itElem->second.back()->IsQuadratic()) {
4166 if (!hasFreeLinks ||
4167 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4168 nodes[1], nodes[3], nodes[5]) ) {
4169 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4170 nodes[1], nodes[3], nodes[5]));
4174 if (!hasFreeLinks ||
4175 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4176 nodes[1], nodes[3], nodes[5], nodes[7]) )
4177 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4178 nodes[1], nodes[3], nodes[5], nodes[7]));
4182 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4183 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4184 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4188 while ( srcElements.Length() < myLastCreatedElems.Length() )
4189 srcElements.Append( myLastCreatedElems.Last() );
4191 } // loop on swept elements
4194 //=======================================================================
4195 //function : RotationSweep
4197 //=======================================================================
4199 SMESH_MeshEditor::PGroupIDs
4200 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4201 const gp_Ax1& theAxis,
4202 const double theAngle,
4203 const int theNbSteps,
4204 const double theTol,
4205 const bool theMakeGroups,
4206 const bool theMakeWalls)
4208 myLastCreatedElems.Clear();
4209 myLastCreatedNodes.Clear();
4211 // source elements for each generated one
4212 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4214 MESSAGE( "RotationSweep()");
4216 aTrsf.SetRotation( theAxis, theAngle );
4218 aTrsf2.SetRotation( theAxis, theAngle/2. );
4220 gp_Lin aLine( theAxis );
4221 double aSqTol = theTol * theTol;
4223 SMESHDS_Mesh* aMesh = GetMeshDS();
4225 TNodeOfNodeListMap mapNewNodes;
4226 TElemOfVecOfNnlmiMap mapElemNewNodes;
4227 TElemOfElemListMap newElemsMap;
4230 TIDSortedElemSet::iterator itElem;
4231 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4232 const SMDS_MeshElement* elem = *itElem;
4233 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4235 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4236 newNodesItVec.reserve( elem->NbNodes() );
4238 // loop on elem nodes
4239 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4240 while ( itN->more() ) {
4241 // check if a node has been already sweeped
4242 const SMDS_MeshNode* node = cast2Node( itN->next() );
4244 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4246 aXYZ.Coord( coord[0], coord[1], coord[2] );
4247 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4249 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4250 if ( nIt == mapNewNodes.end() ) {
4251 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4252 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4255 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4257 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4258 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4259 const SMDS_MeshNode * newNode = node;
4260 for ( int i = 0; i < theNbSteps; i++ ) {
4262 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4264 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4265 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4266 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4267 myLastCreatedNodes.Append(newNode);
4268 srcNodes.Append( node );
4269 listNewNodes.push_back( newNode );
4270 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4271 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4274 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4276 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4277 myLastCreatedNodes.Append(newNode);
4278 srcNodes.Append( node );
4279 listNewNodes.push_back( newNode );
4282 listNewNodes.push_back( newNode );
4283 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4284 listNewNodes.push_back( newNode );
4291 // if current elem is quadratic and current node is not medium
4292 // we have to check - may be it is needed to insert additional nodes
4293 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4294 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4295 if(listNewNodes.size()==theNbSteps) {
4296 listNewNodes.clear();
4298 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4300 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4301 const SMDS_MeshNode * newNode = node;
4303 for(int i = 0; i<theNbSteps; i++) {
4304 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4305 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4306 cout<<" 3 AddNode: "<<newNode;
4307 myLastCreatedNodes.Append(newNode);
4308 listNewNodes.push_back( newNode );
4309 srcNodes.Append( node );
4310 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4311 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4312 cout<<" 4 AddNode: "<<newNode;
4313 myLastCreatedNodes.Append(newNode);
4314 srcNodes.Append( node );
4315 listNewNodes.push_back( newNode );
4319 listNewNodes.push_back( newNode );
4325 newNodesItVec.push_back( nIt );
4327 // make new elements
4328 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4332 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4334 PGroupIDs newGroupIDs;
4335 if ( theMakeGroups )
4336 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4342 //=======================================================================
4343 //function : CreateNode
4345 //=======================================================================
4346 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4349 const double tolnode,
4350 SMESH_SequenceOfNode& aNodes)
4352 myLastCreatedElems.Clear();
4353 myLastCreatedNodes.Clear();
4356 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4358 // try to search in sequence of existing nodes
4359 // if aNodes.Length()>0 we 'nave to use given sequence
4360 // else - use all nodes of mesh
4361 if(aNodes.Length()>0) {
4363 for(i=1; i<=aNodes.Length(); i++) {
4364 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4365 if(P1.Distance(P2)<tolnode)
4366 return aNodes.Value(i);
4370 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4371 while(itn->more()) {
4372 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4373 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4374 if(P1.Distance(P2)<tolnode)
4379 // create new node and return it
4380 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4381 myLastCreatedNodes.Append(NewNode);
4386 //=======================================================================
4387 //function : ExtrusionSweep
4389 //=======================================================================
4391 SMESH_MeshEditor::PGroupIDs
4392 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4393 const gp_Vec& theStep,
4394 const int theNbSteps,
4395 TElemOfElemListMap& newElemsMap,
4396 const bool theMakeGroups,
4398 const double theTolerance)
4400 ExtrusParam aParams;
4401 aParams.myDir = gp_Dir(theStep);
4402 aParams.myNodes.Clear();
4403 aParams.mySteps = new TColStd_HSequenceOfReal;
4405 for(i=1; i<=theNbSteps; i++)
4406 aParams.mySteps->Append(theStep.Magnitude());
4409 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4413 //=======================================================================
4414 //function : ExtrusionSweep
4416 //=======================================================================
4418 SMESH_MeshEditor::PGroupIDs
4419 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4420 ExtrusParam& theParams,
4421 TElemOfElemListMap& newElemsMap,
4422 const bool theMakeGroups,
4424 const double theTolerance)
4426 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4427 myLastCreatedElems.Clear();
4428 myLastCreatedNodes.Clear();
4430 // source elements for each generated one
4431 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4433 SMESHDS_Mesh* aMesh = GetMeshDS();
4435 int nbsteps = theParams.mySteps->Length();
4437 TNodeOfNodeListMap mapNewNodes;
4438 //TNodeOfNodeVecMap mapNewNodes;
4439 TElemOfVecOfNnlmiMap mapElemNewNodes;
4440 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4443 TIDSortedElemSet::iterator itElem;
4444 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4445 // check element type
4446 const SMDS_MeshElement* elem = *itElem;
4447 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4450 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4451 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4452 newNodesItVec.reserve( elem->NbNodes() );
4454 // loop on elem nodes
4455 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4456 while ( itN->more() )
4458 // check if a node has been already sweeped
4459 const SMDS_MeshNode* node = cast2Node( itN->next() );
4460 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4461 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4462 if ( nIt == mapNewNodes.end() ) {
4463 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4464 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4465 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4466 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4467 //vecNewNodes.reserve(nbsteps);
4470 double coord[] = { node->X(), node->Y(), node->Z() };
4471 //int nbsteps = theParams.mySteps->Length();
4472 for ( int i = 0; i < nbsteps; i++ ) {
4473 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4474 // create additional node
4475 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4476 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4477 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4478 if( theFlags & EXTRUSION_FLAG_SEW ) {
4479 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4480 theTolerance, theParams.myNodes);
4481 listNewNodes.push_back( newNode );
4484 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4485 myLastCreatedNodes.Append(newNode);
4486 srcNodes.Append( node );
4487 listNewNodes.push_back( newNode );
4490 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4491 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4492 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4493 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4494 if( theFlags & EXTRUSION_FLAG_SEW ) {
4495 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4496 theTolerance, theParams.myNodes);
4497 listNewNodes.push_back( newNode );
4498 //vecNewNodes[i]=newNode;
4501 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4502 myLastCreatedNodes.Append(newNode);
4503 srcNodes.Append( node );
4504 listNewNodes.push_back( newNode );
4505 //vecNewNodes[i]=newNode;
4510 // if current elem is quadratic and current node is not medium
4511 // we have to check - may be it is needed to insert additional nodes
4512 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4513 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4514 if(listNewNodes.size()==nbsteps) {
4515 listNewNodes.clear();
4516 double coord[] = { node->X(), node->Y(), node->Z() };
4517 for ( int i = 0; i < nbsteps; i++ ) {
4518 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4519 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4520 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4521 if( theFlags & EXTRUSION_FLAG_SEW ) {
4522 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4523 theTolerance, theParams.myNodes);
4524 listNewNodes.push_back( newNode );
4527 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4528 myLastCreatedNodes.Append(newNode);
4529 srcNodes.Append( node );
4530 listNewNodes.push_back( newNode );
4532 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4533 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4534 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4535 if( theFlags & EXTRUSION_FLAG_SEW ) {
4536 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4537 theTolerance, theParams.myNodes);
4538 listNewNodes.push_back( newNode );
4541 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4542 myLastCreatedNodes.Append(newNode);
4543 srcNodes.Append( node );
4544 listNewNodes.push_back( newNode );
4550 newNodesItVec.push_back( nIt );
4552 // make new elements
4553 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4556 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4557 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4559 PGroupIDs newGroupIDs;
4560 if ( theMakeGroups )
4561 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4567 //=======================================================================
4568 //class : SMESH_MeshEditor_PathPoint
4569 //purpose : auxiliary class
4570 //=======================================================================
4571 class SMESH_MeshEditor_PathPoint {
4573 SMESH_MeshEditor_PathPoint() {
4574 myPnt.SetCoord(99., 99., 99.);
4575 myTgt.SetCoord(1.,0.,0.);
4579 void SetPnt(const gp_Pnt& aP3D){
4582 void SetTangent(const gp_Dir& aTgt){
4585 void SetAngle(const double& aBeta){
4588 void SetParameter(const double& aPrm){
4591 const gp_Pnt& Pnt()const{
4594 const gp_Dir& Tangent()const{
4597 double Angle()const{
4600 double Parameter()const{
4612 //=======================================================================
4613 //function : ExtrusionAlongTrack
4615 //=======================================================================
4616 SMESH_MeshEditor::Extrusion_Error
4617 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4618 SMESH_subMesh* theTrack,
4619 const SMDS_MeshNode* theN1,
4620 const bool theHasAngles,
4621 list<double>& theAngles,
4622 const bool theLinearVariation,
4623 const bool theHasRefPoint,
4624 const gp_Pnt& theRefPoint,
4625 const bool theMakeGroups)
4627 MESSAGE("ExtrusionAlongTrack");
4628 myLastCreatedElems.Clear();
4629 myLastCreatedNodes.Clear();
4632 std::list<double> aPrms;
4633 TIDSortedElemSet::iterator itElem;
4636 TopoDS_Edge aTrackEdge;
4637 TopoDS_Vertex aV1, aV2;
4639 SMDS_ElemIteratorPtr aItE;
4640 SMDS_NodeIteratorPtr aItN;
4641 SMDSAbs_ElementType aTypeE;
4643 TNodeOfNodeListMap mapNewNodes;
4646 aNbE = theElements.size();
4649 return EXTR_NO_ELEMENTS;
4651 // 1.1 Track Pattern
4654 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4656 aItE = pSubMeshDS->GetElements();
4657 while ( aItE->more() ) {
4658 const SMDS_MeshElement* pE = aItE->next();
4659 aTypeE = pE->GetType();
4660 // Pattern must contain links only
4661 if ( aTypeE != SMDSAbs_Edge )
4662 return EXTR_PATH_NOT_EDGE;
4665 list<SMESH_MeshEditor_PathPoint> fullList;
4667 const TopoDS_Shape& aS = theTrack->GetSubShape();
4668 // Sub shape for the Pattern must be an Edge or Wire
4669 if( aS.ShapeType() == TopAbs_EDGE ) {
4670 aTrackEdge = TopoDS::Edge( aS );
4671 // the Edge must not be degenerated
4672 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4673 return EXTR_BAD_PATH_SHAPE;
4674 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4675 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4676 const SMDS_MeshNode* aN1 = aItN->next();
4677 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4678 const SMDS_MeshNode* aN2 = aItN->next();
4679 // starting node must be aN1 or aN2
4680 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4681 return EXTR_BAD_STARTING_NODE;
4682 aItN = pSubMeshDS->GetNodes();
4683 while ( aItN->more() ) {
4684 const SMDS_MeshNode* pNode = aItN->next();
4685 const SMDS_EdgePosition* pEPos =
4686 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4687 double aT = pEPos->GetUParameter();
4688 aPrms.push_back( aT );
4690 //Extrusion_Error err =
4691 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4693 else if( aS.ShapeType() == TopAbs_WIRE ) {
4694 list< SMESH_subMesh* > LSM;
4695 TopTools_SequenceOfShape Edges;
4696 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4697 while(itSM->more()) {
4698 SMESH_subMesh* SM = itSM->next();
4700 const TopoDS_Shape& aS = SM->GetSubShape();
4703 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4704 int startNid = theN1->GetID();
4705 TColStd_MapOfInteger UsedNums;
4706 int NbEdges = Edges.Length();
4708 for(; i<=NbEdges; i++) {
4710 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4711 for(; itLSM!=LSM.end(); itLSM++) {
4713 if(UsedNums.Contains(k)) continue;
4714 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4715 SMESH_subMesh* locTrack = *itLSM;
4716 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4717 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4718 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4719 const SMDS_MeshNode* aN1 = aItN->next();
4720 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4721 const SMDS_MeshNode* aN2 = aItN->next();
4722 // starting node must be aN1 or aN2
4723 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4724 // 2. Collect parameters on the track edge
4726 aItN = locMeshDS->GetNodes();
4727 while ( aItN->more() ) {
4728 const SMDS_MeshNode* pNode = aItN->next();
4729 const SMDS_EdgePosition* pEPos =
4730 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4731 double aT = pEPos->GetUParameter();
4732 aPrms.push_back( aT );
4734 list<SMESH_MeshEditor_PathPoint> LPP;
4735 //Extrusion_Error err =
4736 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4737 LLPPs.push_back(LPP);
4739 // update startN for search following egde
4740 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4741 else startNid = aN1->GetID();
4745 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4746 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4747 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4748 for(; itPP!=firstList.end(); itPP++) {
4749 fullList.push_back( *itPP );
4751 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4752 fullList.pop_back();
4754 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4755 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4756 itPP = currList.begin();
4757 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4758 gp_Dir D1 = PP1.Tangent();
4759 gp_Dir D2 = PP2.Tangent();
4760 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4761 (D1.Z()+D2.Z())/2 ) );
4762 PP1.SetTangent(Dnew);
4763 fullList.push_back(PP1);
4765 for(; itPP!=firstList.end(); itPP++) {
4766 fullList.push_back( *itPP );
4768 PP1 = fullList.back();
4769 fullList.pop_back();
4771 // if wire not closed
4772 fullList.push_back(PP1);
4776 return EXTR_BAD_PATH_SHAPE;
4779 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4780 theHasRefPoint, theRefPoint, theMakeGroups);
4784 //=======================================================================
4785 //function : ExtrusionAlongTrack
4787 //=======================================================================
4788 SMESH_MeshEditor::Extrusion_Error
4789 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4790 SMESH_Mesh* theTrack,
4791 const SMDS_MeshNode* theN1,
4792 const bool theHasAngles,
4793 list<double>& theAngles,
4794 const bool theLinearVariation,
4795 const bool theHasRefPoint,
4796 const gp_Pnt& theRefPoint,
4797 const bool theMakeGroups)
4799 myLastCreatedElems.Clear();
4800 myLastCreatedNodes.Clear();
4803 std::list<double> aPrms;
4804 TIDSortedElemSet::iterator itElem;
4807 TopoDS_Edge aTrackEdge;
4808 TopoDS_Vertex aV1, aV2;
4810 SMDS_ElemIteratorPtr aItE;
4811 SMDS_NodeIteratorPtr aItN;
4812 SMDSAbs_ElementType aTypeE;
4814 TNodeOfNodeListMap mapNewNodes;
4817 aNbE = theElements.size();
4820 return EXTR_NO_ELEMENTS;
4822 // 1.1 Track Pattern
4825 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4827 aItE = pMeshDS->elementsIterator();
4828 while ( aItE->more() ) {
4829 const SMDS_MeshElement* pE = aItE->next();
4830 aTypeE = pE->GetType();
4831 // Pattern must contain links only
4832 if ( aTypeE != SMDSAbs_Edge )
4833 return EXTR_PATH_NOT_EDGE;
4836 list<SMESH_MeshEditor_PathPoint> fullList;
4838 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4839 // Sub shape for the Pattern must be an Edge or Wire
4840 if( aS.ShapeType() == TopAbs_EDGE ) {
4841 aTrackEdge = TopoDS::Edge( aS );
4842 // the Edge must not be degenerated
4843 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4844 return EXTR_BAD_PATH_SHAPE;
4845 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4846 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4847 const SMDS_MeshNode* aN1 = aItN->next();
4848 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4849 const SMDS_MeshNode* aN2 = aItN->next();
4850 // starting node must be aN1 or aN2
4851 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4852 return EXTR_BAD_STARTING_NODE;
4853 aItN = pMeshDS->nodesIterator();
4854 while ( aItN->more() ) {
4855 const SMDS_MeshNode* pNode = aItN->next();
4856 if( pNode==aN1 || pNode==aN2 ) continue;
4857 const SMDS_EdgePosition* pEPos =
4858 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4859 double aT = pEPos->GetUParameter();
4860 aPrms.push_back( aT );
4862 //Extrusion_Error err =
4863 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4865 else if( aS.ShapeType() == TopAbs_WIRE ) {
4866 list< SMESH_subMesh* > LSM;
4867 TopTools_SequenceOfShape Edges;
4868 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4869 for(; eExp.More(); eExp.Next()) {
4870 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4871 if( BRep_Tool::Degenerated(E) ) continue;
4872 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4878 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4879 int startNid = theN1->GetID();
4880 TColStd_MapOfInteger UsedNums;
4881 int NbEdges = Edges.Length();
4883 for(; i<=NbEdges; i++) {
4885 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4886 for(; itLSM!=LSM.end(); itLSM++) {
4888 if(UsedNums.Contains(k)) continue;
4889 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4890 SMESH_subMesh* locTrack = *itLSM;
4891 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4892 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4893 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4894 const SMDS_MeshNode* aN1 = aItN->next();
4895 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4896 const SMDS_MeshNode* aN2 = aItN->next();
4897 // starting node must be aN1 or aN2
4898 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4899 // 2. Collect parameters on the track edge
4901 aItN = locMeshDS->GetNodes();
4902 while ( aItN->more() ) {
4903 const SMDS_MeshNode* pNode = aItN->next();
4904 const SMDS_EdgePosition* pEPos =
4905 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4906 double aT = pEPos->GetUParameter();
4907 aPrms.push_back( aT );
4909 list<SMESH_MeshEditor_PathPoint> LPP;
4910 //Extrusion_Error err =
4911 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4912 LLPPs.push_back(LPP);
4914 // update startN for search following egde
4915 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4916 else startNid = aN1->GetID();
4920 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4921 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4922 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4923 for(; itPP!=firstList.end(); itPP++) {
4924 fullList.push_back( *itPP );
4926 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4927 fullList.pop_back();
4929 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4930 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4931 itPP = currList.begin();
4932 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4933 gp_Dir D1 = PP1.Tangent();
4934 gp_Dir D2 = PP2.Tangent();
4935 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4936 (D1.Z()+D2.Z())/2 ) );
4937 PP1.SetTangent(Dnew);
4938 fullList.push_back(PP1);
4940 for(; itPP!=currList.end(); itPP++) {
4941 fullList.push_back( *itPP );
4943 PP1 = fullList.back();
4944 fullList.pop_back();
4946 // if wire not closed
4947 fullList.push_back(PP1);
4951 return EXTR_BAD_PATH_SHAPE;
4954 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4955 theHasRefPoint, theRefPoint, theMakeGroups);
4959 //=======================================================================
4960 //function : MakeEdgePathPoints
4961 //purpose : auxilary for ExtrusionAlongTrack
4962 //=======================================================================
4963 SMESH_MeshEditor::Extrusion_Error
4964 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4965 const TopoDS_Edge& aTrackEdge,
4967 list<SMESH_MeshEditor_PathPoint>& LPP)
4969 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4971 aTolVec2=aTolVec*aTolVec;
4973 TopoDS_Vertex aV1, aV2;
4974 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4975 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4976 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4977 // 2. Collect parameters on the track edge
4978 aPrms.push_front( aT1 );
4979 aPrms.push_back( aT2 );
4982 if( FirstIsStart ) {
4993 SMESH_MeshEditor_PathPoint aPP;
4994 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4995 std::list<double>::iterator aItD = aPrms.begin();
4996 for(; aItD != aPrms.end(); ++aItD) {
5000 aC3D->D1( aT, aP3D, aVec );
5001 aL2 = aVec.SquareMagnitude();
5002 if ( aL2 < aTolVec2 )
5003 return EXTR_CANT_GET_TANGENT;
5004 gp_Dir aTgt( aVec );
5006 aPP.SetTangent( aTgt );
5007 aPP.SetParameter( aT );
5014 //=======================================================================
5015 //function : MakeExtrElements
5016 //purpose : auxilary for ExtrusionAlongTrack
5017 //=======================================================================
5018 SMESH_MeshEditor::Extrusion_Error
5019 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5020 list<SMESH_MeshEditor_PathPoint>& fullList,
5021 const bool theHasAngles,
5022 list<double>& theAngles,
5023 const bool theLinearVariation,
5024 const bool theHasRefPoint,
5025 const gp_Pnt& theRefPoint,
5026 const bool theMakeGroups)
5028 MESSAGE("MakeExtrElements");
5029 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5030 int aNbTP = fullList.size();
5031 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5033 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5034 LinearAngleVariation(aNbTP-1, theAngles);
5036 vector<double> aAngles( aNbTP );
5038 for(; j<aNbTP; ++j) {
5041 if ( theHasAngles ) {
5043 std::list<double>::iterator aItD = theAngles.begin();
5044 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5046 aAngles[j] = anAngle;
5049 // fill vector of path points with angles
5050 //aPPs.resize(fullList.size());
5052 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5053 for(; itPP!=fullList.end(); itPP++) {
5055 SMESH_MeshEditor_PathPoint PP = *itPP;
5056 PP.SetAngle(aAngles[j]);
5060 TNodeOfNodeListMap mapNewNodes;
5061 TElemOfVecOfNnlmiMap mapElemNewNodes;
5062 TElemOfElemListMap newElemsMap;
5063 TIDSortedElemSet::iterator itElem;
5066 SMDSAbs_ElementType aTypeE;
5067 // source elements for each generated one
5068 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5070 // 3. Center of rotation aV0
5071 gp_Pnt aV0 = theRefPoint;
5073 if ( !theHasRefPoint ) {
5075 aGC.SetCoord( 0.,0.,0. );
5077 itElem = theElements.begin();
5078 for ( ; itElem != theElements.end(); itElem++ ) {
5079 const SMDS_MeshElement* elem = *itElem;
5081 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5082 while ( itN->more() ) {
5083 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5088 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5089 list<const SMDS_MeshNode*> aLNx;
5090 mapNewNodes[node] = aLNx;
5092 gp_XYZ aXYZ( aX, aY, aZ );
5100 } // if (!theHasRefPoint) {
5101 mapNewNodes.clear();
5103 // 4. Processing the elements
5104 SMESHDS_Mesh* aMesh = GetMeshDS();
5106 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5107 // check element type
5108 const SMDS_MeshElement* elem = *itElem;
5109 aTypeE = elem->GetType();
5110 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5113 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5114 newNodesItVec.reserve( elem->NbNodes() );
5116 // loop on elem nodes
5118 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5119 while ( itN->more() )
5122 // check if a node has been already processed
5123 const SMDS_MeshNode* node =
5124 static_cast<const SMDS_MeshNode*>( itN->next() );
5125 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5126 if ( nIt == mapNewNodes.end() ) {
5127 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5128 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5131 aX = node->X(); aY = node->Y(); aZ = node->Z();
5133 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5134 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5135 gp_Ax1 anAx1, anAxT1T0;
5136 gp_Dir aDT1x, aDT0x, aDT1T0;
5141 aPN0.SetCoord(aX, aY, aZ);
5143 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5145 aDT0x= aPP0.Tangent();
5146 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5148 for ( j = 1; j < aNbTP; ++j ) {
5149 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5151 aDT1x = aPP1.Tangent();
5152 aAngle1x = aPP1.Angle();
5154 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5156 gp_Vec aV01x( aP0x, aP1x );
5157 aTrsf.SetTranslation( aV01x );
5160 aV1x = aV0x.Transformed( aTrsf );
5161 aPN1 = aPN0.Transformed( aTrsf );
5163 // rotation 1 [ T1,T0 ]
5164 aAngleT1T0=-aDT1x.Angle( aDT0x );
5165 if (fabs(aAngleT1T0) > aTolAng) {
5167 anAxT1T0.SetLocation( aV1x );
5168 anAxT1T0.SetDirection( aDT1T0 );
5169 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5171 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5175 if ( theHasAngles ) {
5176 anAx1.SetLocation( aV1x );
5177 anAx1.SetDirection( aDT1x );
5178 aTrsfRot.SetRotation( anAx1, aAngle1x );
5180 aPN1 = aPN1.Transformed( aTrsfRot );
5184 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5185 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5186 // create additional node
5187 double x = ( aPN1.X() + aPN0.X() )/2.;
5188 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5189 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5190 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5191 myLastCreatedNodes.Append(newNode);
5192 srcNodes.Append( node );
5193 listNewNodes.push_back( newNode );
5198 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5199 myLastCreatedNodes.Append(newNode);
5200 srcNodes.Append( node );
5201 listNewNodes.push_back( newNode );
5211 // if current elem is quadratic and current node is not medium
5212 // we have to check - may be it is needed to insert additional nodes
5213 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5214 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5215 if(listNewNodes.size()==aNbTP-1) {
5216 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5217 gp_XYZ P(node->X(), node->Y(), node->Z());
5218 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5220 for(i=0; i<aNbTP-1; i++) {
5221 const SMDS_MeshNode* N = *it;
5222 double x = ( N->X() + P.X() )/2.;
5223 double y = ( N->Y() + P.Y() )/2.;
5224 double z = ( N->Z() + P.Z() )/2.;
5225 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5226 srcNodes.Append( node );
5227 myLastCreatedNodes.Append(newN);
5230 P = gp_XYZ(N->X(),N->Y(),N->Z());
5232 listNewNodes.clear();
5233 for(i=0; i<2*(aNbTP-1); i++) {
5234 listNewNodes.push_back(aNodes[i]);
5240 newNodesItVec.push_back( nIt );
5242 // make new elements
5243 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5244 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5245 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5248 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5250 if ( theMakeGroups )
5251 generateGroups( srcNodes, srcElems, "extruded");
5257 //=======================================================================
5258 //function : LinearAngleVariation
5259 //purpose : auxilary for ExtrusionAlongTrack
5260 //=======================================================================
5261 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5262 list<double>& Angles)
5264 int nbAngles = Angles.size();
5265 if( nbSteps > nbAngles ) {
5266 vector<double> theAngles(nbAngles);
5267 list<double>::iterator it = Angles.begin();
5269 for(; it!=Angles.end(); it++) {
5271 theAngles[i] = (*it);
5274 double rAn2St = double( nbAngles ) / double( nbSteps );
5275 double angPrev = 0, angle;
5276 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5277 double angCur = rAn2St * ( iSt+1 );
5278 double angCurFloor = floor( angCur );
5279 double angPrevFloor = floor( angPrev );
5280 if ( angPrevFloor == angCurFloor )
5281 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5283 int iP = int( angPrevFloor );
5284 double angPrevCeil = ceil(angPrev);
5285 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5287 int iC = int( angCurFloor );
5288 if ( iC < nbAngles )
5289 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5291 iP = int( angPrevCeil );
5293 angle += theAngles[ iC ];
5295 res.push_back(angle);
5300 for(; it!=res.end(); it++)
5301 Angles.push_back( *it );
5306 //================================================================================
5308 * \brief Move or copy theElements applying theTrsf to their nodes
5309 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5310 * \param theTrsf - transformation to apply
5311 * \param theCopy - if true, create translated copies of theElems
5312 * \param theMakeGroups - if true and theCopy, create translated groups
5313 * \param theTargetMesh - mesh to copy translated elements into
5314 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5316 //================================================================================
5318 SMESH_MeshEditor::PGroupIDs
5319 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5320 const gp_Trsf& theTrsf,
5322 const bool theMakeGroups,
5323 SMESH_Mesh* theTargetMesh)
5325 myLastCreatedElems.Clear();
5326 myLastCreatedNodes.Clear();
5328 bool needReverse = false;
5329 string groupPostfix;
5330 switch ( theTrsf.Form() ) {
5332 MESSAGE("gp_PntMirror");
5334 groupPostfix = "mirrored";
5337 MESSAGE("gp_Ax1Mirror");
5338 groupPostfix = "mirrored";
5341 MESSAGE("gp_Ax2Mirror");
5343 groupPostfix = "mirrored";
5346 MESSAGE("gp_Rotation");
5347 groupPostfix = "rotated";
5349 case gp_Translation:
5350 MESSAGE("gp_Translation");
5351 groupPostfix = "translated";
5354 MESSAGE("gp_Scale");
5355 groupPostfix = "scaled";
5357 case gp_CompoundTrsf: // different scale by axis
5358 MESSAGE("gp_CompoundTrsf");
5359 groupPostfix = "scaled";
5363 needReverse = false;
5364 groupPostfix = "transformed";
5367 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5368 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5369 SMESHDS_Mesh* aMesh = GetMeshDS();
5372 // map old node to new one
5373 TNodeNodeMap nodeMap;
5375 // elements sharing moved nodes; those of them which have all
5376 // nodes mirrored but are not in theElems are to be reversed
5377 TIDSortedElemSet inverseElemSet;
5379 // source elements for each generated one
5380 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5382 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5383 TIDSortedElemSet orphanNode;
5385 if ( theElems.empty() ) // transform the whole mesh
5388 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5389 while ( eIt->more() ) theElems.insert( eIt->next() );
5391 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5392 while ( nIt->more() )
5394 const SMDS_MeshNode* node = nIt->next();
5395 if ( node->NbInverseElements() == 0)
5396 orphanNode.insert( node );
5400 // loop on elements to transform nodes : first orphan nodes then elems
5401 TIDSortedElemSet::iterator itElem;
5402 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5403 for (int i=0; i<2; i++)
5404 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5405 const SMDS_MeshElement* elem = *itElem;
5409 // loop on elem nodes
5410 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5411 while ( itN->more() ) {
5413 const SMDS_MeshNode* node = cast2Node( itN->next() );
5414 // check if a node has been already transformed
5415 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5416 nodeMap.insert( make_pair ( node, node ));
5417 if ( !n2n_isnew.second )
5421 coord[0] = node->X();
5422 coord[1] = node->Y();
5423 coord[2] = node->Z();
5424 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5425 if ( theTargetMesh ) {
5426 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5427 n2n_isnew.first->second = newNode;
5428 myLastCreatedNodes.Append(newNode);
5429 srcNodes.Append( node );
5431 else if ( theCopy ) {
5432 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5433 n2n_isnew.first->second = newNode;
5434 myLastCreatedNodes.Append(newNode);
5435 srcNodes.Append( node );
5438 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5439 // node position on shape becomes invalid
5440 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5441 ( SMDS_SpacePosition::originSpacePosition() );
5444 // keep inverse elements
5445 if ( !theCopy && !theTargetMesh && needReverse ) {
5446 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5447 while ( invElemIt->more() ) {
5448 const SMDS_MeshElement* iel = invElemIt->next();
5449 inverseElemSet.insert( iel );
5455 // either create new elements or reverse mirrored ones
5456 if ( !theCopy && !needReverse && !theTargetMesh )
5459 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5460 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5461 theElems.insert( *invElemIt );
5463 // replicate or reverse elements
5464 // TODO revoir ordre reverse vtk
5466 REV_TETRA = 0, // = nbNodes - 4
5467 REV_PYRAMID = 1, // = nbNodes - 4
5468 REV_PENTA = 2, // = nbNodes - 4
5470 REV_HEXA = 4, // = nbNodes - 4
5474 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5475 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5476 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5477 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5478 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5479 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5482 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5484 const SMDS_MeshElement* elem = *itElem;
5485 if ( !elem || elem->GetType() == SMDSAbs_Node )
5488 int nbNodes = elem->NbNodes();
5489 int elemType = elem->GetType();
5491 if (elem->IsPoly()) {
5492 // Polygon or Polyhedral Volume
5493 switch ( elemType ) {
5496 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5498 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5499 while (itN->more()) {
5500 const SMDS_MeshNode* node =
5501 static_cast<const SMDS_MeshNode*>(itN->next());
5502 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5503 if (nodeMapIt == nodeMap.end())
5504 break; // not all nodes transformed
5506 // reverse mirrored faces and volumes
5507 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5509 poly_nodes[iNode] = (*nodeMapIt).second;
5513 if ( iNode != nbNodes )
5514 continue; // not all nodes transformed
5516 if ( theTargetMesh ) {
5517 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5518 srcElems.Append( elem );
5520 else if ( theCopy ) {
5521 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5522 srcElems.Append( elem );
5525 aMesh->ChangePolygonNodes(elem, poly_nodes);
5529 case SMDSAbs_Volume:
5531 // ATTENTION: Reversing is not yet done!!!
5532 const SMDS_VtkVolume* aPolyedre =
5533 dynamic_cast<const SMDS_VtkVolume*>( elem );
5535 MESSAGE("Warning: bad volumic element");
5539 vector<const SMDS_MeshNode*> poly_nodes;
5540 vector<int> quantities;
5542 bool allTransformed = true;
5543 int nbFaces = aPolyedre->NbFaces();
5544 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5545 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5546 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5547 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5548 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5549 if (nodeMapIt == nodeMap.end()) {
5550 allTransformed = false; // not all nodes transformed
5552 poly_nodes.push_back((*nodeMapIt).second);
5555 quantities.push_back(nbFaceNodes);
5557 if ( !allTransformed )
5558 continue; // not all nodes transformed
5560 if ( theTargetMesh ) {
5561 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5562 srcElems.Append( elem );
5564 else if ( theCopy ) {
5565 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5566 srcElems.Append( elem );
5569 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5579 int* i = index[ FORWARD ];
5580 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5581 if ( elemType == SMDSAbs_Face )
5582 i = index[ REV_FACE ];
5584 i = index[ nbNodes - 4 ];
5586 if(elem->IsQuadratic()) {
5587 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5590 if(nbNodes==3) { // quadratic edge
5591 static int anIds[] = {1,0,2};
5594 else if(nbNodes==6) { // quadratic triangle
5595 static int anIds[] = {0,2,1,5,4,3};
5598 else if(nbNodes==8) { // quadratic quadrangle
5599 static int anIds[] = {0,3,2,1,7,6,5,4};
5602 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5603 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5606 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5607 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5610 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5611 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5614 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5615 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5621 // find transformed nodes
5622 vector<const SMDS_MeshNode*> nodes(nbNodes);
5624 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5625 while ( itN->more() ) {
5626 const SMDS_MeshNode* node =
5627 static_cast<const SMDS_MeshNode*>( itN->next() );
5628 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5629 if ( nodeMapIt == nodeMap.end() )
5630 break; // not all nodes transformed
5631 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5633 if ( iNode != nbNodes )
5634 continue; // not all nodes transformed
5636 if ( theTargetMesh ) {
5637 if ( SMDS_MeshElement* copy =
5638 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5639 myLastCreatedElems.Append( copy );
5640 srcElems.Append( elem );
5643 else if ( theCopy ) {
5644 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5645 srcElems.Append( elem );
5648 // reverse element as it was reversed by transformation
5650 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5654 PGroupIDs newGroupIDs;
5656 if ( ( theMakeGroups && theCopy ) ||
5657 ( theMakeGroups && theTargetMesh ) )
5658 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5664 ////=======================================================================
5665 ////function : Scale
5667 ////=======================================================================
5669 //SMESH_MeshEditor::PGroupIDs
5670 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5671 // const gp_Pnt& thePoint,
5672 // const std::list<double>& theScaleFact,
5673 // const bool theCopy,
5674 // const bool theMakeGroups,
5675 // SMESH_Mesh* theTargetMesh)
5677 // MESSAGE("Scale");
5678 // myLastCreatedElems.Clear();
5679 // myLastCreatedNodes.Clear();
5681 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5682 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5683 // SMESHDS_Mesh* aMesh = GetMeshDS();
5685 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5686 // std::list<double>::const_iterator itS = theScaleFact.begin();
5688 // if(theScaleFact.size()==1) {
5692 // if(theScaleFact.size()==2) {
5697 // if(theScaleFact.size()>2) {
5704 // // map old node to new one
5705 // TNodeNodeMap nodeMap;
5707 // // elements sharing moved nodes; those of them which have all
5708 // // nodes mirrored but are not in theElems are to be reversed
5709 // TIDSortedElemSet inverseElemSet;
5711 // // source elements for each generated one
5712 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5714 // // loop on theElems
5715 // TIDSortedElemSet::iterator itElem;
5716 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5717 // const SMDS_MeshElement* elem = *itElem;
5721 // // loop on elem nodes
5722 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5723 // while ( itN->more() ) {
5725 // // check if a node has been already transformed
5726 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5727 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5728 // nodeMap.insert( make_pair ( node, node ));
5729 // if ( !n2n_isnew.second )
5732 // //double coord[3];
5733 // //coord[0] = node->X();
5734 // //coord[1] = node->Y();
5735 // //coord[2] = node->Z();
5736 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5737 // double dx = (node->X() - thePoint.X()) * scaleX;
5738 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5739 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5740 // if ( theTargetMesh ) {
5741 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5742 // const SMDS_MeshNode * newNode =
5743 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5744 // n2n_isnew.first->second = newNode;
5745 // myLastCreatedNodes.Append(newNode);
5746 // srcNodes.Append( node );
5748 // else if ( theCopy ) {
5749 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5750 // const SMDS_MeshNode * newNode =
5751 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5752 // n2n_isnew.first->second = newNode;
5753 // myLastCreatedNodes.Append(newNode);
5754 // srcNodes.Append( node );
5757 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5758 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5759 // // node position on shape becomes invalid
5760 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5761 // ( SMDS_SpacePosition::originSpacePosition() );
5764 // // keep inverse elements
5765 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5766 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5767 // // while ( invElemIt->more() ) {
5768 // // const SMDS_MeshElement* iel = invElemIt->next();
5769 // // inverseElemSet.insert( iel );
5775 // // either create new elements or reverse mirrored ones
5776 // //if ( !theCopy && !needReverse && !theTargetMesh )
5777 // if ( !theCopy && !theTargetMesh )
5778 // return PGroupIDs();
5780 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5781 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5782 // theElems.insert( *invElemIt );
5784 // // replicate or reverse elements
5787 // REV_TETRA = 0, // = nbNodes - 4
5788 // REV_PYRAMID = 1, // = nbNodes - 4
5789 // REV_PENTA = 2, // = nbNodes - 4
5791 // REV_HEXA = 4, // = nbNodes - 4
5794 // int index[][8] = {
5795 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5796 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5797 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5798 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5799 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5800 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5803 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5805 // const SMDS_MeshElement* elem = *itElem;
5806 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5809 // int nbNodes = elem->NbNodes();
5810 // int elemType = elem->GetType();
5812 // if (elem->IsPoly()) {
5813 // // Polygon or Polyhedral Volume
5814 // switch ( elemType ) {
5815 // case SMDSAbs_Face:
5817 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5819 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5820 // while (itN->more()) {
5821 // const SMDS_MeshNode* node =
5822 // static_cast<const SMDS_MeshNode*>(itN->next());
5823 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5824 // if (nodeMapIt == nodeMap.end())
5825 // break; // not all nodes transformed
5826 // //if (needReverse) {
5827 // // // reverse mirrored faces and volumes
5828 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5830 // poly_nodes[iNode] = (*nodeMapIt).second;
5834 // if ( iNode != nbNodes )
5835 // continue; // not all nodes transformed
5837 // if ( theTargetMesh ) {
5838 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5839 // srcElems.Append( elem );
5841 // else if ( theCopy ) {
5842 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5843 // srcElems.Append( elem );
5846 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5850 // case SMDSAbs_Volume:
5852 // // ATTENTION: Reversing is not yet done!!!
5853 // const SMDS_VtkVolume* aPolyedre =
5854 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5855 // if (!aPolyedre) {
5856 // MESSAGE("Warning: bad volumic element");
5860 // vector<const SMDS_MeshNode*> poly_nodes;
5861 // vector<int> quantities;
5863 // bool allTransformed = true;
5864 // int nbFaces = aPolyedre->NbFaces();
5865 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5866 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5867 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5868 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5869 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5870 // if (nodeMapIt == nodeMap.end()) {
5871 // allTransformed = false; // not all nodes transformed
5873 // poly_nodes.push_back((*nodeMapIt).second);
5876 // quantities.push_back(nbFaceNodes);
5878 // if ( !allTransformed )
5879 // continue; // not all nodes transformed
5881 // if ( theTargetMesh ) {
5882 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5883 // srcElems.Append( elem );
5885 // else if ( theCopy ) {
5886 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5887 // srcElems.Append( elem );
5890 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5899 // // Regular elements
5900 // int* i = index[ FORWARD ];
5901 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5902 // // if ( elemType == SMDSAbs_Face )
5903 // // i = index[ REV_FACE ];
5905 // // i = index[ nbNodes - 4 ];
5907 // if(elem->IsQuadratic()) {
5908 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5910 // //if(needReverse) {
5911 // // if(nbNodes==3) { // quadratic edge
5912 // // static int anIds[] = {1,0,2};
5915 // // else if(nbNodes==6) { // quadratic triangle
5916 // // static int anIds[] = {0,2,1,5,4,3};
5919 // // else if(nbNodes==8) { // quadratic quadrangle
5920 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5923 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5924 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5927 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5928 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5931 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5932 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5935 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5936 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5942 // // find transformed nodes
5943 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5945 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5946 // while ( itN->more() ) {
5947 // const SMDS_MeshNode* node =
5948 // static_cast<const SMDS_MeshNode*>( itN->next() );
5949 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5950 // if ( nodeMapIt == nodeMap.end() )
5951 // break; // not all nodes transformed
5952 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5954 // if ( iNode != nbNodes )
5955 // continue; // not all nodes transformed
5957 // if ( theTargetMesh ) {
5958 // if ( SMDS_MeshElement* copy =
5959 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5960 // myLastCreatedElems.Append( copy );
5961 // srcElems.Append( elem );
5964 // else if ( theCopy ) {
5965 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5966 // myLastCreatedElems.Append( copy );
5967 // srcElems.Append( elem );
5971 // // reverse element as it was reversed by transformation
5972 // if ( nbNodes > 2 )
5973 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5977 // PGroupIDs newGroupIDs;
5979 // if ( theMakeGroups && theCopy ||
5980 // theMakeGroups && theTargetMesh ) {
5981 // string groupPostfix = "scaled";
5982 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5985 // return newGroupIDs;
5989 //=======================================================================
5991 * \brief Create groups of elements made during transformation
5992 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5993 * \param elemGens - elements making corresponding myLastCreatedElems
5994 * \param postfix - to append to names of new groups
5996 //=======================================================================
5998 SMESH_MeshEditor::PGroupIDs
5999 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6000 const SMESH_SequenceOfElemPtr& elemGens,
6001 const std::string& postfix,
6002 SMESH_Mesh* targetMesh)
6004 PGroupIDs newGroupIDs( new list<int> );
6005 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6007 // Sort existing groups by types and collect their names
6009 // to store an old group and a generated new one
6010 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6011 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6013 set< string > groupNames;
6015 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6016 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6017 while ( groupIt->more() ) {
6018 SMESH_Group * group = groupIt->next();
6019 if ( !group ) continue;
6020 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6021 if ( !groupDS || groupDS->IsEmpty() ) continue;
6022 groupNames.insert( group->GetName() );
6023 groupDS->SetStoreName( group->GetName() );
6024 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6029 // loop on nodes and elements
6030 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6032 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6033 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6034 if ( gens.Length() != elems.Length() )
6035 throw SALOME_Exception(LOCALIZED("invalid args"));
6037 // loop on created elements
6038 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6040 const SMDS_MeshElement* sourceElem = gens( iElem );
6041 if ( !sourceElem ) {
6042 MESSAGE("generateGroups(): NULL source element");
6045 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6046 if ( groupsOldNew.empty() ) {
6047 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6048 ++iElem; // skip all elements made by sourceElem
6051 // collect all elements made by sourceElem
6052 list< const SMDS_MeshElement* > resultElems;
6053 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6054 if ( resElem != sourceElem )
6055 resultElems.push_back( resElem );
6056 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6057 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6058 if ( resElem != sourceElem )
6059 resultElems.push_back( resElem );
6060 // do not generate element groups from node ones
6061 if ( sourceElem->GetType() == SMDSAbs_Node &&
6062 elems( iElem )->GetType() != SMDSAbs_Node )
6065 // add resultElems to groups made by ones the sourceElem belongs to
6066 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6067 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6069 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6070 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6072 SMDS_MeshGroup* & newGroup = gOldNew->second;
6073 if ( !newGroup )// create a new group
6076 string name = oldGroup->GetStoreName();
6077 if ( !targetMesh ) {
6081 while ( !groupNames.insert( name ).second ) // name exists
6087 TCollection_AsciiString nbStr(nb+1);
6088 name.resize( name.rfind('_')+1 );
6089 name += nbStr.ToCString();
6096 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6098 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6099 newGroup = & groupDS->SMDSGroup();
6100 newGroupIDs->push_back( id );
6103 // fill in a new group
6104 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6105 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6106 newGroup->Add( *resElemIt );
6109 } // loop on created elements
6110 }// loop on nodes and elements
6115 //================================================================================
6117 * \brief Return list of group of nodes close to each other within theTolerance
6118 * Search among theNodes or in the whole mesh if theNodes is empty using
6119 * an Octree algorithm
6121 //================================================================================
6123 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6124 const double theTolerance,
6125 TListOfListOfNodes & theGroupsOfNodes)
6127 myLastCreatedElems.Clear();
6128 myLastCreatedNodes.Clear();
6130 if ( theNodes.empty() )
6131 { // get all nodes in the mesh
6132 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6133 while ( nIt->more() )
6134 theNodes.insert( theNodes.end(),nIt->next());
6137 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6141 //=======================================================================
6143 * \brief Implementation of search for the node closest to point
6145 //=======================================================================
6147 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6149 //---------------------------------------------------------------------
6151 * \brief Constructor
6153 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6155 myMesh = ( SMESHDS_Mesh* ) theMesh;
6157 TIDSortedNodeSet nodes;
6159 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6160 while ( nIt->more() )
6161 nodes.insert( nodes.end(), nIt->next() );
6163 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6165 // get max size of a leaf box
6166 SMESH_OctreeNode* tree = myOctreeNode;
6167 while ( !tree->isLeaf() )
6169 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6173 myHalfLeafSize = tree->maxSize() / 2.;
6176 //---------------------------------------------------------------------
6178 * \brief Move node and update myOctreeNode accordingly
6180 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6182 myOctreeNode->UpdateByMoveNode( node, toPnt );
6183 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6186 //---------------------------------------------------------------------
6188 * \brief Do it's job
6190 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6192 map<double, const SMDS_MeshNode*> dist2Nodes;
6193 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6194 if ( !dist2Nodes.empty() )
6195 return dist2Nodes.begin()->second;
6196 list<const SMDS_MeshNode*> nodes;
6197 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6199 double minSqDist = DBL_MAX;
6200 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6202 // sort leafs by their distance from thePnt
6203 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6204 TDistTreeMap treeMap;
6205 list< SMESH_OctreeNode* > treeList;
6206 list< SMESH_OctreeNode* >::iterator trIt;
6207 treeList.push_back( myOctreeNode );
6209 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6210 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6211 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6213 SMESH_OctreeNode* tree = *trIt;
6214 if ( !tree->isLeaf() ) // put children to the queue
6216 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6217 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6218 while ( cIt->more() )
6219 treeList.push_back( cIt->next() );
6221 else if ( tree->NbNodes() ) // put a tree to the treeMap
6223 const Bnd_B3d& box = tree->getBox();
6224 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6225 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6226 if ( !it_in.second ) // not unique distance to box center
6227 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6230 // find distance after which there is no sense to check tree's
6231 double sqLimit = DBL_MAX;
6232 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6233 if ( treeMap.size() > 5 ) {
6234 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6235 const Bnd_B3d& box = closestTree->getBox();
6236 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6237 sqLimit = limit * limit;
6239 // get all nodes from trees
6240 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6241 if ( sqDist_tree->first > sqLimit )
6243 SMESH_OctreeNode* tree = sqDist_tree->second;
6244 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6247 // find closest among nodes
6248 minSqDist = DBL_MAX;
6249 const SMDS_MeshNode* closestNode = 0;
6250 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6251 for ( ; nIt != nodes.end(); ++nIt ) {
6252 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6253 if ( minSqDist > sqDist ) {
6261 //---------------------------------------------------------------------
6265 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6267 //---------------------------------------------------------------------
6269 * \brief Return the node tree
6271 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6274 SMESH_OctreeNode* myOctreeNode;
6275 SMESHDS_Mesh* myMesh;
6276 double myHalfLeafSize; // max size of a leaf box
6279 //=======================================================================
6281 * \brief Return SMESH_NodeSearcher
6283 //=======================================================================
6285 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6287 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6290 // ========================================================================
6291 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6293 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6294 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6295 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6297 //=======================================================================
6299 * \brief Octal tree of bounding boxes of elements
6301 //=======================================================================
6303 class ElementBndBoxTree : public SMESH_Octree
6307 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6308 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6309 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6310 ~ElementBndBoxTree();
6313 ElementBndBoxTree() {}
6314 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6315 void buildChildrenData();
6316 Bnd_B3d* buildRootBox();
6318 //!< Bounding box of element
6319 struct ElementBox : public Bnd_B3d
6321 const SMDS_MeshElement* _element;
6322 int _refCount; // an ElementBox can be included in several tree branches
6323 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6325 vector< ElementBox* > _elements;
6328 //================================================================================
6330 * \brief ElementBndBoxTree creation
6332 //================================================================================
6334 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6335 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6337 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6338 _elements.reserve( nbElems );
6340 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6341 while ( elemIt->more() )
6342 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6344 if ( _elements.size() > MaxNbElemsInLeaf )
6350 //================================================================================
6354 //================================================================================
6356 ElementBndBoxTree::~ElementBndBoxTree()
6358 for ( int i = 0; i < _elements.size(); ++i )
6359 if ( --_elements[i]->_refCount <= 0 )
6360 delete _elements[i];
6363 //================================================================================
6365 * \brief Return the maximal box
6367 //================================================================================
6369 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6371 Bnd_B3d* box = new Bnd_B3d;
6372 for ( int i = 0; i < _elements.size(); ++i )
6373 box->Add( *_elements[i] );
6377 //================================================================================
6379 * \brief Redistrubute element boxes among children
6381 //================================================================================
6383 void ElementBndBoxTree::buildChildrenData()
6385 for ( int i = 0; i < _elements.size(); ++i )
6387 for (int j = 0; j < 8; j++)
6389 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6391 _elements[i]->_refCount++;
6392 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6395 _elements[i]->_refCount--;
6399 for (int j = 0; j < 8; j++)
6401 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6402 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6403 child->myIsLeaf = true;
6405 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6406 child->_elements.resize( child->_elements.size() ); // compact
6410 //================================================================================
6412 * \brief Return elements which can include the point
6414 //================================================================================
6416 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6417 TIDSortedElemSet& foundElems)
6419 if ( level() && getBox().IsOut( point.XYZ() ))
6424 for ( int i = 0; i < _elements.size(); ++i )
6425 if ( !_elements[i]->IsOut( point.XYZ() ))
6426 foundElems.insert( _elements[i]->_element );
6430 for (int i = 0; i < 8; i++)
6431 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6435 //================================================================================
6437 * \brief Return elements which can be intersected by the line
6439 //================================================================================
6441 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6442 TIDSortedElemSet& foundElems)
6444 if ( level() && getBox().IsOut( line ))
6449 for ( int i = 0; i < _elements.size(); ++i )
6450 if ( !_elements[i]->IsOut( line ))
6451 foundElems.insert( _elements[i]->_element );
6455 for (int i = 0; i < 8; i++)
6456 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6460 //================================================================================
6462 * \brief Construct the element box
6464 //================================================================================
6466 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6470 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6471 while ( nIt->more() )
6472 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6473 Enlarge( tolerance );
6478 //=======================================================================
6480 * \brief Implementation of search for the elements by point and
6481 * of classification of point in 2D mesh
6483 //=======================================================================
6485 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6487 SMESHDS_Mesh* _mesh;
6488 SMDS_ElemIteratorPtr _meshPartIt;
6489 ElementBndBoxTree* _ebbTree;
6490 SMESH_NodeSearcherImpl* _nodeSearcher;
6491 SMDSAbs_ElementType _elementType;
6493 bool _outerFacesFound;
6494 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6496 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6497 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6498 ~SMESH_ElementSearcherImpl()
6500 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6501 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6503 virtual int FindElementsByPoint(const gp_Pnt& point,
6504 SMDSAbs_ElementType type,
6505 vector< const SMDS_MeshElement* >& foundElements);
6506 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6508 void GetElementsNearLine( const gp_Ax1& line,
6509 SMDSAbs_ElementType type,
6510 vector< const SMDS_MeshElement* >& foundElems);
6511 double getTolerance();
6512 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6513 const double tolerance, double & param);
6514 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6515 bool isOuterBoundary(const SMDS_MeshElement* face) const
6517 return _outerFaces.empty() || _outerFaces.count(face);
6519 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6521 const SMDS_MeshElement* _face;
6523 bool _coincides; //!< the line lays in face plane
6524 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6525 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6527 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6530 TIDSortedElemSet _faces;
6531 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6532 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6536 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6538 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6539 << ", _coincides="<<i._coincides << ")";
6542 //=======================================================================
6544 * \brief define tolerance for search
6546 //=======================================================================
6548 double SMESH_ElementSearcherImpl::getTolerance()
6550 if ( _tolerance < 0 )
6552 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6555 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6557 double boxSize = _nodeSearcher->getTree()->maxSize();
6558 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6560 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6562 double boxSize = _ebbTree->maxSize();
6563 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6565 if ( _tolerance == 0 )
6567 // define tolerance by size of a most complex element
6568 int complexType = SMDSAbs_Volume;
6569 while ( complexType > SMDSAbs_All &&
6570 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6572 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6574 if ( complexType == int( SMDSAbs_Node ))
6576 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6578 if ( meshInfo.NbNodes() > 2 )
6579 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6583 SMDS_ElemIteratorPtr elemIt =
6584 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6585 const SMDS_MeshElement* elem = elemIt->next();
6586 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6587 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6589 while ( nodeIt->more() )
6591 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6592 elemSize = max( dist, elemSize );
6595 _tolerance = 1e-4 * elemSize;
6601 //================================================================================
6603 * \brief Find intersection of the line and an edge of face and return parameter on line
6605 //================================================================================
6607 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6608 const SMDS_MeshElement* face,
6615 GeomAPI_ExtremaCurveCurve anExtCC;
6616 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6618 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6619 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6621 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6622 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6623 anExtCC.Init( lineCurve, edge);
6624 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6626 Quantity_Parameter pl, pe;
6627 anExtCC.LowerDistanceParameters( pl, pe );
6629 if ( ++nbInts == 2 )
6633 if ( nbInts > 0 ) param /= nbInts;
6636 //================================================================================
6638 * \brief Find all faces belonging to the outer boundary of mesh
6640 //================================================================================
6642 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6644 if ( _outerFacesFound ) return;
6646 // Collect all outer faces by passing from one outer face to another via their links
6647 // and BTW find out if there are internal faces at all.
6649 // checked links and links where outer boundary meets internal one
6650 set< SMESH_TLink > visitedLinks, seamLinks;
6652 // links to treat with already visited faces sharing them
6653 list < TFaceLink > startLinks;
6655 // load startLinks with the first outerFace
6656 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6657 _outerFaces.insert( outerFace );
6659 TIDSortedElemSet emptySet;
6660 while ( !startLinks.empty() )
6662 const SMESH_TLink& link = startLinks.front()._link;
6663 TIDSortedElemSet& faces = startLinks.front()._faces;
6665 outerFace = *faces.begin();
6666 // find other faces sharing the link
6667 const SMDS_MeshElement* f;
6668 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6671 // select another outer face among the found
6672 const SMDS_MeshElement* outerFace2 = 0;
6673 if ( faces.size() == 2 )
6675 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6677 else if ( faces.size() > 2 )
6679 seamLinks.insert( link );
6681 // link direction within the outerFace
6682 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6683 SMESH_TNodeXYZ( link.node2()));
6684 int i1 = outerFace->GetNodeIndex( link.node1() );
6685 int i2 = outerFace->GetNodeIndex( link.node2() );
6686 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6687 if ( rev ) n1n2.Reverse();
6689 gp_XYZ ofNorm, fNorm;
6690 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6692 // direction from the link inside outerFace
6693 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6694 // sort all other faces by angle with the dirInOF
6695 map< double, const SMDS_MeshElement* > angle2Face;
6696 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6697 for ( ; face != faces.end(); ++face )
6699 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6701 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6702 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6703 if ( angle < 0 ) angle += 2*PI;
6704 angle2Face.insert( make_pair( angle, *face ));
6706 if ( !angle2Face.empty() )
6707 outerFace2 = angle2Face.begin()->second;
6710 // store the found outer face and add its links to continue seaching from
6713 _outerFaces.insert( outerFace );
6714 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6715 for ( int i = 0; i < nbNodes; ++i )
6717 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6718 if ( visitedLinks.insert( link2 ).second )
6719 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6722 startLinks.pop_front();
6724 _outerFacesFound = true;
6726 if ( !seamLinks.empty() )
6728 // There are internal boundaries touching the outher one,
6729 // find all faces of internal boundaries in order to find
6730 // faces of boundaries of holes, if any.
6735 _outerFaces.clear();
6739 //=======================================================================
6741 * \brief Find elements of given type where the given point is IN or ON.
6742 * Returns nb of found elements and elements them-selves.
6744 * 'ALL' type means elements of any type excluding nodes and 0D elements
6746 //=======================================================================
6748 int SMESH_ElementSearcherImpl::
6749 FindElementsByPoint(const gp_Pnt& point,
6750 SMDSAbs_ElementType type,
6751 vector< const SMDS_MeshElement* >& foundElements)
6753 foundElements.clear();
6755 double tolerance = getTolerance();
6757 // =================================================================================
6758 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6760 if ( !_nodeSearcher )
6761 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6763 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6764 if ( !closeNode ) return foundElements.size();
6766 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6767 return foundElements.size(); // to far from any node
6769 if ( type == SMDSAbs_Node )
6771 foundElements.push_back( closeNode );
6775 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6776 while ( elemIt->more() )
6777 foundElements.push_back( elemIt->next() );
6780 // =================================================================================
6781 else // elements more complex than 0D
6783 if ( !_ebbTree || _elementType != type )
6785 if ( _ebbTree ) delete _ebbTree;
6786 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6788 TIDSortedElemSet suspectElems;
6789 _ebbTree->getElementsNearPoint( point, suspectElems );
6790 TIDSortedElemSet::iterator elem = suspectElems.begin();
6791 for ( ; elem != suspectElems.end(); ++elem )
6792 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6793 foundElements.push_back( *elem );
6795 return foundElements.size();
6798 //================================================================================
6800 * \brief Classify the given point in the closed 2D mesh
6802 //================================================================================
6804 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6806 double tolerance = getTolerance();
6807 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6809 if ( _ebbTree ) delete _ebbTree;
6810 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6812 // Algo: analyse transition of a line starting at the point through mesh boundary;
6813 // try three lines parallel to axis of the coordinate system and perform rough
6814 // analysis. If solution is not clear perform thorough analysis.
6816 const int nbAxes = 3;
6817 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6818 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6819 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6820 multimap< int, int > nbInt2Axis; // to find the simplest case
6821 for ( int axis = 0; axis < nbAxes; ++axis )
6823 gp_Ax1 lineAxis( point, axisDir[axis]);
6824 gp_Lin line ( lineAxis );
6826 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6827 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6829 // Intersect faces with the line
6831 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6832 TIDSortedElemSet::iterator face = suspectFaces.begin();
6833 for ( ; face != suspectFaces.end(); ++face )
6837 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6838 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6840 // perform intersection
6841 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6842 if ( !intersection.IsDone() )
6844 if ( intersection.IsInQuadric() )
6846 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6848 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6850 gp_Pnt intersectionPoint = intersection.Point(1);
6851 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6852 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6855 // Analyse intersections roughly
6857 int nbInter = u2inters.size();
6861 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6862 if ( nbInter == 1 ) // not closed mesh
6863 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6865 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6868 if ( (f<0) == (l<0) )
6871 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6872 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6873 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6876 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6878 if ( _outerFacesFound ) break; // pass to thorough analysis
6880 } // three attempts - loop on CS axes
6882 // Analyse intersections thoroughly.
6883 // We make two loops maximum, on the first one we only exclude touching intersections,
6884 // on the second, if situation is still unclear, we gather and use information on
6885 // position of faces (internal or outer). If faces position is already gathered,
6886 // we make the second loop right away.
6888 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6890 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6891 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6893 int axis = nb_axis->second;
6894 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6896 gp_Ax1 lineAxis( point, axisDir[axis]);
6897 gp_Lin line ( lineAxis );
6899 // add tangent intersections to u2inters
6901 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6902 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6903 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6904 u2inters.insert(make_pair( param, *tgtInt ));
6905 tangentInters[ axis ].clear();
6907 // Count intersections before and after the point excluding touching ones.
6908 // If hasPositionInfo we count intersections of outer boundary only
6910 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6911 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6912 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6913 bool ok = ! u_int1->second._coincides;
6914 while ( ok && u_int1 != u2inters.end() )
6916 double u = u_int1->first;
6917 bool touchingInt = false;
6918 if ( ++u_int2 != u2inters.end() )
6920 // skip intersections at the same point (if the line passes through edge or node)
6922 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6928 // skip tangent intersections
6930 const SMDS_MeshElement* prevFace = u_int1->second._face;
6931 while ( ok && u_int2->second._coincides )
6933 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6939 ok = ( u_int2 != u2inters.end() );
6944 // skip intersections at the same point after tangent intersections
6947 double u2 = u_int2->first;
6949 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6955 // decide if we skipped a touching intersection
6956 if ( nbSamePnt + nbTgt > 0 )
6958 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6959 map< double, TInters >::iterator u_int = u_int1;
6960 for ( ; u_int != u_int2; ++u_int )
6962 if ( u_int->second._coincides ) continue;
6963 double dot = u_int->second._faceNorm * line.Direction();
6964 if ( dot > maxDot ) maxDot = dot;
6965 if ( dot < minDot ) minDot = dot;
6967 touchingInt = ( minDot*maxDot < 0 );
6972 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6983 u_int1 = u_int2; // to next intersection
6985 } // loop on intersections with one line
6989 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6992 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6995 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6996 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6998 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7001 if ( (f<0) == (l<0) )
7004 if ( hasPositionInfo )
7005 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7007 } // loop on intersections of the tree lines - thorough analysis
7009 if ( !hasPositionInfo )
7011 // gather info on faces position - is face in the outer boundary or not
7012 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7013 findOuterBoundary( u2inters.begin()->second._face );
7016 } // two attempts - with and w/o faces position info in the mesh
7018 return TopAbs_UNKNOWN;
7021 //=======================================================================
7023 * \brief Return elements possibly intersecting the line
7025 //=======================================================================
7027 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7028 SMDSAbs_ElementType type,
7029 vector< const SMDS_MeshElement* >& foundElems)
7031 if ( !_ebbTree || _elementType != type )
7033 if ( _ebbTree ) delete _ebbTree;
7034 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7036 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7037 _ebbTree->getElementsNearLine( line, suspectFaces );
7038 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7041 //=======================================================================
7043 * \brief Return SMESH_ElementSearcher
7045 //=======================================================================
7047 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7049 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7052 //=======================================================================
7054 * \brief Return SMESH_ElementSearcher
7056 //=======================================================================
7058 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7060 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7063 //=======================================================================
7065 * \brief Return true if the point is IN or ON of the element
7067 //=======================================================================
7069 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7071 if ( element->GetType() == SMDSAbs_Volume)
7073 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7076 // get ordered nodes
7078 vector< gp_XYZ > xyz;
7079 vector<const SMDS_MeshNode*> nodeList;
7081 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7082 if ( element->IsQuadratic() ) {
7083 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7084 nodeIt = f->interlacedNodesElemIterator();
7085 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7086 nodeIt = e->interlacedNodesElemIterator();
7088 while ( nodeIt->more() )
7090 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7091 xyz.push_back( SMESH_TNodeXYZ(node) );
7092 nodeList.push_back(node);
7095 int i, nbNodes = element->NbNodes();
7097 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7099 // compute face normal
7100 gp_Vec faceNorm(0,0,0);
7101 xyz.push_back( xyz.front() );
7102 nodeList.push_back( nodeList.front() );
7103 for ( i = 0; i < nbNodes; ++i )
7105 gp_Vec edge1( xyz[i+1], xyz[i]);
7106 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7107 faceNorm += edge1 ^ edge2;
7109 double normSize = faceNorm.Magnitude();
7110 if ( normSize <= tol )
7112 // degenerated face: point is out if it is out of all face edges
7113 for ( i = 0; i < nbNodes; ++i )
7115 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7116 if ( !isOut( &edge, point, tol ))
7121 faceNorm /= normSize;
7123 // check if the point lays on face plane
7124 gp_Vec n2p( xyz[0], point );
7125 if ( fabs( n2p * faceNorm ) > tol )
7126 return true; // not on face plane
7128 // check if point is out of face boundary:
7129 // define it by closest transition of a ray point->infinity through face boundary
7130 // on the face plane.
7131 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7132 // to find intersections of the ray with the boundary.
7134 gp_Vec plnNorm = ray ^ faceNorm;
7135 normSize = plnNorm.Magnitude();
7136 if ( normSize <= tol ) return false; // point coincides with the first node
7137 plnNorm /= normSize;
7138 // for each node of the face, compute its signed distance to the plane
7139 vector<double> dist( nbNodes + 1);
7140 for ( i = 0; i < nbNodes; ++i )
7142 gp_Vec n2p( xyz[i], point );
7143 dist[i] = n2p * plnNorm;
7145 dist.back() = dist.front();
7146 // find the closest intersection
7148 double rClosest, distClosest = 1e100;;
7150 for ( i = 0; i < nbNodes; ++i )
7153 if ( fabs( dist[i]) < tol )
7155 else if ( fabs( dist[i+1]) < tol )
7157 else if ( dist[i] * dist[i+1] < 0 )
7158 r = dist[i] / ( dist[i] - dist[i+1] );
7160 continue; // no intersection
7161 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7162 gp_Vec p2int ( point, pInt);
7163 if ( p2int * ray > -tol ) // right half-space
7165 double intDist = p2int.SquareMagnitude();
7166 if ( intDist < distClosest )
7171 distClosest = intDist;
7176 return true; // no intesections - out
7178 // analyse transition
7179 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7180 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7181 gp_Vec p2int ( point, pClosest );
7182 bool out = (edgeNorm * p2int) < -tol;
7183 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7186 // ray pass through a face node; analyze transition through an adjacent edge
7187 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7188 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7189 gp_Vec edgeAdjacent( p1, p2 );
7190 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7191 bool out2 = (edgeNorm2 * p2int) < -tol;
7193 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7194 return covexCorner ? (out || out2) : (out && out2);
7196 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7198 // point is out of edge if it is NOT ON any straight part of edge
7199 // (we consider quadratic edge as being composed of two straight parts)
7200 for ( i = 1; i < nbNodes; ++i )
7202 gp_Vec edge( xyz[i-1], xyz[i]);
7203 gp_Vec n1p ( xyz[i-1], point);
7204 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7207 gp_Vec n2p( xyz[i], point );
7208 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7210 return false; // point is ON this part
7214 // Node or 0D element -------------------------------------------------------------------------
7216 gp_Vec n2p ( xyz[0], point );
7217 return n2p.Magnitude() <= tol;
7222 //=======================================================================
7223 //function : SimplifyFace
7225 //=======================================================================
7226 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7227 vector<const SMDS_MeshNode *>& poly_nodes,
7228 vector<int>& quantities) const
7230 int nbNodes = faceNodes.size();
7235 set<const SMDS_MeshNode*> nodeSet;
7237 // get simple seq of nodes
7238 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7239 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7240 int iSimple = 0, nbUnique = 0;
7242 simpleNodes[iSimple++] = faceNodes[0];
7244 for (int iCur = 1; iCur < nbNodes; iCur++) {
7245 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7246 simpleNodes[iSimple++] = faceNodes[iCur];
7247 if (nodeSet.insert( faceNodes[iCur] ).second)
7251 int nbSimple = iSimple;
7252 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7262 bool foundLoop = (nbSimple > nbUnique);
7265 set<const SMDS_MeshNode*> loopSet;
7266 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7267 const SMDS_MeshNode* n = simpleNodes[iSimple];
7268 if (!loopSet.insert( n ).second) {
7272 int iC = 0, curLast = iSimple;
7273 for (; iC < curLast; iC++) {
7274 if (simpleNodes[iC] == n) break;
7276 int loopLen = curLast - iC;
7278 // create sub-element
7280 quantities.push_back(loopLen);
7281 for (; iC < curLast; iC++) {
7282 poly_nodes.push_back(simpleNodes[iC]);
7285 // shift the rest nodes (place from the first loop position)
7286 for (iC = curLast + 1; iC < nbSimple; iC++) {
7287 simpleNodes[iC - loopLen] = simpleNodes[iC];
7289 nbSimple -= loopLen;
7292 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7293 } // while (foundLoop)
7297 quantities.push_back(iSimple);
7298 for (int i = 0; i < iSimple; i++)
7299 poly_nodes.push_back(simpleNodes[i]);
7305 //=======================================================================
7306 //function : MergeNodes
7307 //purpose : In each group, the cdr of nodes are substituted by the first one
7309 //=======================================================================
7311 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7313 MESSAGE("MergeNodes");
7314 myLastCreatedElems.Clear();
7315 myLastCreatedNodes.Clear();
7317 SMESHDS_Mesh* aMesh = GetMeshDS();
7319 TNodeNodeMap nodeNodeMap; // node to replace - new node
7320 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7321 list< int > rmElemIds, rmNodeIds;
7323 // Fill nodeNodeMap and elems
7325 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7326 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7327 list<const SMDS_MeshNode*>& nodes = *grIt;
7328 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7329 const SMDS_MeshNode* nToKeep = *nIt;
7330 //MESSAGE("node to keep " << nToKeep->GetID());
7331 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7332 const SMDS_MeshNode* nToRemove = *nIt;
7333 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7334 if ( nToRemove != nToKeep ) {
7335 //MESSAGE(" node to remove " << nToRemove->GetID());
7336 rmNodeIds.push_back( nToRemove->GetID() );
7337 AddToSameGroups( nToKeep, nToRemove, aMesh );
7340 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7341 while ( invElemIt->more() ) {
7342 const SMDS_MeshElement* elem = invElemIt->next();
7347 // Change element nodes or remove an element
7349 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7350 for ( ; eIt != elems.end(); eIt++ ) {
7351 const SMDS_MeshElement* elem = *eIt;
7352 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7353 int nbNodes = elem->NbNodes();
7354 int aShapeId = FindShape( elem );
7356 set<const SMDS_MeshNode*> nodeSet;
7357 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7358 int iUnique = 0, iCur = 0, nbRepl = 0;
7359 vector<int> iRepl( nbNodes );
7361 // get new seq of nodes
7362 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7363 while ( itN->more() ) {
7364 const SMDS_MeshNode* n =
7365 static_cast<const SMDS_MeshNode*>( itN->next() );
7367 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7368 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7370 // BUG 0020185: begin
7372 bool stopRecur = false;
7373 set<const SMDS_MeshNode*> nodesRecur;
7374 nodesRecur.insert(n);
7375 while (!stopRecur) {
7376 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7377 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7378 n = (*nnIt_i).second;
7379 if (!nodesRecur.insert(n).second) {
7380 // error: recursive dependancy
7389 iRepl[ nbRepl++ ] = iCur;
7391 curNodes[ iCur ] = n;
7392 bool isUnique = nodeSet.insert( n ).second;
7394 uniqueNodes[ iUnique++ ] = n;
7395 if ( nbRepl && iRepl[ nbRepl-1 ] == iCur )
7396 --nbRepl; // n do not stick to a node of the elem
7401 // Analyse element topology after replacement
7404 int nbUniqueNodes = nodeSet.size();
7405 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7406 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7407 // Polygons and Polyhedral volumes
7408 if (elem->IsPoly()) {
7410 if (elem->GetType() == SMDSAbs_Face) {
7412 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7414 for (; inode < nbNodes; inode++) {
7415 face_nodes[inode] = curNodes[inode];
7418 vector<const SMDS_MeshNode *> polygons_nodes;
7419 vector<int> quantities;
7420 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7423 for (int iface = 0; iface < nbNew; iface++) {
7424 int nbNodes = quantities[iface];
7425 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7426 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7427 poly_nodes[ii] = polygons_nodes[inode];
7429 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7430 myLastCreatedElems.Append(newElem);
7432 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7435 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7436 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7437 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7439 if (nbNew > 0) quid = nbNew - 1;
7440 vector<int> newquant(quantities.begin()+quid, quantities.end());
7441 const SMDS_MeshElement* newElem = 0;
7442 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7443 myLastCreatedElems.Append(newElem);
7444 if ( aShapeId && newElem )
7445 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7446 rmElemIds.push_back(elem->GetID());
7449 rmElemIds.push_back(elem->GetID());
7453 else if (elem->GetType() == SMDSAbs_Volume) {
7454 // Polyhedral volume
7455 if (nbUniqueNodes < 4) {
7456 rmElemIds.push_back(elem->GetID());
7459 // each face has to be analyzed in order to check volume validity
7460 const SMDS_VtkVolume* aPolyedre =
7461 dynamic_cast<const SMDS_VtkVolume*>( elem );
7463 int nbFaces = aPolyedre->NbFaces();
7465 vector<const SMDS_MeshNode *> poly_nodes;
7466 vector<int> quantities;
7468 for (int iface = 1; iface <= nbFaces; iface++) {
7469 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7470 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7472 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7473 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7474 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7475 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7476 faceNode = (*nnIt).second;
7478 faceNodes[inode - 1] = faceNode;
7481 SimplifyFace(faceNodes, poly_nodes, quantities);
7484 if (quantities.size() > 3) {
7485 // to be done: remove coincident faces
7488 if (quantities.size() > 3)
7490 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7491 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7492 const SMDS_MeshElement* newElem = 0;
7493 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7494 myLastCreatedElems.Append(newElem);
7495 if ( aShapeId && newElem )
7496 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7497 rmElemIds.push_back(elem->GetID());
7501 rmElemIds.push_back(elem->GetID());
7512 // TODO not all the possible cases are solved. Find something more generic?
7513 switch ( nbNodes ) {
7514 case 2: ///////////////////////////////////// EDGE
7515 isOk = false; break;
7516 case 3: ///////////////////////////////////// TRIANGLE
7517 isOk = false; break;
7519 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7521 else { //////////////////////////////////// QUADRANGLE
7522 if ( nbUniqueNodes < 3 )
7524 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7525 isOk = false; // opposite nodes stick
7526 //MESSAGE("isOk " << isOk);
7529 case 6: ///////////////////////////////////// PENTAHEDRON
7530 if ( nbUniqueNodes == 4 ) {
7531 // ---------------------------------> tetrahedron
7533 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7534 // all top nodes stick: reverse a bottom
7535 uniqueNodes[ 0 ] = curNodes [ 1 ];
7536 uniqueNodes[ 1 ] = curNodes [ 0 ];
7538 else if (nbRepl == 3 &&
7539 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7540 // all bottom nodes stick: set a top before
7541 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7542 uniqueNodes[ 0 ] = curNodes [ 3 ];
7543 uniqueNodes[ 1 ] = curNodes [ 4 ];
7544 uniqueNodes[ 2 ] = curNodes [ 5 ];
7546 else if (nbRepl == 4 &&
7547 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7548 // a lateral face turns into a line: reverse a bottom
7549 uniqueNodes[ 0 ] = curNodes [ 1 ];
7550 uniqueNodes[ 1 ] = curNodes [ 0 ];
7555 else if ( nbUniqueNodes == 5 ) {
7556 // PENTAHEDRON --------------------> 2 tetrahedrons
7557 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7558 // a bottom node sticks with a linked top one
7560 SMDS_MeshElement* newElem =
7561 aMesh->AddVolume(curNodes[ 3 ],
7564 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7565 myLastCreatedElems.Append(newElem);
7567 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7568 // 2. : reverse a bottom
7569 uniqueNodes[ 0 ] = curNodes [ 1 ];
7570 uniqueNodes[ 1 ] = curNodes [ 0 ];
7580 if(elem->IsQuadratic()) { // Quadratic quadrangle
7592 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7595 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7597 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7598 uniqueNodes[0] = curNodes[0];
7599 uniqueNodes[1] = curNodes[2];
7600 uniqueNodes[2] = curNodes[3];
7601 uniqueNodes[3] = curNodes[5];
7602 uniqueNodes[4] = curNodes[6];
7603 uniqueNodes[5] = curNodes[7];
7606 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7607 uniqueNodes[0] = curNodes[0];
7608 uniqueNodes[1] = curNodes[1];
7609 uniqueNodes[2] = curNodes[2];
7610 uniqueNodes[3] = curNodes[4];
7611 uniqueNodes[4] = curNodes[5];
7612 uniqueNodes[5] = curNodes[6];
7615 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7616 uniqueNodes[0] = curNodes[1];
7617 uniqueNodes[1] = curNodes[2];
7618 uniqueNodes[2] = curNodes[3];
7619 uniqueNodes[3] = curNodes[5];
7620 uniqueNodes[4] = curNodes[6];
7621 uniqueNodes[5] = curNodes[0];
7624 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7625 uniqueNodes[0] = curNodes[0];
7626 uniqueNodes[1] = curNodes[1];
7627 uniqueNodes[2] = curNodes[3];
7628 uniqueNodes[3] = curNodes[4];
7629 uniqueNodes[4] = curNodes[6];
7630 uniqueNodes[5] = curNodes[7];
7633 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7634 uniqueNodes[0] = curNodes[0];
7635 uniqueNodes[1] = curNodes[2];
7636 uniqueNodes[2] = curNodes[3];
7637 uniqueNodes[3] = curNodes[1];
7638 uniqueNodes[4] = curNodes[6];
7639 uniqueNodes[5] = curNodes[7];
7642 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7643 uniqueNodes[0] = curNodes[0];
7644 uniqueNodes[1] = curNodes[1];
7645 uniqueNodes[2] = curNodes[2];
7646 uniqueNodes[3] = curNodes[4];
7647 uniqueNodes[4] = curNodes[5];
7648 uniqueNodes[5] = curNodes[7];
7651 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7652 uniqueNodes[0] = curNodes[0];
7653 uniqueNodes[1] = curNodes[1];
7654 uniqueNodes[2] = curNodes[3];
7655 uniqueNodes[3] = curNodes[4];
7656 uniqueNodes[4] = curNodes[2];
7657 uniqueNodes[5] = curNodes[7];
7660 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7661 uniqueNodes[0] = curNodes[0];
7662 uniqueNodes[1] = curNodes[1];
7663 uniqueNodes[2] = curNodes[2];
7664 uniqueNodes[3] = curNodes[4];
7665 uniqueNodes[4] = curNodes[5];
7666 uniqueNodes[5] = curNodes[3];
7671 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7674 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7678 //////////////////////////////////// HEXAHEDRON
7680 SMDS_VolumeTool hexa (elem);
7681 hexa.SetExternalNormal();
7682 if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
7683 //////////////////////// HEX ---> 1 tetrahedron
7684 for ( int iFace = 0; iFace < 6; iFace++ ) {
7685 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7686 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7687 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7688 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7689 // one face turns into a point ...
7690 int iOppFace = hexa.GetOppFaceIndex( iFace );
7691 ind = hexa.GetFaceNodesIndices( iOppFace );
7693 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7694 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7697 if ( nbStick == 1 ) {
7698 // ... and the opposite one - into a triangle.
7700 ind = hexa.GetFaceNodesIndices( iFace );
7701 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7708 else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
7709 //////////////////////// HEX ---> 1 prism
7710 int nbTria = 0, iTria[3];
7711 const int *ind; // indices of face nodes
7712 // look for triangular faces
7713 for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
7714 ind = hexa.GetFaceNodesIndices( iFace );
7715 TIDSortedNodeSet faceNodes;
7716 for ( iCur = 0; iCur < 4; iCur++ )
7717 faceNodes.insert( curNodes[ind[iCur]] );
7718 if ( faceNodes.size() == 3 )
7719 iTria[ nbTria++ ] = iFace;
7721 // check if triangles are opposite
7722 if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
7725 // set nodes of the bottom triangle
7726 ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
7728 for ( iCur = 0; iCur < 4; iCur++ )
7729 if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
7730 indB.push_back( ind[iCur] );
7731 if ( !hexa.IsForward() )
7732 std::swap( indB[0], indB[2] );
7733 for ( iCur = 0; iCur < 3; iCur++ )
7734 uniqueNodes[ iCur ] = curNodes[indB[iCur]];
7735 // set nodes of the top triangle
7736 const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
7737 for ( iCur = 0; iCur < 3; ++iCur )
7738 for ( int j = 0; j < 4; ++j )
7739 if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
7741 uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
7747 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7748 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7749 for ( int iFace = 0; iFace < 6; iFace++ ) {
7750 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7751 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7752 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7753 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7754 // one face turns into a point ...
7755 int iOppFace = hexa.GetOppFaceIndex( iFace );
7756 ind = hexa.GetFaceNodesIndices( iOppFace );
7758 iUnique = 2; // reverse a tetrahedron 1 bottom
7759 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7760 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7762 else if ( iUnique >= 0 )
7763 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7765 if ( nbStick == 0 ) {
7766 // ... and the opposite one is a quadrangle
7768 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7769 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7772 SMDS_MeshElement* newElem =
7773 aMesh->AddVolume(curNodes[ind[ 0 ]],
7776 curNodes[indTop[ 0 ]]);
7777 myLastCreatedElems.Append(newElem);
7779 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7786 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7787 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7788 // find indices of quad and tri faces
7789 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7790 for ( iFace = 0; iFace < 6; iFace++ ) {
7791 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7793 for ( iCur = 0; iCur < 4; iCur++ )
7794 nodeSet.insert( curNodes[ind[ iCur ]] );
7795 nbUniqueNodes = nodeSet.size();
7796 if ( nbUniqueNodes == 3 )
7797 iTriFace[ nbTri++ ] = iFace;
7798 else if ( nbUniqueNodes == 4 )
7799 iQuadFace[ nbQuad++ ] = iFace;
7801 if (nbQuad == 2 && nbTri == 4 &&
7802 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7803 // 2 opposite quadrangles stuck with a diagonal;
7804 // sample groups of merged indices: (0-4)(2-6)
7805 // --------------------------------------------> 2 tetrahedrons
7806 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7807 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7808 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7809 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7810 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7811 // stuck with 0-2 diagonal
7819 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7820 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7821 // stuck with 1-3 diagonal
7833 uniqueNodes[ 0 ] = curNodes [ i0 ];
7834 uniqueNodes[ 1 ] = curNodes [ i1d ];
7835 uniqueNodes[ 2 ] = curNodes [ i3d ];
7836 uniqueNodes[ 3 ] = curNodes [ i0t ];
7839 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7843 myLastCreatedElems.Append(newElem);
7845 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7848 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7849 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7850 // --------------------------------------------> prism
7851 // find 2 opposite triangles
7853 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7854 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7855 // find indices of kept and replaced nodes
7856 // and fill unique nodes of 2 opposite triangles
7857 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7858 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7859 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7860 // fill unique nodes
7863 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7864 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7865 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7867 // iCur of a linked node of the opposite face (make normals co-directed):
7868 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7869 // check that correspondent corners of triangles are linked
7870 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7873 uniqueNodes[ iUnique ] = n;
7874 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7883 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7886 MESSAGE("MergeNodes() removes hexahedron "<< elem);
7893 } // switch ( nbNodes )
7895 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7897 if ( isOk ) { // the elem remains valid after sticking nodes
7898 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7900 // Change nodes of polyedre
7901 const SMDS_VtkVolume* aPolyedre =
7902 dynamic_cast<const SMDS_VtkVolume*>( elem );
7904 int nbFaces = aPolyedre->NbFaces();
7906 vector<const SMDS_MeshNode *> poly_nodes;
7907 vector<int> quantities (nbFaces);
7909 for (int iface = 1; iface <= nbFaces; iface++) {
7910 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7911 quantities[iface - 1] = nbFaceNodes;
7913 for (inode = 1; inode <= nbFaceNodes; inode++) {
7914 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7916 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7917 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7918 curNode = (*nnIt).second;
7920 poly_nodes.push_back(curNode);
7923 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7926 else // replace non-polyhedron elements
7928 const SMDSAbs_ElementType etyp = elem->GetType();
7929 const int elemId = elem->GetID();
7930 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
7931 uniqueNodes.resize(nbUniqueNodes);
7933 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7935 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7936 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7937 if ( sm && newElem )
7938 sm->AddElement( newElem );
7939 if ( elem != newElem )
7940 ReplaceElemInGroups( elem, newElem, aMesh );
7944 // Remove invalid regular element or invalid polygon
7945 rmElemIds.push_back( elem->GetID() );
7948 } // loop on elements
7950 // Remove bad elements, then equal nodes (order important)
7952 Remove( rmElemIds, false );
7953 Remove( rmNodeIds, true );
7958 // ========================================================
7959 // class : SortableElement
7960 // purpose : allow sorting elements basing on their nodes
7961 // ========================================================
7962 class SortableElement : public set <const SMDS_MeshElement*>
7966 SortableElement( const SMDS_MeshElement* theElem )
7969 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7970 while ( nodeIt->more() )
7971 this->insert( nodeIt->next() );
7974 const SMDS_MeshElement* Get() const
7977 void Set(const SMDS_MeshElement* e) const
7982 mutable const SMDS_MeshElement* myElem;
7985 //=======================================================================
7986 //function : FindEqualElements
7987 //purpose : Return list of group of elements built on the same nodes.
7988 // Search among theElements or in the whole mesh if theElements is empty
7989 //=======================================================================
7990 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7991 TListOfListOfElementsID & theGroupsOfElementsID)
7993 myLastCreatedElems.Clear();
7994 myLastCreatedNodes.Clear();
7996 typedef set<const SMDS_MeshElement*> TElemsSet;
7997 typedef map< SortableElement, int > TMapOfNodeSet;
7998 typedef list<int> TGroupOfElems;
8001 if ( theElements.empty() )
8002 { // get all elements in the mesh
8003 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
8004 while ( eIt->more() )
8005 elems.insert( elems.end(), eIt->next());
8008 elems = theElements;
8010 vector< TGroupOfElems > arrayOfGroups;
8011 TGroupOfElems groupOfElems;
8012 TMapOfNodeSet mapOfNodeSet;
8014 TElemsSet::iterator elemIt = elems.begin();
8015 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
8016 const SMDS_MeshElement* curElem = *elemIt;
8017 SortableElement SE(curElem);
8020 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
8021 if( !(pp.second) ) {
8022 TMapOfNodeSet::iterator& itSE = pp.first;
8023 ind = (*itSE).second;
8024 arrayOfGroups[ind].push_back(curElem->GetID());
8027 groupOfElems.clear();
8028 groupOfElems.push_back(curElem->GetID());
8029 arrayOfGroups.push_back(groupOfElems);
8034 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8035 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8036 groupOfElems = *groupIt;
8037 if ( groupOfElems.size() > 1 ) {
8038 groupOfElems.sort();
8039 theGroupsOfElementsID.push_back(groupOfElems);
8044 //=======================================================================
8045 //function : MergeElements
8046 //purpose : In each given group, substitute all elements by the first one.
8047 //=======================================================================
8049 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8051 myLastCreatedElems.Clear();
8052 myLastCreatedNodes.Clear();
8054 typedef list<int> TListOfIDs;
8055 TListOfIDs rmElemIds; // IDs of elems to remove
8057 SMESHDS_Mesh* aMesh = GetMeshDS();
8059 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8060 while ( groupsIt != theGroupsOfElementsID.end() ) {
8061 TListOfIDs& aGroupOfElemID = *groupsIt;
8062 aGroupOfElemID.sort();
8063 int elemIDToKeep = aGroupOfElemID.front();
8064 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8065 aGroupOfElemID.pop_front();
8066 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8067 while ( idIt != aGroupOfElemID.end() ) {
8068 int elemIDToRemove = *idIt;
8069 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8070 // add the kept element in groups of removed one (PAL15188)
8071 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8072 rmElemIds.push_back( elemIDToRemove );
8078 Remove( rmElemIds, false );
8081 //=======================================================================
8082 //function : MergeEqualElements
8083 //purpose : Remove all but one of elements built on the same nodes.
8084 //=======================================================================
8086 void SMESH_MeshEditor::MergeEqualElements()
8088 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8089 to merge equal elements in the whole mesh */
8090 TListOfListOfElementsID aGroupsOfElementsID;
8091 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8092 MergeElements(aGroupsOfElementsID);
8095 //=======================================================================
8096 //function : FindFaceInSet
8097 //purpose : Return a face having linked nodes n1 and n2 and which is
8098 // - not in avoidSet,
8099 // - in elemSet provided that !elemSet.empty()
8100 // i1 and i2 optionally returns indices of n1 and n2
8101 //=======================================================================
8103 const SMDS_MeshElement*
8104 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8105 const SMDS_MeshNode* n2,
8106 const TIDSortedElemSet& elemSet,
8107 const TIDSortedElemSet& avoidSet,
8113 const SMDS_MeshElement* face = 0;
8115 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8116 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8117 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8119 //MESSAGE("in while ( invElemIt->more() && !face )");
8120 const SMDS_MeshElement* elem = invElemIt->next();
8121 if (avoidSet.count( elem ))
8123 if ( !elemSet.empty() && !elemSet.count( elem ))
8126 i1 = elem->GetNodeIndex( n1 );
8127 // find a n2 linked to n1
8128 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8129 for ( int di = -1; di < 2 && !face; di += 2 )
8131 i2 = (i1+di+nbN) % nbN;
8132 if ( elem->GetNode( i2 ) == n2 )
8135 if ( !face && elem->IsQuadratic())
8137 // analysis for quadratic elements using all nodes
8138 const SMDS_VtkFace* F =
8139 dynamic_cast<const SMDS_VtkFace*>(elem);
8140 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8141 // use special nodes iterator
8142 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8143 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8144 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8146 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8147 if ( n1 == prevN && n2 == n )
8151 else if ( n2 == prevN && n1 == n )
8153 face = elem; swap( i1, i2 );
8159 if ( n1ind ) *n1ind = i1;
8160 if ( n2ind ) *n2ind = i2;
8164 //=======================================================================
8165 //function : findAdjacentFace
8167 //=======================================================================
8169 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8170 const SMDS_MeshNode* n2,
8171 const SMDS_MeshElement* elem)
8173 TIDSortedElemSet elemSet, avoidSet;
8175 avoidSet.insert ( elem );
8176 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8179 //=======================================================================
8180 //function : FindFreeBorder
8182 //=======================================================================
8184 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8186 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8187 const SMDS_MeshNode* theSecondNode,
8188 const SMDS_MeshNode* theLastNode,
8189 list< const SMDS_MeshNode* > & theNodes,
8190 list< const SMDS_MeshElement* >& theFaces)
8192 if ( !theFirstNode || !theSecondNode )
8194 // find border face between theFirstNode and theSecondNode
8195 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8199 theFaces.push_back( curElem );
8200 theNodes.push_back( theFirstNode );
8201 theNodes.push_back( theSecondNode );
8203 //vector<const SMDS_MeshNode*> nodes;
8204 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8205 TIDSortedElemSet foundElems;
8206 bool needTheLast = ( theLastNode != 0 );
8208 while ( nStart != theLastNode ) {
8209 if ( nStart == theFirstNode )
8210 return !needTheLast;
8212 // find all free border faces sharing form nStart
8214 list< const SMDS_MeshElement* > curElemList;
8215 list< const SMDS_MeshNode* > nStartList;
8216 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8217 while ( invElemIt->more() ) {
8218 const SMDS_MeshElement* e = invElemIt->next();
8219 if ( e == curElem || foundElems.insert( e ).second ) {
8221 int iNode = 0, nbNodes = e->NbNodes();
8222 //const SMDS_MeshNode* nodes[nbNodes+1];
8223 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8225 if(e->IsQuadratic()) {
8226 const SMDS_VtkFace* F =
8227 dynamic_cast<const SMDS_VtkFace*>(e);
8228 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8229 // use special nodes iterator
8230 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8231 while( anIter->more() ) {
8232 nodes[ iNode++ ] = cast2Node(anIter->next());
8236 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8237 while ( nIt->more() )
8238 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8240 nodes[ iNode ] = nodes[ 0 ];
8242 for ( iNode = 0; iNode < nbNodes; iNode++ )
8243 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8244 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8245 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8247 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8248 curElemList.push_back( e );
8252 // analyse the found
8254 int nbNewBorders = curElemList.size();
8255 if ( nbNewBorders == 0 ) {
8256 // no free border furthermore
8257 return !needTheLast;
8259 else if ( nbNewBorders == 1 ) {
8260 // one more element found
8262 nStart = nStartList.front();
8263 curElem = curElemList.front();
8264 theFaces.push_back( curElem );
8265 theNodes.push_back( nStart );
8268 // several continuations found
8269 list< const SMDS_MeshElement* >::iterator curElemIt;
8270 list< const SMDS_MeshNode* >::iterator nStartIt;
8271 // check if one of them reached the last node
8272 if ( needTheLast ) {
8273 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8274 curElemIt!= curElemList.end();
8275 curElemIt++, nStartIt++ )
8276 if ( *nStartIt == theLastNode ) {
8277 theFaces.push_back( *curElemIt );
8278 theNodes.push_back( *nStartIt );
8282 // find the best free border by the continuations
8283 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8284 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8285 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8286 curElemIt!= curElemList.end();
8287 curElemIt++, nStartIt++ )
8289 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8290 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8291 // find one more free border
8292 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8296 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8297 // choice: clear a worse one
8298 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8299 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8300 contNodes[ iWorse ].clear();
8301 contFaces[ iWorse ].clear();
8304 if ( contNodes[0].empty() && contNodes[1].empty() )
8307 // append the best free border
8308 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8309 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8310 theNodes.pop_back(); // remove nIgnore
8311 theNodes.pop_back(); // remove nStart
8312 theFaces.pop_back(); // remove curElem
8313 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8314 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8315 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8316 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8319 } // several continuations found
8320 } // while ( nStart != theLastNode )
8325 //=======================================================================
8326 //function : CheckFreeBorderNodes
8327 //purpose : Return true if the tree nodes are on a free border
8328 //=======================================================================
8330 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8331 const SMDS_MeshNode* theNode2,
8332 const SMDS_MeshNode* theNode3)
8334 list< const SMDS_MeshNode* > nodes;
8335 list< const SMDS_MeshElement* > faces;
8336 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8339 //=======================================================================
8340 //function : SewFreeBorder
8342 //=======================================================================
8344 SMESH_MeshEditor::Sew_Error
8345 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8346 const SMDS_MeshNode* theBordSecondNode,
8347 const SMDS_MeshNode* theBordLastNode,
8348 const SMDS_MeshNode* theSideFirstNode,
8349 const SMDS_MeshNode* theSideSecondNode,
8350 const SMDS_MeshNode* theSideThirdNode,
8351 const bool theSideIsFreeBorder,
8352 const bool toCreatePolygons,
8353 const bool toCreatePolyedrs)
8355 myLastCreatedElems.Clear();
8356 myLastCreatedNodes.Clear();
8358 MESSAGE("::SewFreeBorder()");
8359 Sew_Error aResult = SEW_OK;
8361 // ====================================
8362 // find side nodes and elements
8363 // ====================================
8365 list< const SMDS_MeshNode* > nSide[ 2 ];
8366 list< const SMDS_MeshElement* > eSide[ 2 ];
8367 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8368 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8372 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8373 nSide[0], eSide[0])) {
8374 MESSAGE(" Free Border 1 not found " );
8375 aResult = SEW_BORDER1_NOT_FOUND;
8377 if (theSideIsFreeBorder) {
8380 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8381 nSide[1], eSide[1])) {
8382 MESSAGE(" Free Border 2 not found " );
8383 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8386 if ( aResult != SEW_OK )
8389 if (!theSideIsFreeBorder) {
8393 // -------------------------------------------------------------------------
8395 // 1. If nodes to merge are not coincident, move nodes of the free border
8396 // from the coord sys defined by the direction from the first to last
8397 // nodes of the border to the correspondent sys of the side 2
8398 // 2. On the side 2, find the links most co-directed with the correspondent
8399 // links of the free border
8400 // -------------------------------------------------------------------------
8402 // 1. Since sewing may break if there are volumes to split on the side 2,
8403 // we wont move nodes but just compute new coordinates for them
8404 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8405 TNodeXYZMap nBordXYZ;
8406 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8407 list< const SMDS_MeshNode* >::iterator nBordIt;
8409 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8410 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8411 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8412 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8413 double tol2 = 1.e-8;
8414 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8415 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8416 // Need node movement.
8418 // find X and Z axes to create trsf
8419 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8421 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8423 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8426 gp_Ax3 toBordAx( Pb1, Zb, X );
8427 gp_Ax3 fromSideAx( Ps1, Zs, X );
8428 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8430 gp_Trsf toBordSys, fromSide2Sys;
8431 toBordSys.SetTransformation( toBordAx );
8432 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8433 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8436 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8437 const SMDS_MeshNode* n = *nBordIt;
8438 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8439 toBordSys.Transforms( xyz );
8440 fromSide2Sys.Transforms( xyz );
8441 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8445 // just insert nodes XYZ in the nBordXYZ map
8446 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8447 const SMDS_MeshNode* n = *nBordIt;
8448 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8452 // 2. On the side 2, find the links most co-directed with the correspondent
8453 // links of the free border
8455 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8456 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8457 sideNodes.push_back( theSideFirstNode );
8459 bool hasVolumes = false;
8460 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8461 set<long> foundSideLinkIDs, checkedLinkIDs;
8462 SMDS_VolumeTool volume;
8463 //const SMDS_MeshNode* faceNodes[ 4 ];
8465 const SMDS_MeshNode* sideNode;
8466 const SMDS_MeshElement* sideElem;
8467 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8468 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8469 nBordIt = bordNodes.begin();
8471 // border node position and border link direction to compare with
8472 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8473 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8474 // choose next side node by link direction or by closeness to
8475 // the current border node:
8476 bool searchByDir = ( *nBordIt != theBordLastNode );
8478 // find the next node on the Side 2
8480 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8482 checkedLinkIDs.clear();
8483 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8485 // loop on inverse elements of current node (prevSideNode) on the Side 2
8486 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8487 while ( invElemIt->more() )
8489 const SMDS_MeshElement* elem = invElemIt->next();
8490 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8491 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8492 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8493 bool isVolume = volume.Set( elem );
8494 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8495 if ( isVolume ) // --volume
8497 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8498 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8499 if(elem->IsQuadratic()) {
8500 const SMDS_VtkFace* F =
8501 dynamic_cast<const SMDS_VtkFace*>(elem);
8502 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8503 // use special nodes iterator
8504 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8505 while( anIter->more() ) {
8506 nodes[ iNode ] = cast2Node(anIter->next());
8507 if ( nodes[ iNode++ ] == prevSideNode )
8508 iPrevNode = iNode - 1;
8512 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8513 while ( nIt->more() ) {
8514 nodes[ iNode ] = cast2Node( nIt->next() );
8515 if ( nodes[ iNode++ ] == prevSideNode )
8516 iPrevNode = iNode - 1;
8519 // there are 2 links to check
8524 // loop on links, to be precise, on the second node of links
8525 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8526 const SMDS_MeshNode* n = nodes[ iNode ];
8528 if ( !volume.IsLinked( n, prevSideNode ))
8532 if ( iNode ) // a node before prevSideNode
8533 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8534 else // a node after prevSideNode
8535 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8537 // check if this link was already used
8538 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8539 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8540 if (!isJustChecked &&
8541 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8543 // test a link geometrically
8544 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8545 bool linkIsBetter = false;
8546 double dot = 0.0, dist = 0.0;
8547 if ( searchByDir ) { // choose most co-directed link
8548 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8549 linkIsBetter = ( dot > maxDot );
8551 else { // choose link with the node closest to bordPos
8552 dist = ( nextXYZ - bordPos ).SquareModulus();
8553 linkIsBetter = ( dist < minDist );
8555 if ( linkIsBetter ) {
8564 } // loop on inverse elements of prevSideNode
8567 MESSAGE(" Cant find path by links of the Side 2 ");
8568 return SEW_BAD_SIDE_NODES;
8570 sideNodes.push_back( sideNode );
8571 sideElems.push_back( sideElem );
8572 foundSideLinkIDs.insert ( linkID );
8573 prevSideNode = sideNode;
8575 if ( *nBordIt == theBordLastNode )
8576 searchByDir = false;
8578 // find the next border link to compare with
8579 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8580 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8581 // move to next border node if sideNode is before forward border node (bordPos)
8582 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8583 prevBordNode = *nBordIt;
8585 bordPos = nBordXYZ[ *nBordIt ];
8586 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8587 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8591 while ( sideNode != theSideSecondNode );
8593 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8594 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8595 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8597 } // end nodes search on the side 2
8599 // ============================
8600 // sew the border to the side 2
8601 // ============================
8603 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8604 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8606 TListOfListOfNodes nodeGroupsToMerge;
8607 if ( nbNodes[0] == nbNodes[1] ||
8608 ( theSideIsFreeBorder && !theSideThirdNode)) {
8610 // all nodes are to be merged
8612 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8613 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8614 nIt[0]++, nIt[1]++ )
8616 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8617 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8618 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8623 // insert new nodes into the border and the side to get equal nb of segments
8625 // get normalized parameters of nodes on the borders
8626 //double param[ 2 ][ maxNbNodes ];
8628 param[0] = new double [ maxNbNodes ];
8629 param[1] = new double [ maxNbNodes ];
8631 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8632 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8633 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8634 const SMDS_MeshNode* nPrev = *nIt;
8635 double bordLength = 0;
8636 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8637 const SMDS_MeshNode* nCur = *nIt;
8638 gp_XYZ segment (nCur->X() - nPrev->X(),
8639 nCur->Y() - nPrev->Y(),
8640 nCur->Z() - nPrev->Z());
8641 double segmentLen = segment.Modulus();
8642 bordLength += segmentLen;
8643 param[ iBord ][ iNode ] = bordLength;
8646 // normalize within [0,1]
8647 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8648 param[ iBord ][ iNode ] /= bordLength;
8652 // loop on border segments
8653 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8654 int i[ 2 ] = { 0, 0 };
8655 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8656 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8658 TElemOfNodeListMap insertMap;
8659 TElemOfNodeListMap::iterator insertMapIt;
8661 // key: elem to insert nodes into
8662 // value: 2 nodes to insert between + nodes to be inserted
8664 bool next[ 2 ] = { false, false };
8666 // find min adjacent segment length after sewing
8667 double nextParam = 10., prevParam = 0;
8668 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8669 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8670 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8671 if ( i[ iBord ] > 0 )
8672 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8674 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8675 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8676 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8678 // choose to insert or to merge nodes
8679 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8680 if ( Abs( du ) <= minSegLen * 0.2 ) {
8683 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8684 const SMDS_MeshNode* n0 = *nIt[0];
8685 const SMDS_MeshNode* n1 = *nIt[1];
8686 nodeGroupsToMerge.back().push_back( n1 );
8687 nodeGroupsToMerge.back().push_back( n0 );
8688 // position of node of the border changes due to merge
8689 param[ 0 ][ i[0] ] += du;
8690 // move n1 for the sake of elem shape evaluation during insertion.
8691 // n1 will be removed by MergeNodes() anyway
8692 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8693 next[0] = next[1] = true;
8698 int intoBord = ( du < 0 ) ? 0 : 1;
8699 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8700 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8701 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8702 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8703 if ( intoBord == 1 ) {
8704 // move node of the border to be on a link of elem of the side
8705 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8706 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8707 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8708 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8709 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8711 insertMapIt = insertMap.find( elem );
8712 bool notFound = ( insertMapIt == insertMap.end() );
8713 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8715 // insert into another link of the same element:
8716 // 1. perform insertion into the other link of the elem
8717 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8718 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8719 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8720 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8721 // 2. perform insertion into the link of adjacent faces
8723 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8725 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8729 if (toCreatePolyedrs) {
8730 // perform insertion into the links of adjacent volumes
8731 UpdateVolumes(n12, n22, nodeList);
8733 // 3. find an element appeared on n1 and n2 after the insertion
8734 insertMap.erase( elem );
8735 elem = findAdjacentFace( n1, n2, 0 );
8737 if ( notFound || otherLink ) {
8738 // add element and nodes of the side into the insertMap
8739 insertMapIt = insertMap.insert
8740 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8741 (*insertMapIt).second.push_back( n1 );
8742 (*insertMapIt).second.push_back( n2 );
8744 // add node to be inserted into elem
8745 (*insertMapIt).second.push_back( nIns );
8746 next[ 1 - intoBord ] = true;
8749 // go to the next segment
8750 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8751 if ( next[ iBord ] ) {
8752 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8754 nPrev[ iBord ] = *nIt[ iBord ];
8755 nIt[ iBord ]++; i[ iBord ]++;
8759 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8761 // perform insertion of nodes into elements
8763 for (insertMapIt = insertMap.begin();
8764 insertMapIt != insertMap.end();
8767 const SMDS_MeshElement* elem = (*insertMapIt).first;
8768 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8769 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8770 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8772 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8774 if ( !theSideIsFreeBorder ) {
8775 // look for and insert nodes into the faces adjacent to elem
8777 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8779 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8784 if (toCreatePolyedrs) {
8785 // perform insertion into the links of adjacent volumes
8786 UpdateVolumes(n1, n2, nodeList);
8792 } // end: insert new nodes
8794 MergeNodes ( nodeGroupsToMerge );
8799 //=======================================================================
8800 //function : InsertNodesIntoLink
8801 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8802 // and theBetweenNode2 and split theElement
8803 //=======================================================================
8805 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8806 const SMDS_MeshNode* theBetweenNode1,
8807 const SMDS_MeshNode* theBetweenNode2,
8808 list<const SMDS_MeshNode*>& theNodesToInsert,
8809 const bool toCreatePoly)
8811 if ( theFace->GetType() != SMDSAbs_Face ) return;
8813 // find indices of 2 link nodes and of the rest nodes
8814 int iNode = 0, il1, il2, i3, i4;
8815 il1 = il2 = i3 = i4 = -1;
8816 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8817 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8819 if(theFace->IsQuadratic()) {
8820 const SMDS_VtkFace* F =
8821 dynamic_cast<const SMDS_VtkFace*>(theFace);
8822 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8823 // use special nodes iterator
8824 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8825 while( anIter->more() ) {
8826 const SMDS_MeshNode* n = cast2Node(anIter->next());
8827 if ( n == theBetweenNode1 )
8829 else if ( n == theBetweenNode2 )
8835 nodes[ iNode++ ] = n;
8839 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8840 while ( nodeIt->more() ) {
8841 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8842 if ( n == theBetweenNode1 )
8844 else if ( n == theBetweenNode2 )
8850 nodes[ iNode++ ] = n;
8853 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8856 // arrange link nodes to go one after another regarding the face orientation
8857 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8858 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8863 aNodesToInsert.reverse();
8865 // check that not link nodes of a quadrangles are in good order
8866 int nbFaceNodes = theFace->NbNodes();
8867 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8873 if (toCreatePoly || theFace->IsPoly()) {
8876 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8878 // add nodes of face up to first node of link
8881 if(theFace->IsQuadratic()) {
8882 const SMDS_VtkFace* F =
8883 dynamic_cast<const SMDS_VtkFace*>(theFace);
8884 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8885 // use special nodes iterator
8886 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8887 while( anIter->more() && !isFLN ) {
8888 const SMDS_MeshNode* n = cast2Node(anIter->next());
8889 poly_nodes[iNode++] = n;
8890 if (n == nodes[il1]) {
8894 // add nodes to insert
8895 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8896 for (; nIt != aNodesToInsert.end(); nIt++) {
8897 poly_nodes[iNode++] = *nIt;
8899 // add nodes of face starting from last node of link
8900 while ( anIter->more() ) {
8901 poly_nodes[iNode++] = cast2Node(anIter->next());
8905 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8906 while ( nodeIt->more() && !isFLN ) {
8907 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8908 poly_nodes[iNode++] = n;
8909 if (n == nodes[il1]) {
8913 // add nodes to insert
8914 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8915 for (; nIt != aNodesToInsert.end(); nIt++) {
8916 poly_nodes[iNode++] = *nIt;
8918 // add nodes of face starting from last node of link
8919 while ( nodeIt->more() ) {
8920 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8921 poly_nodes[iNode++] = n;
8925 // edit or replace the face
8926 SMESHDS_Mesh *aMesh = GetMeshDS();
8928 if (theFace->IsPoly()) {
8929 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8932 int aShapeId = FindShape( theFace );
8934 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8935 myLastCreatedElems.Append(newElem);
8936 if ( aShapeId && newElem )
8937 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8939 aMesh->RemoveElement(theFace);
8944 SMESHDS_Mesh *aMesh = GetMeshDS();
8945 if( !theFace->IsQuadratic() ) {
8947 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8948 int nbLinkNodes = 2 + aNodesToInsert.size();
8949 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8950 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8951 linkNodes[ 0 ] = nodes[ il1 ];
8952 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8953 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8954 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8955 linkNodes[ iNode++ ] = *nIt;
8957 // decide how to split a quadrangle: compare possible variants
8958 // and choose which of splits to be a quadrangle
8959 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8960 if ( nbFaceNodes == 3 ) {
8961 iBestQuad = nbSplits;
8964 else if ( nbFaceNodes == 4 ) {
8965 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8966 double aBestRate = DBL_MAX;
8967 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8969 double aBadRate = 0;
8970 // evaluate elements quality
8971 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8972 if ( iSplit == iQuad ) {
8973 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8977 aBadRate += getBadRate( &quad, aCrit );
8980 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8982 nodes[ iSplit < iQuad ? i4 : i3 ]);
8983 aBadRate += getBadRate( &tria, aCrit );
8987 if ( aBadRate < aBestRate ) {
8989 aBestRate = aBadRate;
8994 // create new elements
8995 int aShapeId = FindShape( theFace );
8998 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8999 SMDS_MeshElement* newElem = 0;
9000 if ( iSplit == iBestQuad )
9001 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9006 newElem = aMesh->AddFace (linkNodes[ i1++ ],
9008 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
9009 myLastCreatedElems.Append(newElem);
9010 if ( aShapeId && newElem )
9011 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9014 // change nodes of theFace
9015 const SMDS_MeshNode* newNodes[ 4 ];
9016 newNodes[ 0 ] = linkNodes[ i1 ];
9017 newNodes[ 1 ] = linkNodes[ i2 ];
9018 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
9019 newNodes[ 3 ] = nodes[ i4 ];
9020 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
9021 const SMDS_MeshElement* newElem = 0;
9022 if (iSplit == iBestQuad)
9023 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
9025 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
9026 myLastCreatedElems.Append(newElem);
9027 if ( aShapeId && newElem )
9028 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9029 } // end if(!theFace->IsQuadratic())
9030 else { // theFace is quadratic
9031 // we have to split theFace on simple triangles and one simple quadrangle
9033 int nbshift = tmp*2;
9034 // shift nodes in nodes[] by nbshift
9036 for(i=0; i<nbshift; i++) {
9037 const SMDS_MeshNode* n = nodes[0];
9038 for(j=0; j<nbFaceNodes-1; j++) {
9039 nodes[j] = nodes[j+1];
9041 nodes[nbFaceNodes-1] = n;
9043 il1 = il1 - nbshift;
9044 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9045 // n0 n1 n2 n0 n1 n2
9046 // +-----+-----+ +-----+-----+
9055 // create new elements
9056 int aShapeId = FindShape( theFace );
9059 if(nbFaceNodes==6) { // quadratic triangle
9060 SMDS_MeshElement* newElem =
9061 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9062 myLastCreatedElems.Append(newElem);
9063 if ( aShapeId && newElem )
9064 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9065 if(theFace->IsMediumNode(nodes[il1])) {
9066 // create quadrangle
9067 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9068 myLastCreatedElems.Append(newElem);
9069 if ( aShapeId && newElem )
9070 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9076 // create quadrangle
9077 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9078 myLastCreatedElems.Append(newElem);
9079 if ( aShapeId && newElem )
9080 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9086 else { // nbFaceNodes==8 - quadratic quadrangle
9087 SMDS_MeshElement* newElem =
9088 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9089 myLastCreatedElems.Append(newElem);
9090 if ( aShapeId && newElem )
9091 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9092 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9093 myLastCreatedElems.Append(newElem);
9094 if ( aShapeId && newElem )
9095 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9096 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9097 myLastCreatedElems.Append(newElem);
9098 if ( aShapeId && newElem )
9099 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9100 if(theFace->IsMediumNode(nodes[il1])) {
9101 // create quadrangle
9102 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9103 myLastCreatedElems.Append(newElem);
9104 if ( aShapeId && newElem )
9105 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9111 // create quadrangle
9112 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9113 myLastCreatedElems.Append(newElem);
9114 if ( aShapeId && newElem )
9115 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9121 // create needed triangles using n1,n2,n3 and inserted nodes
9122 int nbn = 2 + aNodesToInsert.size();
9123 //const SMDS_MeshNode* aNodes[nbn];
9124 vector<const SMDS_MeshNode*> aNodes(nbn);
9125 aNodes[0] = nodes[n1];
9126 aNodes[nbn-1] = nodes[n2];
9127 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9128 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9129 aNodes[iNode++] = *nIt;
9131 for(i=1; i<nbn; i++) {
9132 SMDS_MeshElement* newElem =
9133 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9134 myLastCreatedElems.Append(newElem);
9135 if ( aShapeId && newElem )
9136 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9140 aMesh->RemoveElement(theFace);
9143 //=======================================================================
9144 //function : UpdateVolumes
9146 //=======================================================================
9147 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9148 const SMDS_MeshNode* theBetweenNode2,
9149 list<const SMDS_MeshNode*>& theNodesToInsert)
9151 myLastCreatedElems.Clear();
9152 myLastCreatedNodes.Clear();
9154 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9155 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9156 const SMDS_MeshElement* elem = invElemIt->next();
9158 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9159 SMDS_VolumeTool aVolume (elem);
9160 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9163 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9164 int iface, nbFaces = aVolume.NbFaces();
9165 vector<const SMDS_MeshNode *> poly_nodes;
9166 vector<int> quantities (nbFaces);
9168 for (iface = 0; iface < nbFaces; iface++) {
9169 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9170 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9171 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9173 for (int inode = 0; inode < nbFaceNodes; inode++) {
9174 poly_nodes.push_back(faceNodes[inode]);
9176 if (nbInserted == 0) {
9177 if (faceNodes[inode] == theBetweenNode1) {
9178 if (faceNodes[inode + 1] == theBetweenNode2) {
9179 nbInserted = theNodesToInsert.size();
9181 // add nodes to insert
9182 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9183 for (; nIt != theNodesToInsert.end(); nIt++) {
9184 poly_nodes.push_back(*nIt);
9188 else if (faceNodes[inode] == theBetweenNode2) {
9189 if (faceNodes[inode + 1] == theBetweenNode1) {
9190 nbInserted = theNodesToInsert.size();
9192 // add nodes to insert in reversed order
9193 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9195 for (; nIt != theNodesToInsert.begin(); nIt--) {
9196 poly_nodes.push_back(*nIt);
9198 poly_nodes.push_back(*nIt);
9205 quantities[iface] = nbFaceNodes + nbInserted;
9208 // Replace or update the volume
9209 SMESHDS_Mesh *aMesh = GetMeshDS();
9211 if (elem->IsPoly()) {
9212 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9216 int aShapeId = FindShape( elem );
9218 SMDS_MeshElement* newElem =
9219 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9220 myLastCreatedElems.Append(newElem);
9221 if (aShapeId && newElem)
9222 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9224 aMesh->RemoveElement(elem);
9229 //=======================================================================
9231 * \brief Convert elements contained in a submesh to quadratic
9232 * \return int - nb of checked elements
9234 //=======================================================================
9236 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9237 SMESH_MesherHelper& theHelper,
9238 const bool theForce3d)
9241 if( !theSm ) return nbElem;
9243 vector<int> nbNodeInFaces;
9244 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9245 while(ElemItr->more())
9248 const SMDS_MeshElement* elem = ElemItr->next();
9249 if( !elem || elem->IsQuadratic() ) continue;
9251 int id = elem->GetID();
9252 int nbNodes = elem->NbNodes();
9253 SMDSAbs_ElementType aType = elem->GetType();
9255 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9256 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9257 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9259 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9261 const SMDS_MeshElement* NewElem = 0;
9267 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9275 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9278 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9281 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9286 case SMDSAbs_Volume :
9291 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9294 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9297 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9300 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9301 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9304 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9311 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9313 theSm->AddElement( NewElem );
9315 // if (!GetMeshDS()->isCompacted())
9316 // GetMeshDS()->compactMesh();
9320 //=======================================================================
9321 //function : ConvertToQuadratic
9323 //=======================================================================
9324 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9326 SMESHDS_Mesh* meshDS = GetMeshDS();
9328 SMESH_MesherHelper aHelper(*myMesh);
9329 aHelper.SetIsQuadratic( true );
9331 int nbCheckedElems = 0;
9332 if ( myMesh->HasShapeToMesh() )
9334 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9336 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9337 while ( smIt->more() ) {
9338 SMESH_subMesh* sm = smIt->next();
9339 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9340 aHelper.SetSubShape( sm->GetSubShape() );
9341 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9346 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9347 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9349 SMESHDS_SubMesh *smDS = 0;
9350 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9351 while(aEdgeItr->more())
9353 const SMDS_MeshEdge* edge = aEdgeItr->next();
9354 if(edge && !edge->IsQuadratic())
9356 int id = edge->GetID();
9357 //MESSAGE("edge->GetID() " << id);
9358 const SMDS_MeshNode* n1 = edge->GetNode(0);
9359 const SMDS_MeshNode* n2 = edge->GetNode(1);
9361 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9363 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9364 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9367 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9368 while(aFaceItr->more())
9370 const SMDS_MeshFace* face = aFaceItr->next();
9371 if(!face || face->IsQuadratic() ) continue;
9373 int id = face->GetID();
9374 int nbNodes = face->NbNodes();
9375 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9377 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9379 SMDS_MeshFace * NewFace = 0;
9383 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9386 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9389 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9391 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9393 vector<int> nbNodeInFaces;
9394 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9395 while(aVolumeItr->more())
9397 const SMDS_MeshVolume* volume = aVolumeItr->next();
9398 if(!volume || volume->IsQuadratic() ) continue;
9400 int id = volume->GetID();
9401 int nbNodes = volume->NbNodes();
9402 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9403 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9404 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9406 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9408 SMDS_MeshVolume * NewVolume = 0;
9412 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9413 nodes[3], id, theForce3d );
9416 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9417 nodes[3], nodes[4], id, theForce3d);
9420 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9421 nodes[3], nodes[4], nodes[5], id, theForce3d);
9424 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9425 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9428 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9430 ReplaceElemInGroups(volume, NewVolume, meshDS);
9435 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9436 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9437 aHelper.FixQuadraticElements();
9441 //================================================================================
9443 * \brief Makes given elements quadratic
9444 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9445 * \param theElements - elements to make quadratic
9447 //================================================================================
9449 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9450 TIDSortedElemSet& theElements)
9452 if ( theElements.empty() ) return;
9454 // we believe that all theElements are of the same type
9455 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9457 // get all nodes shared by theElements
9458 TIDSortedNodeSet allNodes;
9459 TIDSortedElemSet::iterator eIt = theElements.begin();
9460 for ( ; eIt != theElements.end(); ++eIt )
9461 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9463 // complete theElements with elements of lower dim whose all nodes are in allNodes
9465 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9466 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9467 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9468 for ( ; nIt != allNodes.end(); ++nIt )
9470 const SMDS_MeshNode* n = *nIt;
9471 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9472 while ( invIt->more() )
9474 const SMDS_MeshElement* e = invIt->next();
9475 if ( e->IsQuadratic() )
9477 quadAdjacentElems[ e->GetType() ].insert( e );
9480 if ( e->GetType() >= elemType )
9482 continue; // same type of more complex linear element
9485 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9486 continue; // e is already checked
9490 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9491 while ( nodeIt->more() && allIn )
9492 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9494 theElements.insert(e );
9498 SMESH_MesherHelper helper(*myMesh);
9499 helper.SetIsQuadratic( true );
9501 // add links of quadratic adjacent elements to the helper
9503 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9504 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9505 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9507 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9509 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9510 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9511 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9513 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9515 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9516 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9517 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9519 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9522 // make quadratic elements instead of linear ones
9524 SMESHDS_Mesh* meshDS = GetMeshDS();
9525 SMESHDS_SubMesh* smDS = 0;
9526 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9528 const SMDS_MeshElement* elem = *eIt;
9529 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9532 int id = elem->GetID();
9533 SMDSAbs_ElementType type = elem->GetType();
9534 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9536 if ( !smDS || !smDS->Contains( elem ))
9537 smDS = meshDS->MeshElements( elem->getshapeId() );
9538 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9540 SMDS_MeshElement * newElem = 0;
9541 switch( nodes.size() )
9543 case 4: // cases for most multiple element types go first (for optimization)
9544 if ( type == SMDSAbs_Volume )
9545 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9547 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9550 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9551 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9554 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9557 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9560 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9561 nodes[4], id, theForce3d);
9564 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9565 nodes[4], nodes[5], id, theForce3d);
9569 ReplaceElemInGroups( elem, newElem, meshDS);
9570 if( newElem && smDS )
9571 smDS->AddElement( newElem );
9574 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9575 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9576 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9577 helper.FixQuadraticElements();
9581 //=======================================================================
9583 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9584 * \return int - nb of checked elements
9586 //=======================================================================
9588 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9589 SMDS_ElemIteratorPtr theItr,
9590 const int theShapeID)
9593 SMESHDS_Mesh* meshDS = GetMeshDS();
9595 while( theItr->more() )
9597 const SMDS_MeshElement* elem = theItr->next();
9599 if( elem && elem->IsQuadratic())
9601 int id = elem->GetID();
9602 int nbCornerNodes = elem->NbCornerNodes();
9603 SMDSAbs_ElementType aType = elem->GetType();
9605 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9607 //remove a quadratic element
9608 if ( !theSm || !theSm->Contains( elem ))
9609 theSm = meshDS->MeshElements( elem->getshapeId() );
9610 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9612 // remove medium nodes
9613 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9614 if ( nodes[i]->NbInverseElements() == 0 )
9615 meshDS->RemoveFreeNode( nodes[i], theSm );
9617 // add a linear element
9618 nodes.resize( nbCornerNodes );
9619 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9620 ReplaceElemInGroups(elem, newElem, meshDS);
9621 if( theSm && newElem )
9622 theSm->AddElement( newElem );
9628 //=======================================================================
9629 //function : ConvertFromQuadratic
9631 //=======================================================================
9633 bool SMESH_MeshEditor::ConvertFromQuadratic()
9635 int nbCheckedElems = 0;
9636 if ( myMesh->HasShapeToMesh() )
9638 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9640 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9641 while ( smIt->more() ) {
9642 SMESH_subMesh* sm = smIt->next();
9643 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9644 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9650 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9651 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9653 SMESHDS_SubMesh *aSM = 0;
9654 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9662 //================================================================================
9664 * \brief Return true if all medium nodes of the element are in the node set
9666 //================================================================================
9668 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9670 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9671 if ( !nodeSet.count( elem->GetNode(i) ))
9677 //================================================================================
9679 * \brief Makes given elements linear
9681 //================================================================================
9683 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9685 if ( theElements.empty() ) return;
9687 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9688 set<int> mediumNodeIDs;
9689 TIDSortedElemSet::iterator eIt = theElements.begin();
9690 for ( ; eIt != theElements.end(); ++eIt )
9692 const SMDS_MeshElement* e = *eIt;
9693 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9694 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9697 // replace given elements by linear ones
9698 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9699 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9700 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9702 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9703 // except those elements sharing medium nodes of quadratic element whose medium nodes
9704 // are not all in mediumNodeIDs
9706 // get remaining medium nodes
9707 TIDSortedNodeSet mediumNodes;
9708 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9709 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9710 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9711 mediumNodes.insert( mediumNodes.end(), n );
9713 // find more quadratic elements to convert
9714 TIDSortedElemSet moreElemsToConvert;
9715 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9716 for ( ; nIt != mediumNodes.end(); ++nIt )
9718 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9719 while ( invIt->more() )
9721 const SMDS_MeshElement* e = invIt->next();
9722 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9724 // find a more complex element including e and
9725 // whose medium nodes are not in mediumNodes
9726 bool complexFound = false;
9727 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9729 SMDS_ElemIteratorPtr invIt2 =
9730 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9731 while ( invIt2->more() )
9733 const SMDS_MeshElement* eComplex = invIt2->next();
9734 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9736 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9737 if ( nbCommonNodes == e->NbNodes())
9739 complexFound = true;
9740 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9746 if ( !complexFound )
9747 moreElemsToConvert.insert( e );
9751 elemIt = SMDS_ElemIteratorPtr
9752 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9753 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9756 //=======================================================================
9757 //function : SewSideElements
9759 //=======================================================================
9761 SMESH_MeshEditor::Sew_Error
9762 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9763 TIDSortedElemSet& theSide2,
9764 const SMDS_MeshNode* theFirstNode1,
9765 const SMDS_MeshNode* theFirstNode2,
9766 const SMDS_MeshNode* theSecondNode1,
9767 const SMDS_MeshNode* theSecondNode2)
9769 myLastCreatedElems.Clear();
9770 myLastCreatedNodes.Clear();
9772 MESSAGE ("::::SewSideElements()");
9773 if ( theSide1.size() != theSide2.size() )
9774 return SEW_DIFF_NB_OF_ELEMENTS;
9776 Sew_Error aResult = SEW_OK;
9778 // 1. Build set of faces representing each side
9779 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9780 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9782 // =======================================================================
9783 // 1. Build set of faces representing each side:
9784 // =======================================================================
9785 // a. build set of nodes belonging to faces
9786 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9787 // c. create temporary faces representing side of volumes if correspondent
9788 // face does not exist
9790 SMESHDS_Mesh* aMesh = GetMeshDS();
9791 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9792 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9793 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9794 set<const SMDS_MeshElement*> volSet1, volSet2;
9795 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9796 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9797 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9798 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9799 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9800 int iSide, iFace, iNode;
9802 list<const SMDS_MeshElement* > tempFaceList;
9803 for ( iSide = 0; iSide < 2; iSide++ ) {
9804 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9805 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9806 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9807 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9808 set<const SMDS_MeshElement*>::iterator vIt;
9809 TIDSortedElemSet::iterator eIt;
9810 set<const SMDS_MeshNode*>::iterator nIt;
9812 // check that given nodes belong to given elements
9813 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9814 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9815 int firstIndex = -1, secondIndex = -1;
9816 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9817 const SMDS_MeshElement* elem = *eIt;
9818 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9819 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9820 if ( firstIndex > -1 && secondIndex > -1 ) break;
9822 if ( firstIndex < 0 || secondIndex < 0 ) {
9823 // we can simply return until temporary faces created
9824 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9827 // -----------------------------------------------------------
9828 // 1a. Collect nodes of existing faces
9829 // and build set of face nodes in order to detect missing
9830 // faces corresponding to sides of volumes
9831 // -----------------------------------------------------------
9833 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9835 // loop on the given element of a side
9836 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9837 //const SMDS_MeshElement* elem = *eIt;
9838 const SMDS_MeshElement* elem = *eIt;
9839 if ( elem->GetType() == SMDSAbs_Face ) {
9840 faceSet->insert( elem );
9841 set <const SMDS_MeshNode*> faceNodeSet;
9842 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9843 while ( nodeIt->more() ) {
9844 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9845 nodeSet->insert( n );
9846 faceNodeSet.insert( n );
9848 setOfFaceNodeSet.insert( faceNodeSet );
9850 else if ( elem->GetType() == SMDSAbs_Volume )
9851 volSet->insert( elem );
9853 // ------------------------------------------------------------------------------
9854 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9855 // ------------------------------------------------------------------------------
9857 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9858 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9859 while ( fIt->more() ) { // loop on faces sharing a node
9860 const SMDS_MeshElement* f = fIt->next();
9861 if ( faceSet->find( f ) == faceSet->end() ) {
9862 // check if all nodes are in nodeSet and
9863 // complete setOfFaceNodeSet if they are
9864 set <const SMDS_MeshNode*> faceNodeSet;
9865 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9866 bool allInSet = true;
9867 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9868 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9869 if ( nodeSet->find( n ) == nodeSet->end() )
9872 faceNodeSet.insert( n );
9875 faceSet->insert( f );
9876 setOfFaceNodeSet.insert( faceNodeSet );
9882 // -------------------------------------------------------------------------
9883 // 1c. Create temporary faces representing sides of volumes if correspondent
9884 // face does not exist
9885 // -------------------------------------------------------------------------
9887 if ( !volSet->empty() ) {
9888 //int nodeSetSize = nodeSet->size();
9890 // loop on given volumes
9891 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9892 SMDS_VolumeTool vol (*vIt);
9893 // loop on volume faces: find free faces
9894 // --------------------------------------
9895 list<const SMDS_MeshElement* > freeFaceList;
9896 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9897 if ( !vol.IsFreeFace( iFace ))
9899 // check if there is already a face with same nodes in a face set
9900 const SMDS_MeshElement* aFreeFace = 0;
9901 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9902 int nbNodes = vol.NbFaceNodes( iFace );
9903 set <const SMDS_MeshNode*> faceNodeSet;
9904 vol.GetFaceNodes( iFace, faceNodeSet );
9905 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9907 // no such a face is given but it still can exist, check it
9908 if ( nbNodes == 3 ) {
9909 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9911 else if ( nbNodes == 4 ) {
9912 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9915 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9916 aFreeFace = aMesh->FindFace(poly_nodes);
9920 // create a temporary face
9921 if ( nbNodes == 3 ) {
9922 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9923 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9925 else if ( nbNodes == 4 ) {
9926 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9927 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9930 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9931 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9932 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9936 freeFaceList.push_back( aFreeFace );
9937 tempFaceList.push_back( aFreeFace );
9940 } // loop on faces of a volume
9942 // choose one of several free faces
9943 // --------------------------------------
9944 if ( freeFaceList.size() > 1 ) {
9945 // choose a face having max nb of nodes shared by other elems of a side
9946 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9947 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9948 while ( fIt != freeFaceList.end() ) { // loop on free faces
9949 int nbSharedNodes = 0;
9950 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9951 while ( nodeIt->more() ) { // loop on free face nodes
9952 const SMDS_MeshNode* n =
9953 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9954 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9955 while ( invElemIt->more() ) {
9956 const SMDS_MeshElement* e = invElemIt->next();
9957 if ( faceSet->find( e ) != faceSet->end() )
9959 if ( elemSet->find( e ) != elemSet->end() )
9963 if ( nbSharedNodes >= maxNbNodes ) {
9964 maxNbNodes = nbSharedNodes;
9968 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9970 if ( freeFaceList.size() > 1 )
9972 // could not choose one face, use another way
9973 // choose a face most close to the bary center of the opposite side
9974 gp_XYZ aBC( 0., 0., 0. );
9975 set <const SMDS_MeshNode*> addedNodes;
9976 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9977 eIt = elemSet2->begin();
9978 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9979 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9980 while ( nodeIt->more() ) { // loop on free face nodes
9981 const SMDS_MeshNode* n =
9982 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9983 if ( addedNodes.insert( n ).second )
9984 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9987 aBC /= addedNodes.size();
9988 double minDist = DBL_MAX;
9989 fIt = freeFaceList.begin();
9990 while ( fIt != freeFaceList.end() ) { // loop on free faces
9992 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9993 while ( nodeIt->more() ) { // loop on free face nodes
9994 const SMDS_MeshNode* n =
9995 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9996 gp_XYZ p( n->X(),n->Y(),n->Z() );
9997 dist += ( aBC - p ).SquareModulus();
9999 if ( dist < minDist ) {
10001 freeFaceList.erase( freeFaceList.begin(), fIt++ );
10004 fIt = freeFaceList.erase( fIt++ );
10007 } // choose one of several free faces of a volume
10009 if ( freeFaceList.size() == 1 ) {
10010 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
10011 faceSet->insert( aFreeFace );
10012 // complete a node set with nodes of a found free face
10013 // for ( iNode = 0; iNode < ; iNode++ )
10014 // nodeSet->insert( fNodes[ iNode ] );
10017 } // loop on volumes of a side
10019 // // complete a set of faces if new nodes in a nodeSet appeared
10020 // // ----------------------------------------------------------
10021 // if ( nodeSetSize != nodeSet->size() ) {
10022 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
10023 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
10024 // while ( fIt->more() ) { // loop on faces sharing a node
10025 // const SMDS_MeshElement* f = fIt->next();
10026 // if ( faceSet->find( f ) == faceSet->end() ) {
10027 // // check if all nodes are in nodeSet and
10028 // // complete setOfFaceNodeSet if they are
10029 // set <const SMDS_MeshNode*> faceNodeSet;
10030 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
10031 // bool allInSet = true;
10032 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
10033 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10034 // if ( nodeSet->find( n ) == nodeSet->end() )
10035 // allInSet = false;
10037 // faceNodeSet.insert( n );
10039 // if ( allInSet ) {
10040 // faceSet->insert( f );
10041 // setOfFaceNodeSet.insert( faceNodeSet );
10047 } // Create temporary faces, if there are volumes given
10050 if ( faceSet1.size() != faceSet2.size() ) {
10051 // delete temporary faces: they are in reverseElements of actual nodes
10052 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10053 // while ( tmpFaceIt->more() )
10054 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10055 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10056 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10057 // aMesh->RemoveElement(*tmpFaceIt);
10058 MESSAGE("Diff nb of faces");
10059 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10062 // ============================================================
10063 // 2. Find nodes to merge:
10064 // bind a node to remove to a node to put instead
10065 // ============================================================
10067 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10068 if ( theFirstNode1 != theFirstNode2 )
10069 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10070 if ( theSecondNode1 != theSecondNode2 )
10071 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10073 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10074 set< long > linkIdSet; // links to process
10075 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10077 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10078 list< NLink > linkList[2];
10079 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10080 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10081 // loop on links in linkList; find faces by links and append links
10082 // of the found faces to linkList
10083 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10084 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10085 NLink link[] = { *linkIt[0], *linkIt[1] };
10086 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10087 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10090 // by links, find faces in the face sets,
10091 // and find indices of link nodes in the found faces;
10092 // in a face set, there is only one or no face sharing a link
10093 // ---------------------------------------------------------------
10095 const SMDS_MeshElement* face[] = { 0, 0 };
10096 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10097 vector<const SMDS_MeshNode*> fnodes1(9);
10098 vector<const SMDS_MeshNode*> fnodes2(9);
10099 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10100 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10101 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10102 int iLinkNode[2][2];
10103 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10104 const SMDS_MeshNode* n1 = link[iSide].first;
10105 const SMDS_MeshNode* n2 = link[iSide].second;
10106 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10107 set< const SMDS_MeshElement* > fMap;
10108 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10109 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10110 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10111 while ( fIt->more() ) { // loop on faces sharing a node
10112 const SMDS_MeshElement* f = fIt->next();
10113 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10114 ! fMap.insert( f ).second ) // f encounters twice
10116 if ( face[ iSide ] ) {
10117 MESSAGE( "2 faces per link " );
10118 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10122 faceSet->erase( f );
10123 // get face nodes and find ones of a link
10128 fnodes1.resize(f->NbNodes()+1);
10129 notLinkNodes1.resize(f->NbNodes()-2);
10132 fnodes2.resize(f->NbNodes()+1);
10133 notLinkNodes2.resize(f->NbNodes()-2);
10136 if(!f->IsQuadratic()) {
10137 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10138 while ( nIt->more() ) {
10139 const SMDS_MeshNode* n =
10140 static_cast<const SMDS_MeshNode*>( nIt->next() );
10142 iLinkNode[ iSide ][ 0 ] = iNode;
10144 else if ( n == n2 ) {
10145 iLinkNode[ iSide ][ 1 ] = iNode;
10147 //else if ( notLinkNodes[ iSide ][ 0 ] )
10148 // notLinkNodes[ iSide ][ 1 ] = n;
10150 // notLinkNodes[ iSide ][ 0 ] = n;
10154 notLinkNodes1[nbl] = n;
10155 //notLinkNodes1.push_back(n);
10157 notLinkNodes2[nbl] = n;
10158 //notLinkNodes2.push_back(n);
10160 //faceNodes[ iSide ][ iNode++ ] = n;
10162 fnodes1[iNode++] = n;
10165 fnodes2[iNode++] = n;
10169 else { // f->IsQuadratic()
10170 const SMDS_VtkFace* F =
10171 dynamic_cast<const SMDS_VtkFace*>(f);
10172 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10173 // use special nodes iterator
10174 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10175 while ( anIter->more() ) {
10176 const SMDS_MeshNode* n =
10177 static_cast<const SMDS_MeshNode*>( anIter->next() );
10179 iLinkNode[ iSide ][ 0 ] = iNode;
10181 else if ( n == n2 ) {
10182 iLinkNode[ iSide ][ 1 ] = iNode;
10187 notLinkNodes1[nbl] = n;
10190 notLinkNodes2[nbl] = n;
10194 fnodes1[iNode++] = n;
10197 fnodes2[iNode++] = n;
10201 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10203 fnodes1[iNode] = fnodes1[0];
10206 fnodes2[iNode] = fnodes1[0];
10213 // check similarity of elements of the sides
10214 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10215 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10216 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10217 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10220 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10222 break; // do not return because it s necessary to remove tmp faces
10225 // set nodes to merge
10226 // -------------------
10228 if ( face[0] && face[1] ) {
10229 int nbNodes = face[0]->NbNodes();
10230 if ( nbNodes != face[1]->NbNodes() ) {
10231 MESSAGE("Diff nb of face nodes");
10232 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10233 break; // do not return because it s necessary to remove tmp faces
10235 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10236 if ( nbNodes == 3 ) {
10237 //nReplaceMap.insert( TNodeNodeMap::value_type
10238 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10239 nReplaceMap.insert( TNodeNodeMap::value_type
10240 ( notLinkNodes1[0], notLinkNodes2[0] ));
10243 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10244 // analyse link orientation in faces
10245 int i1 = iLinkNode[ iSide ][ 0 ];
10246 int i2 = iLinkNode[ iSide ][ 1 ];
10247 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10248 // if notLinkNodes are the first and the last ones, then
10249 // their order does not correspond to the link orientation
10250 if (( i1 == 1 && i2 == 2 ) ||
10251 ( i1 == 2 && i2 == 1 ))
10252 reverse[ iSide ] = !reverse[ iSide ];
10254 if ( reverse[0] == reverse[1] ) {
10255 //nReplaceMap.insert( TNodeNodeMap::value_type
10256 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10257 //nReplaceMap.insert( TNodeNodeMap::value_type
10258 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10259 for(int nn=0; nn<nbNodes-2; nn++) {
10260 nReplaceMap.insert( TNodeNodeMap::value_type
10261 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10265 //nReplaceMap.insert( TNodeNodeMap::value_type
10266 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10267 //nReplaceMap.insert( TNodeNodeMap::value_type
10268 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10269 for(int nn=0; nn<nbNodes-2; nn++) {
10270 nReplaceMap.insert( TNodeNodeMap::value_type
10271 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10276 // add other links of the faces to linkList
10277 // -----------------------------------------
10279 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10280 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10281 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10282 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10283 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10284 if ( !iter_isnew.second ) { // already in a set: no need to process
10285 linkIdSet.erase( iter_isnew.first );
10287 else // new in set == encountered for the first time: add
10289 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10290 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10291 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10292 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10293 linkList[0].push_back ( NLink( n1, n2 ));
10294 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10298 } // loop on link lists
10300 if ( aResult == SEW_OK &&
10301 ( linkIt[0] != linkList[0].end() ||
10302 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10303 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10304 " " << (faceSetPtr[1]->empty()));
10305 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10308 // ====================================================================
10309 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10310 // ====================================================================
10312 // delete temporary faces: they are in reverseElements of actual nodes
10313 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10314 // while ( tmpFaceIt->more() )
10315 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10316 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10317 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10318 // aMesh->RemoveElement(*tmpFaceIt);
10320 if ( aResult != SEW_OK)
10323 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10324 // loop on nodes replacement map
10325 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10326 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10327 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10328 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10329 nodeIDsToRemove.push_back( nToRemove->GetID() );
10330 // loop on elements sharing nToRemove
10331 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10332 while ( invElemIt->more() ) {
10333 const SMDS_MeshElement* e = invElemIt->next();
10334 // get a new suite of nodes: make replacement
10335 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10336 vector< const SMDS_MeshNode*> nodes( nbNodes );
10337 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10338 while ( nIt->more() ) {
10339 const SMDS_MeshNode* n =
10340 static_cast<const SMDS_MeshNode*>( nIt->next() );
10341 nnIt = nReplaceMap.find( n );
10342 if ( nnIt != nReplaceMap.end() ) {
10344 n = (*nnIt).second;
10348 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10349 // elemIDsToRemove.push_back( e->GetID() );
10353 SMDSAbs_ElementType etyp = e->GetType();
10354 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10357 myLastCreatedElems.Append(newElem);
10358 AddToSameGroups(newElem, e, aMesh);
10359 int aShapeId = e->getshapeId();
10362 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10365 aMesh->RemoveElement(e);
10370 Remove( nodeIDsToRemove, true );
10375 //================================================================================
10377 * \brief Find corresponding nodes in two sets of faces
10378 * \param theSide1 - first face set
10379 * \param theSide2 - second first face
10380 * \param theFirstNode1 - a boundary node of set 1
10381 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10382 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10383 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10384 * \param nReplaceMap - output map of corresponding nodes
10385 * \return bool - is a success or not
10387 //================================================================================
10390 //#define DEBUG_MATCHING_NODES
10393 SMESH_MeshEditor::Sew_Error
10394 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10395 set<const SMDS_MeshElement*>& theSide2,
10396 const SMDS_MeshNode* theFirstNode1,
10397 const SMDS_MeshNode* theFirstNode2,
10398 const SMDS_MeshNode* theSecondNode1,
10399 const SMDS_MeshNode* theSecondNode2,
10400 TNodeNodeMap & nReplaceMap)
10402 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10404 nReplaceMap.clear();
10405 if ( theFirstNode1 != theFirstNode2 )
10406 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10407 if ( theSecondNode1 != theSecondNode2 )
10408 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10410 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10411 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10413 list< NLink > linkList[2];
10414 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10415 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10417 // loop on links in linkList; find faces by links and append links
10418 // of the found faces to linkList
10419 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10420 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10421 NLink link[] = { *linkIt[0], *linkIt[1] };
10422 if ( linkSet.find( link[0] ) == linkSet.end() )
10425 // by links, find faces in the face sets,
10426 // and find indices of link nodes in the found faces;
10427 // in a face set, there is only one or no face sharing a link
10428 // ---------------------------------------------------------------
10430 const SMDS_MeshElement* face[] = { 0, 0 };
10431 list<const SMDS_MeshNode*> notLinkNodes[2];
10432 //bool reverse[] = { false, false }; // order of notLinkNodes
10434 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10436 const SMDS_MeshNode* n1 = link[iSide].first;
10437 const SMDS_MeshNode* n2 = link[iSide].second;
10438 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10439 set< const SMDS_MeshElement* > facesOfNode1;
10440 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10442 // during a loop of the first node, we find all faces around n1,
10443 // during a loop of the second node, we find one face sharing both n1 and n2
10444 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10445 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10446 while ( fIt->more() ) { // loop on faces sharing a node
10447 const SMDS_MeshElement* f = fIt->next();
10448 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10449 ! facesOfNode1.insert( f ).second ) // f encounters twice
10451 if ( face[ iSide ] ) {
10452 MESSAGE( "2 faces per link " );
10453 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10456 faceSet->erase( f );
10458 // get not link nodes
10459 int nbN = f->NbNodes();
10460 if ( f->IsQuadratic() )
10462 nbNodes[ iSide ] = nbN;
10463 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10464 int i1 = f->GetNodeIndex( n1 );
10465 int i2 = f->GetNodeIndex( n2 );
10466 int iEnd = nbN, iBeg = -1, iDelta = 1;
10467 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10469 std::swap( iEnd, iBeg ); iDelta = -1;
10474 if ( i == iEnd ) i = iBeg + iDelta;
10475 if ( i == i1 ) break;
10476 nodes.push_back ( f->GetNode( i ) );
10482 // check similarity of elements of the sides
10483 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10484 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10485 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10486 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10489 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10493 // set nodes to merge
10494 // -------------------
10496 if ( face[0] && face[1] ) {
10497 if ( nbNodes[0] != nbNodes[1] ) {
10498 MESSAGE("Diff nb of face nodes");
10499 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10501 #ifdef DEBUG_MATCHING_NODES
10502 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10503 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10504 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10506 int nbN = nbNodes[0];
10508 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10509 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10510 for ( int i = 0 ; i < nbN - 2; ++i ) {
10511 #ifdef DEBUG_MATCHING_NODES
10512 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10514 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10518 // add other links of the face 1 to linkList
10519 // -----------------------------------------
10521 const SMDS_MeshElement* f0 = face[0];
10522 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10523 for ( int i = 0; i < nbN; i++ )
10525 const SMDS_MeshNode* n2 = f0->GetNode( i );
10526 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10527 linkSet.insert( SMESH_TLink( n1, n2 ));
10528 if ( !iter_isnew.second ) { // already in a set: no need to process
10529 linkSet.erase( iter_isnew.first );
10531 else // new in set == encountered for the first time: add
10533 #ifdef DEBUG_MATCHING_NODES
10534 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10535 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10537 linkList[0].push_back ( NLink( n1, n2 ));
10538 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10543 } // loop on link lists
10548 //================================================================================
10550 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10551 \param theElems - the list of elements (edges or faces) to be replicated
10552 The nodes for duplication could be found from these elements
10553 \param theNodesNot - list of nodes to NOT replicate
10554 \param theAffectedElems - the list of elements (cells and edges) to which the
10555 replicated nodes should be associated to.
10556 \return TRUE if operation has been completed successfully, FALSE otherwise
10558 //================================================================================
10560 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10561 const TIDSortedElemSet& theNodesNot,
10562 const TIDSortedElemSet& theAffectedElems )
10564 myLastCreatedElems.Clear();
10565 myLastCreatedNodes.Clear();
10567 if ( theElems.size() == 0 )
10570 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10575 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10576 // duplicate elements and nodes
10577 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10578 // replce nodes by duplications
10579 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10583 //================================================================================
10585 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10586 \param theMeshDS - mesh instance
10587 \param theElems - the elements replicated or modified (nodes should be changed)
10588 \param theNodesNot - nodes to NOT replicate
10589 \param theNodeNodeMap - relation of old node to new created node
10590 \param theIsDoubleElem - flag os to replicate element or modify
10591 \return TRUE if operation has been completed successfully, FALSE otherwise
10593 //================================================================================
10595 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10596 const TIDSortedElemSet& theElems,
10597 const TIDSortedElemSet& theNodesNot,
10598 std::map< const SMDS_MeshNode*,
10599 const SMDS_MeshNode* >& theNodeNodeMap,
10600 const bool theIsDoubleElem )
10602 MESSAGE("doubleNodes");
10603 // iterate on through element and duplicate them (by nodes duplication)
10605 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10606 for ( ; elemItr != theElems.end(); ++elemItr )
10608 const SMDS_MeshElement* anElem = *elemItr;
10612 bool isDuplicate = false;
10613 // duplicate nodes to duplicate element
10614 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10615 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10617 while ( anIter->more() )
10620 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10621 SMDS_MeshNode* aNewNode = aCurrNode;
10622 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10623 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10624 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10627 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10628 theNodeNodeMap[ aCurrNode ] = aNewNode;
10629 myLastCreatedNodes.Append( aNewNode );
10631 isDuplicate |= (aCurrNode != aNewNode);
10632 newNodes[ ind++ ] = aNewNode;
10634 if ( !isDuplicate )
10637 if ( theIsDoubleElem )
10638 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10641 MESSAGE("ChangeElementNodes");
10642 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10649 //================================================================================
10651 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10652 \param theNodes - identifiers of nodes to be doubled
10653 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10654 nodes. If list of element identifiers is empty then nodes are doubled but
10655 they not assigned to elements
10656 \return TRUE if operation has been completed successfully, FALSE otherwise
10658 //================================================================================
10660 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10661 const std::list< int >& theListOfModifiedElems )
10663 MESSAGE("DoubleNodes");
10664 myLastCreatedElems.Clear();
10665 myLastCreatedNodes.Clear();
10667 if ( theListOfNodes.size() == 0 )
10670 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10674 // iterate through nodes and duplicate them
10676 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10678 std::list< int >::const_iterator aNodeIter;
10679 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10681 int aCurr = *aNodeIter;
10682 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10688 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10691 anOldNodeToNewNode[ aNode ] = aNewNode;
10692 myLastCreatedNodes.Append( aNewNode );
10696 // Create map of new nodes for modified elements
10698 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10700 std::list< int >::const_iterator anElemIter;
10701 for ( anElemIter = theListOfModifiedElems.begin();
10702 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10704 int aCurr = *anElemIter;
10705 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10709 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10711 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10713 while ( anIter->more() )
10715 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10716 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10718 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10719 aNodeArr[ ind++ ] = aNewNode;
10722 aNodeArr[ ind++ ] = aCurrNode;
10724 anElemToNodes[ anElem ] = aNodeArr;
10727 // Change nodes of elements
10729 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10730 anElemToNodesIter = anElemToNodes.begin();
10731 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10733 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10734 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10737 MESSAGE("ChangeElementNodes");
10738 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10747 //================================================================================
10749 \brief Check if element located inside shape
10750 \return TRUE if IN or ON shape, FALSE otherwise
10752 //================================================================================
10754 template<class Classifier>
10755 bool isInside(const SMDS_MeshElement* theElem,
10756 Classifier& theClassifier,
10757 const double theTol)
10759 gp_XYZ centerXYZ (0, 0, 0);
10760 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10761 while (aNodeItr->more())
10762 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10764 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10765 theClassifier.Perform(aPnt, theTol);
10766 TopAbs_State aState = theClassifier.State();
10767 return (aState == TopAbs_IN || aState == TopAbs_ON );
10770 //================================================================================
10772 * \brief Classifier of the 3D point on the TopoDS_Face
10773 * with interaface suitable for isInside()
10775 //================================================================================
10777 struct _FaceClassifier
10779 Extrema_ExtPS _extremum;
10780 BRepAdaptor_Surface _surface;
10781 TopAbs_State _state;
10783 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10785 _extremum.Initialize( _surface,
10786 _surface.FirstUParameter(), _surface.LastUParameter(),
10787 _surface.FirstVParameter(), _surface.LastVParameter(),
10788 _surface.Tolerance(), _surface.Tolerance() );
10790 void Perform(const gp_Pnt& aPnt, double theTol)
10792 _state = TopAbs_OUT;
10793 _extremum.Perform(aPnt);
10794 if ( _extremum.IsDone() )
10795 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10796 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10798 TopAbs_State State() const
10805 //================================================================================
10807 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10808 \param theElems - group of of elements (edges or faces) to be replicated
10809 \param theNodesNot - group of nodes not to replicate
10810 \param theShape - shape to detect affected elements (element which geometric center
10811 located on or inside shape).
10812 The replicated nodes should be associated to affected elements.
10813 \return TRUE if operation has been completed successfully, FALSE otherwise
10815 //================================================================================
10817 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10818 const TIDSortedElemSet& theNodesNot,
10819 const TopoDS_Shape& theShape )
10821 if ( theShape.IsNull() )
10824 const double aTol = Precision::Confusion();
10825 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10826 auto_ptr<_FaceClassifier> aFaceClassifier;
10827 if ( theShape.ShapeType() == TopAbs_SOLID )
10829 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10830 bsc3d->PerformInfinitePoint(aTol);
10832 else if (theShape.ShapeType() == TopAbs_FACE )
10834 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10837 // iterates on indicated elements and get elements by back references from their nodes
10838 TIDSortedElemSet anAffected;
10839 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10840 for ( ; elemItr != theElems.end(); ++elemItr )
10842 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10846 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10847 while ( nodeItr->more() )
10849 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10850 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10852 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10853 while ( backElemItr->more() )
10855 const SMDS_MeshElement* curElem = backElemItr->next();
10856 if ( curElem && theElems.find(curElem) == theElems.end() &&
10858 isInside( curElem, *bsc3d, aTol ) :
10859 isInside( curElem, *aFaceClassifier, aTol )))
10860 anAffected.insert( curElem );
10864 return DoubleNodes( theElems, theNodesNot, anAffected );
10868 * \brief compute an oriented angle between two planes defined by four points.
10869 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10870 * @param p0 base of the rotation axe
10871 * @param p1 extremity of the rotation axe
10872 * @param g1 belongs to the first plane
10873 * @param g2 belongs to the second plane
10875 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10877 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10878 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10879 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10880 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10881 gp_Vec vref(p0, p1);
10884 gp_Vec n1 = vref.Crossed(v1);
10885 gp_Vec n2 = vref.Crossed(v2);
10886 return n2.AngleWithRef(n1, vref);
10890 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10891 * The list of groups must describe a partition of the mesh volumes.
10892 * The nodes of the internal faces at the boundaries of the groups are doubled.
10893 * In option, the internal faces are replaced by flat elements.
10894 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10895 * The flat elements are stored in groups of volumes.
10896 * @param theElems - list of groups of volumes, where a group of volume is a set of
10897 * SMDS_MeshElements sorted by Id.
10898 * @param createJointElems - if TRUE, create the elements
10899 * @return TRUE if operation has been completed successfully, FALSE otherwise
10901 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10902 bool createJointElems)
10904 MESSAGE("----------------------------------------------");
10905 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10906 MESSAGE("----------------------------------------------");
10908 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10909 meshDS->BuildDownWardConnectivity(true);
10911 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10913 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10914 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10915 // build the list of nodes shared by 2 or more domains, with their domain indexes
10917 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10918 std::map<int,int>celldom; // cell vtkId --> domain
10919 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10920 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10921 faceDomains.clear();
10923 cellDomains.clear();
10924 nodeDomains.clear();
10925 std::map<int,int> emptyMap;
10926 std::set<int> emptySet;
10929 for (int idom = 0; idom < theElems.size(); idom++)
10932 // --- build a map (face to duplicate --> volume to modify)
10933 // with all the faces shared by 2 domains (group of elements)
10934 // and corresponding volume of this domain, for each shared face.
10935 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10937 const TIDSortedElemSet& domain = theElems[idom];
10938 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10939 for (; elemItr != domain.end(); ++elemItr)
10941 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10944 int vtkId = anElem->getVtkId();
10945 int neighborsVtkIds[NBMAXNEIGHBORS];
10946 int downIds[NBMAXNEIGHBORS];
10947 unsigned char downTypes[NBMAXNEIGHBORS];
10948 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10949 for (int n = 0; n < nbNeighbors; n++)
10951 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10952 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10953 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10955 DownIdType face(downIds[n], downTypes[n]);
10956 if (!faceDomains.count(face))
10957 faceDomains[face] = emptyMap; // create an empty entry for face
10958 if (!faceDomains[face].count(idom))
10960 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10961 celldom[vtkId] = idom;
10968 //MESSAGE("Number of shared faces " << faceDomains.size());
10969 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10971 // --- explore the shared faces domain by domain,
10972 // explore the nodes of the face and see if they belong to a cell in the domain,
10973 // which has only a node or an edge on the border (not a shared face)
10975 for (int idomain = 0; idomain < theElems.size(); idomain++)
10977 const TIDSortedElemSet& domain = theElems[idomain];
10978 itface = faceDomains.begin();
10979 for (; itface != faceDomains.end(); ++itface)
10981 std::map<int, int> domvol = itface->second;
10982 if (!domvol.count(idomain))
10984 DownIdType face = itface->first;
10985 //MESSAGE(" --- face " << face.cellId);
10986 std::set<int> oldNodes;
10988 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10989 std::set<int>::iterator itn = oldNodes.begin();
10990 for (; itn != oldNodes.end(); ++itn)
10993 //MESSAGE(" node " << oldId);
10994 std::set<int> cells;
10996 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10997 for (int i=0; i<l.ncells; i++)
10999 int vtkId = l.cells[i];
11000 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
11001 if (!domain.count(anElem))
11003 int vtkType = grid->GetCellType(vtkId);
11004 int downId = grid->CellIdToDownId(vtkId);
11007 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
11008 continue; // not OK at this stage of the algorithm:
11009 //no cells created after BuildDownWardConnectivity
11011 DownIdType aCell(downId, vtkType);
11012 if (celldom.count(vtkId))
11014 cellDomains[aCell][idomain] = vtkId;
11015 celldom[vtkId] = idomain;
11021 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
11022 // for each shared face, get the nodes
11023 // for each node, for each domain of the face, create a clone of the node
11025 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
11026 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
11027 // the value is the ordered domain ids. (more than 4 domains not taken into account)
11029 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
11030 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
11032 for (int idomain = 0; idomain < theElems.size(); idomain++)
11034 itface = faceDomains.begin();
11035 for (; itface != faceDomains.end(); ++itface)
11037 std::map<int, int> domvol = itface->second;
11038 if (!domvol.count(idomain))
11040 DownIdType face = itface->first;
11041 //MESSAGE(" --- face " << face.cellId);
11042 std::set<int> oldNodes;
11044 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11045 bool isMultipleDetected = false;
11046 std::set<int>::iterator itn = oldNodes.begin();
11047 for (; itn != oldNodes.end(); ++itn)
11050 //MESSAGE(" node " << oldId);
11051 if (!nodeDomains.count(oldId))
11052 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11053 if (nodeDomains[oldId].empty())
11054 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11055 std::map<int, int>::iterator itdom = domvol.begin();
11056 for (; itdom != domvol.end(); ++itdom)
11058 int idom = itdom->first;
11059 //MESSAGE(" domain " << idom);
11060 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11062 if (nodeDomains[oldId].size() >= 2) // a multiple node
11064 vector<int> orderedDoms;
11065 //MESSAGE("multiple node " << oldId);
11066 isMultipleDetected =true;
11067 if (mutipleNodes.count(oldId))
11068 orderedDoms = mutipleNodes[oldId];
11071 map<int,int>::iterator it = nodeDomains[oldId].begin();
11072 for (; it != nodeDomains[oldId].end(); ++it)
11073 orderedDoms.push_back(it->first);
11075 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11076 //stringstream txt;
11077 //for (int i=0; i<orderedDoms.size(); i++)
11078 // txt << orderedDoms[i] << " ";
11079 //MESSAGE("orderedDoms " << txt.str());
11080 mutipleNodes[oldId] = orderedDoms;
11082 double *coords = grid->GetPoint(oldId);
11083 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11084 int newId = newNode->getVtkId();
11085 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11086 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11088 if (nodeDomains[oldId].size() >= 3)
11090 //MESSAGE("confirm multiple node " << oldId);
11091 isMultipleDetected =true;
11095 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11097 //MESSAGE("multiple Nodes detected on a shared face");
11098 int downId = itface->first.cellId;
11099 unsigned char cellType = itface->first.cellType;
11100 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11101 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11102 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11103 for (int ie =0; ie < nbEdges; ie++)
11106 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11107 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11109 vector<int> vn0 = mutipleNodes[nodes[0]];
11110 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11111 sort( vn0.begin(), vn0.end() );
11112 sort( vn1.begin(), vn1.end() );
11115 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11116 double *coords = grid->GetPoint(nodes[0]);
11117 gp_Pnt p0(coords[0], coords[1], coords[2]);
11118 coords = grid->GetPoint(nodes[nbNodes - 1]);
11119 gp_Pnt p1(coords[0], coords[1], coords[2]);
11121 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11122 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11123 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11124 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11125 for (int id=0; id < vn0.size(); id++)
11127 int idom = vn0[id];
11128 for (int ivol=0; ivol<nbvol; ivol++)
11130 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11131 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11132 if (theElems[idom].count(elem))
11134 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11135 domvol[idom] = svol;
11136 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11138 vtkIdType npts = 0;
11139 vtkIdType* pts = 0;
11140 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11141 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11144 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11145 angleDom[idom] = 0;
11149 gp_Pnt g(values[0], values[1], values[2]);
11150 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11151 //MESSAGE(" angle=" << angleDom[idom]);
11157 map<double, int> sortedDom; // sort domains by angle
11158 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11159 sortedDom[ia->second] = ia->first;
11160 vector<int> vnodes;
11162 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11164 vdom.push_back(ib->second);
11165 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11167 for (int ino = 0; ino < nbNodes; ino++)
11168 vnodes.push_back(nodes[ino]);
11169 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11177 // --- iterate on shared faces (volumes to modify, face to extrude)
11178 // get node id's of the face (id SMDS = id VTK)
11179 // create flat element with old and new nodes if requested
11181 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11182 // (domain1 X domain2) = domain1 + MAXINT*domain2
11184 std::map<int, std::map<long,int> > nodeQuadDomains;
11185 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11187 if (createJointElems)
11189 itface = faceDomains.begin();
11190 for (; itface != faceDomains.end(); ++itface)
11192 DownIdType face = itface->first;
11193 std::set<int> oldNodes;
11194 std::set<int>::iterator itn;
11196 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11198 std::map<int, int> domvol = itface->second;
11199 std::map<int, int>::iterator itdom = domvol.begin();
11200 int dom1 = itdom->first;
11201 int vtkVolId = itdom->second;
11203 int dom2 = itdom->first;
11204 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11206 stringstream grpname;
11209 grpname << dom1 << "_" << dom2;
11211 grpname << dom2 << "_" << dom1;
11213 string namegrp = grpname.str();
11214 if (!mapOfJunctionGroups.count(namegrp))
11215 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11216 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11218 sgrp->Add(vol->GetID());
11222 // --- create volumes on multiple domain intersection if requested
11223 // iterate on edgesMultiDomains
11225 if (createJointElems)
11227 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11228 for (; ite != edgesMultiDomains.end(); ++ite)
11230 vector<int> nodes = ite->first;
11231 vector<int> orderDom = ite->second;
11232 vector<vtkIdType> orderedNodes;
11233 if (nodes.size() == 2)
11235 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11236 for (int ino=0; ino < nodes.size(); ino++)
11237 if (orderDom.size() == 3)
11238 for (int idom = 0; idom <orderDom.size(); idom++)
11239 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11241 for (int idom = orderDom.size()-1; idom >=0; idom--)
11242 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11243 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11245 stringstream grpname;
11247 grpname << 0 << "_" << 0;
11249 string namegrp = grpname.str();
11250 if (!mapOfJunctionGroups.count(namegrp))
11251 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11252 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11254 sgrp->Add(vol->GetID());
11258 //MESSAGE("Quadratic multiple joints not implemented");
11259 // TODO quadratic nodes
11264 // --- list the explicit faces and edges of the mesh that need to be modified,
11265 // i.e. faces and edges built with one or more duplicated nodes.
11266 // associate these faces or edges to their corresponding domain.
11267 // only the first domain found is kept when a face or edge is shared
11269 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11270 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11271 faceOrEdgeDom.clear();
11274 for (int idomain = 0; idomain < theElems.size(); idomain++)
11276 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11277 for (; itnod != nodeDomains.end(); ++itnod)
11279 int oldId = itnod->first;
11280 //MESSAGE(" node " << oldId);
11281 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11282 for (int i = 0; i < l.ncells; i++)
11284 int vtkId = l.cells[i];
11285 int vtkType = grid->GetCellType(vtkId);
11286 int downId = grid->CellIdToDownId(vtkId);
11288 continue; // new cells: not to be modified
11289 DownIdType aCell(downId, vtkType);
11290 int volParents[1000];
11291 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11292 for (int j = 0; j < nbvol; j++)
11293 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11294 if (!feDom.count(vtkId))
11296 feDom[vtkId] = idomain;
11297 faceOrEdgeDom[aCell] = emptyMap;
11298 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11299 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11300 // << " type " << vtkType << " downId " << downId);
11306 // --- iterate on shared faces (volumes to modify, face to extrude)
11307 // get node id's of the face
11308 // replace old nodes by new nodes in volumes, and update inverse connectivity
11310 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11311 for (int m=0; m<3; m++)
11313 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11314 itface = (*amap).begin();
11315 for (; itface != (*amap).end(); ++itface)
11317 DownIdType face = itface->first;
11318 std::set<int> oldNodes;
11319 std::set<int>::iterator itn;
11321 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11322 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11323 std::map<int, int> localClonedNodeIds;
11325 std::map<int, int> domvol = itface->second;
11326 std::map<int, int>::iterator itdom = domvol.begin();
11327 for (; itdom != domvol.end(); ++itdom)
11329 int idom = itdom->first;
11330 int vtkVolId = itdom->second;
11331 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11332 localClonedNodeIds.clear();
11333 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11336 if (nodeDomains[oldId].count(idom))
11338 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11339 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11342 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11347 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11348 grid->BuildLinks();
11356 * \brief Double nodes on some external faces and create flat elements.
11357 * Flat elements are mainly used by some types of mechanic calculations.
11359 * Each group of the list must be constituted of faces.
11360 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11361 * @param theElems - list of groups of faces, where a group of faces is a set of
11362 * SMDS_MeshElements sorted by Id.
11363 * @return TRUE if operation has been completed successfully, FALSE otherwise
11365 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11367 MESSAGE("-------------------------------------------------");
11368 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11369 MESSAGE("-------------------------------------------------");
11371 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11373 // --- For each group of faces
11374 // duplicate the nodes, create a flat element based on the face
11375 // replace the nodes of the faces by their clones
11377 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11378 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11379 clonedNodes.clear();
11380 intermediateNodes.clear();
11381 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11382 mapOfJunctionGroups.clear();
11384 for (int idom = 0; idom < theElems.size(); idom++)
11386 const TIDSortedElemSet& domain = theElems[idom];
11387 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11388 for (; elemItr != domain.end(); ++elemItr)
11390 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11391 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11394 // MESSAGE("aFace=" << aFace->GetID());
11395 bool isQuad = aFace->IsQuadratic();
11396 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11398 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11400 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11401 while (nodeIt->more())
11403 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11404 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11406 ln2.push_back(node);
11408 ln0.push_back(node);
11410 const SMDS_MeshNode* clone = 0;
11411 if (!clonedNodes.count(node))
11413 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11414 clonedNodes[node] = clone;
11417 clone = clonedNodes[node];
11420 ln3.push_back(clone);
11422 ln1.push_back(clone);
11424 const SMDS_MeshNode* inter = 0;
11425 if (isQuad && (!isMedium))
11427 if (!intermediateNodes.count(node))
11429 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11430 intermediateNodes[node] = inter;
11433 inter = intermediateNodes[node];
11434 ln4.push_back(inter);
11438 // --- extrude the face
11440 vector<const SMDS_MeshNode*> ln;
11441 SMDS_MeshVolume* vol = 0;
11442 vtkIdType aType = aFace->GetVtkType();
11446 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11447 // MESSAGE("vol prism " << vol->GetID());
11448 ln.push_back(ln1[0]);
11449 ln.push_back(ln1[1]);
11450 ln.push_back(ln1[2]);
11453 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11454 // MESSAGE("vol hexa " << vol->GetID());
11455 ln.push_back(ln1[0]);
11456 ln.push_back(ln1[1]);
11457 ln.push_back(ln1[2]);
11458 ln.push_back(ln1[3]);
11460 case VTK_QUADRATIC_TRIANGLE:
11461 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11462 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11463 // MESSAGE("vol quad prism " << vol->GetID());
11464 ln.push_back(ln1[0]);
11465 ln.push_back(ln1[1]);
11466 ln.push_back(ln1[2]);
11467 ln.push_back(ln3[0]);
11468 ln.push_back(ln3[1]);
11469 ln.push_back(ln3[2]);
11471 case VTK_QUADRATIC_QUAD:
11472 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11473 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11474 // ln4[0], ln4[1], ln4[2], ln4[3]);
11475 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11476 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11477 ln4[0], ln4[1], ln4[2], ln4[3]);
11478 // MESSAGE("vol quad hexa " << vol->GetID());
11479 ln.push_back(ln1[0]);
11480 ln.push_back(ln1[1]);
11481 ln.push_back(ln1[2]);
11482 ln.push_back(ln1[3]);
11483 ln.push_back(ln3[0]);
11484 ln.push_back(ln3[1]);
11485 ln.push_back(ln3[2]);
11486 ln.push_back(ln3[3]);
11496 stringstream grpname;
11500 string namegrp = grpname.str();
11501 if (!mapOfJunctionGroups.count(namegrp))
11502 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11503 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11505 sgrp->Add(vol->GetID());
11508 // --- modify the face
11510 aFace->ChangeNodes(&ln[0], ln.size());
11516 //================================================================================
11518 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11519 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11520 * \return TRUE if operation has been completed successfully, FALSE otherwise
11522 //================================================================================
11524 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11526 // iterates on volume elements and detect all free faces on them
11527 SMESHDS_Mesh* aMesh = GetMeshDS();
11530 //bool res = false;
11531 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11532 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11535 const SMDS_MeshVolume* volume = vIt->next();
11536 SMDS_VolumeTool vTool( volume );
11537 vTool.SetExternalNormal();
11538 const bool isPoly = volume->IsPoly();
11539 const bool isQuad = volume->IsQuadratic();
11540 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11542 if (!vTool.IsFreeFace(iface))
11545 vector<const SMDS_MeshNode *> nodes;
11546 int nbFaceNodes = vTool.NbFaceNodes(iface);
11547 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11549 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11550 nodes.push_back(faceNodes[inode]);
11552 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11553 nodes.push_back(faceNodes[inode]);
11555 // add new face based on volume nodes
11556 if (aMesh->FindFace( nodes ) ) {
11558 continue; // face already exsist
11560 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11564 return ( nbFree==(nbExisted+nbCreated) );
11569 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11571 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11573 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11576 //================================================================================
11578 * \brief Creates missing boundary elements
11579 * \param elements - elements whose boundary is to be checked
11580 * \param dimension - defines type of boundary elements to create
11581 * \param group - a group to store created boundary elements in
11582 * \param targetMesh - a mesh to store created boundary elements in
11583 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11584 * \param toCopyExistingBoundary - if true, not only new but also pre-existing
11585 * boundary elements will be copied into the targetMesh
11586 * \param toAddExistingBondary - if true, not only new but also pre-existing
11587 * boundary elements will be added into the new group
11588 * \param aroundElements - if true, elements will be created on boundary of given
11589 * elements else, on boundary of the whole mesh.
11590 * \return nb of added boundary elements
11592 //================================================================================
11594 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11595 Bnd_Dimension dimension,
11596 SMESH_Group* group/*=0*/,
11597 SMESH_Mesh* targetMesh/*=0*/,
11598 bool toCopyElements/*=false*/,
11599 bool toCopyExistingBoundary/*=false*/,
11600 bool toAddExistingBondary/*= false*/,
11601 bool aroundElements/*= false*/)
11603 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11604 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11605 // hope that all elements are of the same type, do not check them all
11606 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11607 throw SALOME_Exception(LOCALIZED("wrong element type"));
11610 toCopyElements = toCopyExistingBoundary = false;
11612 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11613 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11614 int nbAddedBnd = 0;
11616 // editor adding present bnd elements and optionally holding elements to add to the group
11617 SMESH_MeshEditor* presentEditor;
11618 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11619 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11621 SMDS_VolumeTool vTool;
11622 TIDSortedElemSet avoidSet;
11623 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11626 typedef vector<const SMDS_MeshNode*> TConnectivity;
11628 SMDS_ElemIteratorPtr eIt;
11629 if (elements.empty())
11630 eIt = aMesh->elementsIterator(elemType);
11632 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11634 while (eIt->more())
11636 const SMDS_MeshElement* elem = eIt->next();
11637 const int iQuad = elem->IsQuadratic();
11639 // ------------------------------------------------------------------------------------
11640 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11641 // ------------------------------------------------------------------------------------
11642 vector<const SMDS_MeshElement*> presentBndElems;
11643 vector<TConnectivity> missingBndElems;
11644 TConnectivity nodes;
11645 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11647 vTool.SetExternalNormal();
11648 const SMDS_MeshElement* otherVol = 0;
11649 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11651 if ( !vTool.IsFreeFace(iface, &otherVol) &&
11652 ( !aroundElements || elements.count( otherVol )))
11654 const int nbFaceNodes = vTool.NbFaceNodes(iface);
11655 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11656 if ( missType == SMDSAbs_Edge ) // boundary edges
11658 nodes.resize( 2+iQuad );
11659 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11661 for ( int j = 0; j < nodes.size(); ++j )
11663 if ( const SMDS_MeshElement* edge =
11664 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11665 presentBndElems.push_back( edge );
11667 missingBndElems.push_back( nodes );
11670 else // boundary face
11673 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11674 nodes.push_back( nn[inode] );
11676 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11677 nodes.push_back( nn[inode] );
11679 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11680 presentBndElems.push_back( f );
11682 missingBndElems.push_back( nodes );
11684 if ( targetMesh != myMesh )
11686 // add 1D elements on face boundary to be added to a new mesh
11687 const SMDS_MeshElement* edge;
11688 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11691 edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
11693 edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
11694 if ( edge && avoidSet.insert( edge ).second )
11695 presentBndElems.push_back( edge );
11701 else // elem is a face ------------------------------------------
11703 avoidSet.clear(), avoidSet.insert( elem );
11704 int nbNodes = elem->NbCornerNodes();
11705 nodes.resize( 2 /*+ iQuad*/);
11706 for ( int i = 0; i < nbNodes; i++ )
11708 nodes[0] = elem->GetNode(i);
11709 nodes[1] = elem->GetNode((i+1)%nbNodes);
11710 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11711 continue; // not free link
11714 //nodes[2] = elem->GetNode( i + nbNodes );
11715 if ( const SMDS_MeshElement* edge =
11716 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11717 presentBndElems.push_back( edge );
11719 missingBndElems.push_back( nodes );
11723 // ---------------------------------
11724 // 2. Add missing boundary elements
11725 // ---------------------------------
11726 if ( targetMesh != myMesh )
11727 // instead of making a map of nodes in this mesh and targetMesh,
11728 // we create nodes with same IDs.
11729 for ( int i = 0; i < missingBndElems.size(); ++i )
11731 TConnectivity& srcNodes = missingBndElems[i];
11732 TConnectivity nodes( srcNodes.size() );
11733 for ( inode = 0; inode < nodes.size(); ++inode )
11734 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11735 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11737 /*noMedium=*/true))
11739 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11743 for ( int i = 0; i < missingBndElems.size(); ++i )
11745 TConnectivity& nodes = missingBndElems[i];
11746 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11748 /*noMedium=*/true))
11750 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11754 // ----------------------------------
11755 // 3. Copy present boundary elements
11756 // ----------------------------------
11757 if ( toCopyExistingBoundary )
11758 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11760 const SMDS_MeshElement* e = presentBndElems[i];
11761 TConnectivity nodes( e->NbNodes() );
11762 for ( inode = 0; inode < nodes.size(); ++inode )
11763 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11764 presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
11766 else // store present elements to add them to a group
11767 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11769 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11772 } // loop on given elements
11774 // ---------------------------------------------
11775 // 4. Fill group with boundary elements
11776 // ---------------------------------------------
11779 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11780 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11781 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11783 tgtEditor.myLastCreatedElems.Clear();
11784 tgtEditor2.myLastCreatedElems.Clear();
11786 // -----------------------
11787 // 5. Copy given elements
11788 // -----------------------
11789 if ( toCopyElements && targetMesh != myMesh )
11791 if (elements.empty())
11792 eIt = aMesh->elementsIterator(elemType);
11794 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11795 while (eIt->more())
11797 const SMDS_MeshElement* elem = eIt->next();
11798 TConnectivity nodes( elem->NbNodes() );
11799 for ( inode = 0; inode < nodes.size(); ++inode )
11800 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11801 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11803 tgtEditor.myLastCreatedElems.Clear();