1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
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 const SMDS_MeshNode* N[6];
1136 if ( aBadRate1 <= aBadRate2 ) {
1143 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1144 aNodes[6], aNodes[7], newN );
1145 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1146 newN, aNodes[4], aNodes[5] );
1155 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1156 aNodes[7], aNodes[4], newN );
1157 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1158 newN, aNodes[5], aNodes[6] );
1162 // care of a new element
1164 myLastCreatedElems.Append(newElem1);
1165 myLastCreatedElems.Append(newElem2);
1166 AddToSameGroups( newElem1, elem, aMesh );
1167 AddToSameGroups( newElem2, elem, aMesh );
1169 // put a new triangle on the same shape
1172 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1173 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1175 aMesh->RemoveElement( elem );
1180 //=======================================================================
1181 //function : BestSplit
1182 //purpose : Find better diagonal for cutting.
1183 //=======================================================================
1185 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1186 SMESH::Controls::NumericalFunctorPtr theCrit)
1188 myLastCreatedElems.Clear();
1189 myLastCreatedNodes.Clear();
1194 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1197 if( theQuad->NbNodes()==4 ||
1198 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1200 // retrieve element nodes
1201 const SMDS_MeshNode* aNodes [4];
1202 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1204 //while (itN->more())
1206 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1208 // compare two sets of possible triangles
1209 double aBadRate1, aBadRate2; // to what extent a set is bad
1210 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1211 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1212 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1214 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1215 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1216 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1218 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1219 return 1; // diagonal 1-3
1221 return 2; // diagonal 2-4
1228 // Methods of splitting volumes into tetra
1230 const int theHexTo5_1[5*4+1] =
1232 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1234 const int theHexTo5_2[5*4+1] =
1236 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1238 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1240 const int theHexTo6_1[6*4+1] =
1242 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
1244 const int theHexTo6_2[6*4+1] =
1246 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
1248 const int theHexTo6_3[6*4+1] =
1250 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
1252 const int theHexTo6_4[6*4+1] =
1254 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
1256 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1258 const int thePyraTo2_1[2*4+1] =
1260 0, 1, 2, 4, 0, 2, 3, 4, -1
1262 const int thePyraTo2_2[2*4+1] =
1264 1, 2, 3, 4, 1, 3, 0, 4, -1
1266 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1268 const int thePentaTo3_1[3*4+1] =
1270 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1272 const int thePentaTo3_2[3*4+1] =
1274 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1276 const int thePentaTo3_3[3*4+1] =
1278 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1280 const int thePentaTo3_4[3*4+1] =
1282 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1284 const int thePentaTo3_5[3*4+1] =
1286 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1288 const int thePentaTo3_6[3*4+1] =
1290 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1292 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1293 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1295 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1298 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1299 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1300 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1305 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1306 bool _baryNode; //!< additional node is to be created at cell barycenter
1307 bool _ownConn; //!< to delete _connectivity in destructor
1308 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1310 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1311 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1312 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1313 bool hasFacet( const TTriangleFacet& facet ) const
1315 const int* tetConn = _connectivity;
1316 for ( ; tetConn[0] >= 0; tetConn += 4 )
1317 if (( facet.contains( tetConn[0] ) +
1318 facet.contains( tetConn[1] ) +
1319 facet.contains( tetConn[2] ) +
1320 facet.contains( tetConn[3] )) == 3 )
1326 //=======================================================================
1328 * \brief return TSplitMethod for the given element
1330 //=======================================================================
1332 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1334 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1336 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1337 // an edge and a face barycenter; tertaherdons are based on triangles and
1338 // a volume barycenter
1339 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1341 // Find out how adjacent volumes are split
1343 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1344 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1345 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1347 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1348 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1349 if ( nbNodes < 4 ) continue;
1351 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1352 const int* nInd = vol.GetFaceNodesIndices( iF );
1355 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1356 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1357 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1358 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1362 int iCom = 0; // common node of triangle faces to split into
1363 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1365 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1366 nInd[ iQ * ( (iCom+1)%nbNodes )],
1367 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1368 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1369 nInd[ iQ * ( (iCom+2)%nbNodes )],
1370 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1371 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1373 triaSplits.push_back( t012 );
1374 triaSplits.push_back( t023 );
1379 if ( !triaSplits.empty() )
1380 hasAdjacentSplits = true;
1383 // Among variants of split method select one compliant with adjacent volumes
1385 TSplitMethod method;
1386 if ( !vol.Element()->IsPoly() && !is24TetMode )
1388 int nbVariants = 2, nbTet = 0;
1389 const int** connVariants = 0;
1390 switch ( vol.Element()->GetEntityType() )
1392 case SMDSEntity_Hexa:
1393 case SMDSEntity_Quad_Hexa:
1394 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1395 connVariants = theHexTo5, nbTet = 5;
1397 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1399 case SMDSEntity_Pyramid:
1400 case SMDSEntity_Quad_Pyramid:
1401 connVariants = thePyraTo2; nbTet = 2;
1403 case SMDSEntity_Penta:
1404 case SMDSEntity_Quad_Penta:
1405 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1410 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1412 // check method compliancy with adjacent tetras,
1413 // all found splits must be among facets of tetras described by this method
1414 method = TSplitMethod( nbTet, connVariants[variant] );
1415 if ( hasAdjacentSplits && method._nbTetra > 0 )
1417 bool facetCreated = true;
1418 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1420 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1421 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1422 facetCreated = method.hasFacet( *facet );
1424 if ( !facetCreated )
1425 method = TSplitMethod(0); // incompatible method
1429 if ( method._nbTetra < 1 )
1431 // No standard method is applicable, use a generic solution:
1432 // each facet of a volume is split into triangles and
1433 // each of triangles and a volume barycenter form a tetrahedron.
1435 int* connectivity = new int[ maxTetConnSize + 1 ];
1436 method._connectivity = connectivity;
1437 method._ownConn = true;
1438 method._baryNode = true;
1441 int baryCenInd = vol.NbNodes();
1442 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1444 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1445 const int* nInd = vol.GetFaceNodesIndices( iF );
1446 // find common node of triangle facets of tetra to create
1447 int iCommon = 0; // index in linear numeration
1448 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1449 if ( !triaSplits.empty() )
1452 const TTriangleFacet* facet = &triaSplits.front();
1453 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1454 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1455 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1458 else if ( nbNodes > 3 && !is24TetMode )
1460 // find the best method of splitting into triangles by aspect ratio
1461 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1462 map< double, int > badness2iCommon;
1463 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1464 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1465 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1466 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1468 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1469 nodes[ iQ*((iLast-1)%nbNodes)],
1470 nodes[ iQ*((iLast )%nbNodes)]);
1471 double badness = getBadRate( &tria, aspectRatio );
1472 badness2iCommon.insert( make_pair( badness, iCommon ));
1474 // use iCommon with lowest badness
1475 iCommon = badness2iCommon.begin()->second;
1477 if ( iCommon >= nbNodes )
1478 iCommon = 0; // something wrong
1480 // fill connectivity of tetrahedra based on a current face
1481 int nbTet = nbNodes - 2;
1482 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1484 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1485 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1487 for ( int i = 0; i < nbTet; ++i )
1489 int i1 = i, i2 = (i+1) % nbNodes;
1490 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1491 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493 connectivity[ connSize++ ] = faceBaryCenInd;
1494 connectivity[ connSize++ ] = baryCenInd;
1499 for ( int i = 0; i < nbTet; ++i )
1501 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1502 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1503 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1504 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1505 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1506 connectivity[ connSize++ ] = baryCenInd;
1509 method._nbTetra += nbTet;
1511 connectivity[ connSize++ ] = -1;
1515 //================================================================================
1517 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1519 //================================================================================
1521 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1523 // find the tetrahedron including the three nodes of facet
1524 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1525 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1526 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1527 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1528 while ( volIt1->more() )
1530 const SMDS_MeshElement* v = volIt1->next();
1531 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1533 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1534 while ( volIt2->more() )
1535 if ( v != volIt2->next() )
1537 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1538 while ( volIt3->more() )
1539 if ( v == volIt3->next() )
1545 //=======================================================================
1547 * \brief A key of a face of volume
1549 //=======================================================================
1551 struct TVolumeFaceKey: pair< int, pair< int, int> >
1553 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1555 TIDSortedNodeSet sortedNodes;
1556 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1557 int nbNodes = vol.NbFaceNodes( iF );
1558 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1559 for ( int i = 0; i < nbNodes; i += iQ )
1560 sortedNodes.insert( fNodes[i] );
1561 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1562 first = (*(n++))->GetID();
1563 second.first = (*(n++))->GetID();
1564 second.second = (*(n++))->GetID();
1569 //=======================================================================
1570 //function : SplitVolumesIntoTetra
1571 //purpose : Split volumic elements into tetrahedra.
1572 //=======================================================================
1574 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1575 const int theMethodFlags)
1577 // std-like iterator on coordinates of nodes of mesh element
1578 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1579 NXyzIterator xyzEnd;
1581 SMDS_VolumeTool volTool;
1582 SMESH_MesherHelper helper( *GetMesh());
1584 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1585 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1587 SMESH_SequenceOfElemPtr newNodes, newElems;
1589 // map face of volume to it's baricenrtic node
1590 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1593 TIDSortedElemSet::const_iterator elem = theElems.begin();
1594 for ( ; elem != theElems.end(); ++elem )
1596 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1597 if ( geomType <= SMDSEntity_Quad_Tetra )
1598 continue; // tetra or face or ...
1600 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1602 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1603 if ( splitMethod._nbTetra < 1 ) continue;
1605 // find submesh to add new tetras to
1606 if ( !subMesh || !subMesh->Contains( *elem ))
1608 int shapeID = FindShape( *elem );
1609 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1610 subMesh = GetMeshDS()->MeshElements( shapeID );
1613 if ( (*elem)->IsQuadratic() )
1616 // add quadratic links to the helper
1617 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1619 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1620 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1621 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1623 helper.SetIsQuadratic( true );
1628 helper.SetIsQuadratic( false );
1630 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1631 if ( splitMethod._baryNode )
1633 // make a node at barycenter
1634 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1635 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1636 nodes.push_back( gcNode );
1637 newNodes.Append( gcNode );
1639 if ( !splitMethod._faceBaryNode.empty() )
1641 // make or find baricentric nodes of faces
1642 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1643 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1645 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1646 volFace2BaryNode.insert
1647 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1650 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1651 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1653 nodes.push_back( iF_n->second = f_n->second );
1658 helper.SetElementsOnShape( true );
1659 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1660 const int* tetConn = splitMethod._connectivity;
1661 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1662 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1663 nodes[ tetConn[1] ],
1664 nodes[ tetConn[2] ],
1665 nodes[ tetConn[3] ]));
1667 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1669 // Split faces on sides of the split volume
1671 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1672 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1674 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1675 if ( nbNodes < 4 ) continue;
1677 // find an existing face
1678 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1679 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1680 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1683 helper.SetElementsOnShape( false );
1684 vector< const SMDS_MeshElement* > triangles;
1686 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1687 if ( iF_n != splitMethod._faceBaryNode.end() )
1689 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1691 const SMDS_MeshNode* n1 = fNodes[iN];
1692 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1693 const SMDS_MeshNode *n3 = iF_n->second;
1694 if ( !volTool.IsFaceExternal( iF ))
1696 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1701 // among possible triangles create ones discribed by split method
1702 const int* nInd = volTool.GetFaceNodesIndices( iF );
1703 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1704 int iCom = 0; // common node of triangle faces to split into
1705 list< TTriangleFacet > facets;
1706 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1708 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1709 nInd[ iQ * ( (iCom+1)%nbNodes )],
1710 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1711 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1712 nInd[ iQ * ( (iCom+2)%nbNodes )],
1713 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1714 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1716 facets.push_back( t012 );
1717 facets.push_back( t023 );
1718 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1719 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1720 nInd[ iQ * ((iLast-1)%nbNodes )],
1721 nInd[ iQ * ((iLast )%nbNodes )]));
1725 list< TTriangleFacet >::iterator facet = facets.begin();
1726 for ( ; facet != facets.end(); ++facet )
1728 if ( !volTool.IsFaceExternal( iF ))
1729 swap( facet->_n2, facet->_n3 );
1730 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1731 volNodes[ facet->_n2 ],
1732 volNodes[ facet->_n3 ]));
1735 // find submesh to add new triangles in
1736 if ( !fSubMesh || !fSubMesh->Contains( face ))
1738 int shapeID = FindShape( face );
1739 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1741 for ( int i = 0; i < triangles.size(); ++i )
1743 if ( !triangles[i] ) continue;
1745 fSubMesh->AddElement( triangles[i]);
1746 newElems.Append( triangles[i] );
1748 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1749 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1752 } // loop on volume faces to split them into triangles
1754 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1756 } // loop on volumes to split
1758 myLastCreatedNodes = newNodes;
1759 myLastCreatedElems = newElems;
1762 //=======================================================================
1763 //function : AddToSameGroups
1764 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1765 //=======================================================================
1767 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1768 const SMDS_MeshElement* elemInGroups,
1769 SMESHDS_Mesh * aMesh)
1771 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1772 if (!groups.empty()) {
1773 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1774 for ( ; grIt != groups.end(); grIt++ ) {
1775 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1776 if ( group && group->Contains( elemInGroups ))
1777 group->SMDSGroup().Add( elemToAdd );
1783 //=======================================================================
1784 //function : RemoveElemFromGroups
1785 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1786 //=======================================================================
1787 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1788 SMESHDS_Mesh * aMesh)
1790 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1791 if (!groups.empty())
1793 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1794 for (; GrIt != groups.end(); GrIt++)
1796 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1797 if (!grp || grp->IsEmpty()) continue;
1798 grp->SMDSGroup().Remove(removeelem);
1803 //================================================================================
1805 * \brief Replace elemToRm by elemToAdd in the all groups
1807 //================================================================================
1809 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1810 const SMDS_MeshElement* elemToAdd,
1811 SMESHDS_Mesh * aMesh)
1813 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1814 if (!groups.empty()) {
1815 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1816 for ( ; grIt != groups.end(); grIt++ ) {
1817 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1818 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1819 group->SMDSGroup().Add( elemToAdd );
1824 //================================================================================
1826 * \brief Replace elemToRm by elemToAdd in the all groups
1828 //================================================================================
1830 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1831 const vector<const SMDS_MeshElement*>& elemToAdd,
1832 SMESHDS_Mesh * aMesh)
1834 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1835 if (!groups.empty())
1837 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1838 for ( ; grIt != groups.end(); grIt++ ) {
1839 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1840 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1841 for ( int i = 0; i < elemToAdd.size(); ++i )
1842 group->SMDSGroup().Add( elemToAdd[ i ] );
1847 //=======================================================================
1848 //function : QuadToTri
1849 //purpose : Cut quadrangles into triangles.
1850 // theCrit is used to select a diagonal to cut
1851 //=======================================================================
1853 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1854 const bool the13Diag)
1856 myLastCreatedElems.Clear();
1857 myLastCreatedNodes.Clear();
1859 MESSAGE( "::QuadToTri()" );
1861 SMESHDS_Mesh * aMesh = GetMeshDS();
1863 Handle(Geom_Surface) surface;
1864 SMESH_MesherHelper helper( *GetMesh() );
1866 TIDSortedElemSet::iterator itElem;
1867 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1868 const SMDS_MeshElement* elem = *itElem;
1869 if ( !elem || elem->GetType() != SMDSAbs_Face )
1871 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1872 if(!isquad) continue;
1874 if(elem->NbNodes()==4) {
1875 // retrieve element nodes
1876 const SMDS_MeshNode* aNodes [4];
1877 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1879 while ( itN->more() )
1880 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1882 int aShapeId = FindShape( elem );
1883 const SMDS_MeshElement* newElem1 = 0;
1884 const SMDS_MeshElement* newElem2 = 0;
1886 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1887 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1890 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1891 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1893 myLastCreatedElems.Append(newElem1);
1894 myLastCreatedElems.Append(newElem2);
1895 // put a new triangle on the same shape and add to the same groups
1898 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1899 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1901 AddToSameGroups( newElem1, elem, aMesh );
1902 AddToSameGroups( newElem2, elem, aMesh );
1903 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1904 aMesh->RemoveElement( elem );
1907 // Quadratic quadrangle
1909 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1911 // get surface elem is on
1912 int aShapeId = FindShape( elem );
1913 if ( aShapeId != helper.GetSubShapeID() ) {
1917 shape = aMesh->IndexToShape( aShapeId );
1918 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1919 TopoDS_Face face = TopoDS::Face( shape );
1920 surface = BRep_Tool::Surface( face );
1921 if ( !surface.IsNull() )
1922 helper.SetSubShape( shape );
1926 const SMDS_MeshNode* aNodes [8];
1927 const SMDS_MeshNode* inFaceNode = 0;
1928 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1930 while ( itN->more() ) {
1931 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1932 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1933 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1935 inFaceNode = aNodes[ i-1 ];
1939 // find middle point for (0,1,2,3)
1940 // and create a node in this point;
1942 if ( surface.IsNull() ) {
1944 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1948 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1951 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1953 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1955 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1956 myLastCreatedNodes.Append(newN);
1958 // create a new element
1959 const SMDS_MeshElement* newElem1 = 0;
1960 const SMDS_MeshElement* newElem2 = 0;
1961 const SMDS_MeshNode* N[6];
1969 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1970 aNodes[6], aNodes[7], newN );
1971 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1972 newN, aNodes[4], aNodes[5] );
1981 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1982 aNodes[7], aNodes[4], newN );
1983 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1984 newN, aNodes[5], aNodes[6] );
1986 myLastCreatedElems.Append(newElem1);
1987 myLastCreatedElems.Append(newElem2);
1988 // put a new triangle on the same shape and add to the same groups
1991 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1992 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1994 AddToSameGroups( newElem1, elem, aMesh );
1995 AddToSameGroups( newElem2, elem, aMesh );
1996 aMesh->RemoveElement( elem );
2003 //=======================================================================
2004 //function : getAngle
2006 //=======================================================================
2008 double getAngle(const SMDS_MeshElement * tr1,
2009 const SMDS_MeshElement * tr2,
2010 const SMDS_MeshNode * n1,
2011 const SMDS_MeshNode * n2)
2013 double angle = 2*PI; // bad angle
2016 SMESH::Controls::TSequenceOfXYZ P1, P2;
2017 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2018 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2021 if(!tr1->IsQuadratic())
2022 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2024 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2025 if ( N1.SquareMagnitude() <= gp::Resolution() )
2027 if(!tr2->IsQuadratic())
2028 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2030 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2031 if ( N2.SquareMagnitude() <= gp::Resolution() )
2034 // find the first diagonal node n1 in the triangles:
2035 // take in account a diagonal link orientation
2036 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2037 for ( int t = 0; t < 2; t++ ) {
2038 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2039 int i = 0, iDiag = -1;
2040 while ( it->more()) {
2041 const SMDS_MeshElement *n = it->next();
2042 if ( n == n1 || n == n2 ) {
2046 if ( i - iDiag == 1 )
2047 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2056 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2059 angle = N1.Angle( N2 );
2064 // =================================================
2065 // class generating a unique ID for a pair of nodes
2066 // and able to return nodes by that ID
2067 // =================================================
2071 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2072 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2075 long GetLinkID (const SMDS_MeshNode * n1,
2076 const SMDS_MeshNode * n2) const
2078 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2081 bool GetNodes (const long theLinkID,
2082 const SMDS_MeshNode* & theNode1,
2083 const SMDS_MeshNode* & theNode2) const
2085 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2086 if ( !theNode1 ) return false;
2087 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2088 if ( !theNode2 ) return false;
2094 const SMESHDS_Mesh* myMesh;
2099 //=======================================================================
2100 //function : TriToQuad
2101 //purpose : Fuse neighbour triangles into quadrangles.
2102 // theCrit is used to select a neighbour to fuse with.
2103 // theMaxAngle is a max angle between element normals at which
2104 // fusion is still performed.
2105 //=======================================================================
2107 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2108 SMESH::Controls::NumericalFunctorPtr theCrit,
2109 const double theMaxAngle)
2111 myLastCreatedElems.Clear();
2112 myLastCreatedNodes.Clear();
2114 MESSAGE( "::TriToQuad()" );
2116 if ( !theCrit.get() )
2119 SMESHDS_Mesh * aMesh = GetMeshDS();
2121 // Prepare data for algo: build
2122 // 1. map of elements with their linkIDs
2123 // 2. map of linkIDs with their elements
2125 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2126 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2127 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2128 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2130 TIDSortedElemSet::iterator itElem;
2131 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2132 const SMDS_MeshElement* elem = *itElem;
2133 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2134 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2135 if(!IsTria) continue;
2137 // retrieve element nodes
2138 const SMDS_MeshNode* aNodes [4];
2139 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2142 aNodes[ i++ ] = cast2Node( itN->next() );
2143 aNodes[ 3 ] = aNodes[ 0 ];
2146 for ( i = 0; i < 3; i++ ) {
2147 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2148 // check if elements sharing a link can be fused
2149 itLE = mapLi_listEl.find( link );
2150 if ( itLE != mapLi_listEl.end() ) {
2151 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2153 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2154 //if ( FindShape( elem ) != FindShape( elem2 ))
2155 // continue; // do not fuse triangles laying on different shapes
2156 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2157 continue; // avoid making badly shaped quads
2158 (*itLE).second.push_back( elem );
2161 mapLi_listEl[ link ].push_back( elem );
2163 mapEl_setLi [ elem ].insert( link );
2166 // Clean the maps from the links shared by a sole element, ie
2167 // links to which only one element is bound in mapLi_listEl
2169 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2170 int nbElems = (*itLE).second.size();
2171 if ( nbElems < 2 ) {
2172 const SMDS_MeshElement* elem = (*itLE).second.front();
2173 SMESH_TLink link = (*itLE).first;
2174 mapEl_setLi[ elem ].erase( link );
2175 if ( mapEl_setLi[ elem ].empty() )
2176 mapEl_setLi.erase( elem );
2180 // Algo: fuse triangles into quadrangles
2182 while ( ! mapEl_setLi.empty() ) {
2183 // Look for the start element:
2184 // the element having the least nb of shared links
2185 const SMDS_MeshElement* startElem = 0;
2187 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2188 int nbLinks = (*itEL).second.size();
2189 if ( nbLinks < minNbLinks ) {
2190 startElem = (*itEL).first;
2191 minNbLinks = nbLinks;
2192 if ( minNbLinks == 1 )
2197 // search elements to fuse starting from startElem or links of elements
2198 // fused earlyer - startLinks
2199 list< SMESH_TLink > startLinks;
2200 while ( startElem || !startLinks.empty() ) {
2201 while ( !startElem && !startLinks.empty() ) {
2202 // Get an element to start, by a link
2203 SMESH_TLink linkId = startLinks.front();
2204 startLinks.pop_front();
2205 itLE = mapLi_listEl.find( linkId );
2206 if ( itLE != mapLi_listEl.end() ) {
2207 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2208 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2209 for ( ; itE != listElem.end() ; itE++ )
2210 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2212 mapLi_listEl.erase( itLE );
2217 // Get candidates to be fused
2218 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2219 const SMESH_TLink *link12, *link13;
2221 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2222 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2223 ASSERT( !setLi.empty() );
2224 set< SMESH_TLink >::iterator itLi;
2225 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2227 const SMESH_TLink & link = (*itLi);
2228 itLE = mapLi_listEl.find( link );
2229 if ( itLE == mapLi_listEl.end() )
2232 const SMDS_MeshElement* elem = (*itLE).second.front();
2234 elem = (*itLE).second.back();
2235 mapLi_listEl.erase( itLE );
2236 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2247 // add other links of elem to list of links to re-start from
2248 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2249 set< SMESH_TLink >::iterator it;
2250 for ( it = links.begin(); it != links.end(); it++ ) {
2251 const SMESH_TLink& link2 = (*it);
2252 if ( link2 != link )
2253 startLinks.push_back( link2 );
2257 // Get nodes of possible quadrangles
2258 const SMDS_MeshNode *n12 [4], *n13 [4];
2259 bool Ok12 = false, Ok13 = false;
2260 const SMDS_MeshNode *linkNode1, *linkNode2;
2262 linkNode1 = link12->first;
2263 linkNode2 = link12->second;
2264 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2268 linkNode1 = link13->first;
2269 linkNode2 = link13->second;
2270 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2274 // Choose a pair to fuse
2275 if ( Ok12 && Ok13 ) {
2276 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2277 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2278 double aBadRate12 = getBadRate( &quad12, theCrit );
2279 double aBadRate13 = getBadRate( &quad13, theCrit );
2280 if ( aBadRate13 < aBadRate12 )
2287 // and remove fused elems and removed links from the maps
2288 mapEl_setLi.erase( tr1 );
2290 mapEl_setLi.erase( tr2 );
2291 mapLi_listEl.erase( *link12 );
2292 if(tr1->NbNodes()==3) {
2293 const SMDS_MeshElement* newElem = 0;
2294 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2295 myLastCreatedElems.Append(newElem);
2296 AddToSameGroups( newElem, tr1, aMesh );
2297 int aShapeId = tr1->getshapeId();
2300 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2302 aMesh->RemoveElement( tr1 );
2303 aMesh->RemoveElement( tr2 );
2306 const SMDS_MeshNode* N1 [6];
2307 const SMDS_MeshNode* N2 [6];
2308 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2309 // now we receive following N1 and N2 (using numeration as above image)
2310 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2311 // i.e. first nodes from both arrays determ new diagonal
2312 const SMDS_MeshNode* aNodes[8];
2321 const SMDS_MeshElement* newElem = 0;
2322 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2323 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2324 myLastCreatedElems.Append(newElem);
2325 AddToSameGroups( newElem, tr1, aMesh );
2326 int aShapeId = tr1->getshapeId();
2329 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2331 aMesh->RemoveElement( tr1 );
2332 aMesh->RemoveElement( tr2 );
2333 // remove middle node (9)
2334 GetMeshDS()->RemoveNode( N1[4] );
2338 mapEl_setLi.erase( tr3 );
2339 mapLi_listEl.erase( *link13 );
2340 if(tr1->NbNodes()==3) {
2341 const SMDS_MeshElement* newElem = 0;
2342 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2343 myLastCreatedElems.Append(newElem);
2344 AddToSameGroups( newElem, tr1, aMesh );
2345 int aShapeId = tr1->getshapeId();
2348 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2350 aMesh->RemoveElement( tr1 );
2351 aMesh->RemoveElement( tr3 );
2354 const SMDS_MeshNode* N1 [6];
2355 const SMDS_MeshNode* N2 [6];
2356 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2357 // now we receive following N1 and N2 (using numeration as above image)
2358 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2359 // i.e. first nodes from both arrays determ new diagonal
2360 const SMDS_MeshNode* aNodes[8];
2369 const SMDS_MeshElement* newElem = 0;
2370 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2371 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2372 myLastCreatedElems.Append(newElem);
2373 AddToSameGroups( newElem, tr1, aMesh );
2374 int aShapeId = tr1->getshapeId();
2377 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2379 aMesh->RemoveElement( tr1 );
2380 aMesh->RemoveElement( tr3 );
2381 // remove middle node (9)
2382 GetMeshDS()->RemoveNode( N1[4] );
2386 // Next element to fuse: the rejected one
2388 startElem = Ok12 ? tr3 : tr2;
2390 } // if ( startElem )
2391 } // while ( startElem || !startLinks.empty() )
2392 } // while ( ! mapEl_setLi.empty() )
2398 /*#define DUMPSO(txt) \
2399 // cout << txt << endl;
2400 //=============================================================================
2404 //=============================================================================
2405 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2409 int tmp = idNodes[ i1 ];
2410 idNodes[ i1 ] = idNodes[ i2 ];
2411 idNodes[ i2 ] = tmp;
2412 gp_Pnt Ptmp = P[ i1 ];
2415 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2418 //=======================================================================
2419 //function : SortQuadNodes
2420 //purpose : Set 4 nodes of a quadrangle face in a good order.
2421 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2423 //=======================================================================
2425 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2430 for ( i = 0; i < 4; i++ ) {
2431 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2433 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2436 gp_Vec V1(P[0], P[1]);
2437 gp_Vec V2(P[0], P[2]);
2438 gp_Vec V3(P[0], P[3]);
2440 gp_Vec Cross1 = V1 ^ V2;
2441 gp_Vec Cross2 = V2 ^ V3;
2444 if (Cross1.Dot(Cross2) < 0)
2449 if (Cross1.Dot(Cross2) < 0)
2453 swap ( i, i + 1, idNodes, P );
2455 // for ( int ii = 0; ii < 4; ii++ ) {
2456 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2457 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2463 //=======================================================================
2464 //function : SortHexaNodes
2465 //purpose : Set 8 nodes of a hexahedron in a good order.
2466 // Return success status
2467 //=======================================================================
2469 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2474 DUMPSO( "INPUT: ========================================");
2475 for ( i = 0; i < 8; i++ ) {
2476 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2477 if ( !n ) return false;
2478 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2479 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2481 DUMPSO( "========================================");
2484 set<int> faceNodes; // ids of bottom face nodes, to be found
2485 set<int> checkedId1; // ids of tried 2-nd nodes
2486 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2487 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2488 int iMin, iLoop1 = 0;
2490 // Loop to try the 2-nd nodes
2492 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2494 // Find not checked 2-nd node
2495 for ( i = 1; i < 8; i++ )
2496 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2497 int id1 = idNodes[i];
2498 swap ( 1, i, idNodes, P );
2499 checkedId1.insert ( id1 );
2503 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2504 // ie that all but meybe one (id3 which is on the same face) nodes
2505 // lay on the same side from the triangle plane.
2507 bool manyInPlane = false; // more than 4 nodes lay in plane
2509 while ( ++iLoop2 < 6 ) {
2511 // get 1-2-3 plane coeffs
2512 Standard_Real A, B, C, D;
2513 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2514 if ( N.SquareMagnitude() > gp::Resolution() )
2516 gp_Pln pln ( P[0], N );
2517 pln.Coefficients( A, B, C, D );
2519 // find the node (iMin) closest to pln
2520 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2522 for ( i = 3; i < 8; i++ ) {
2523 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2524 if ( fabs( dist[i] ) < minDist ) {
2525 minDist = fabs( dist[i] );
2528 if ( fabs( dist[i] ) <= tol )
2529 idInPln.insert( idNodes[i] );
2532 // there should not be more than 4 nodes in bottom plane
2533 if ( idInPln.size() > 1 )
2535 DUMPSO( "### idInPln.size() = " << idInPln.size());
2536 // idInPlane does not contain the first 3 nodes
2537 if ( manyInPlane || idInPln.size() == 5)
2538 return false; // all nodes in one plane
2541 // set the 1-st node to be not in plane
2542 for ( i = 3; i < 8; i++ ) {
2543 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2544 DUMPSO( "### Reset 0-th node");
2545 swap( 0, i, idNodes, P );
2550 // reset to re-check second nodes
2551 leastDist = DBL_MAX;
2555 break; // from iLoop2;
2558 // check that the other 4 nodes are on the same side
2559 bool sameSide = true;
2560 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2561 for ( i = 3; sameSide && i < 8; i++ ) {
2563 sameSide = ( isNeg == dist[i] <= 0.);
2566 // keep best solution
2567 if ( sameSide && minDist < leastDist ) {
2568 leastDist = minDist;
2570 faceNodes.insert( idNodes[ 1 ] );
2571 faceNodes.insert( idNodes[ 2 ] );
2572 faceNodes.insert( idNodes[ iMin ] );
2573 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2574 << " leastDist = " << leastDist);
2575 if ( leastDist <= DBL_MIN )
2580 // set next 3-d node to check
2581 int iNext = 2 + iLoop2;
2583 DUMPSO( "Try 2-nd");
2584 swap ( 2, iNext, idNodes, P );
2586 } // while ( iLoop2 < 6 )
2589 if ( faceNodes.empty() ) return false;
2591 // Put the faceNodes in proper places
2592 for ( i = 4; i < 8; i++ ) {
2593 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2594 // find a place to put
2596 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2598 DUMPSO( "Set faceNodes");
2599 swap ( iTo, i, idNodes, P );
2604 // Set nodes of the found bottom face in good order
2605 DUMPSO( " Found bottom face: ");
2606 i = SortQuadNodes( theMesh, idNodes );
2608 gp_Pnt Ptmp = P[ i ];
2613 // for ( int ii = 0; ii < 4; ii++ ) {
2614 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2615 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2618 // Gravity center of the top and bottom faces
2619 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2620 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2622 // Get direction from the bottom to the top face
2623 gp_Vec upDir ( aGCb, aGCt );
2624 Standard_Real upDirSize = upDir.Magnitude();
2625 if ( upDirSize <= gp::Resolution() ) return false;
2628 // Assure that the bottom face normal points up
2629 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2630 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2631 if ( Nb.Dot( upDir ) < 0 ) {
2632 DUMPSO( "Reverse bottom face");
2633 swap( 1, 3, idNodes, P );
2636 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2637 Standard_Real minDist = DBL_MAX;
2638 for ( i = 4; i < 8; i++ ) {
2639 // projection of P[i] to the plane defined by P[0] and upDir
2640 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2641 Standard_Real sqDist = P[0].SquareDistance( Pp );
2642 if ( sqDist < minDist ) {
2647 DUMPSO( "Set 4-th");
2648 swap ( 4, iMin, idNodes, P );
2650 // Set nodes of the top face in good order
2651 DUMPSO( "Sort top face");
2652 i = SortQuadNodes( theMesh, &idNodes[4] );
2655 gp_Pnt Ptmp = P[ i ];
2660 // Assure that direction of the top face normal is from the bottom face
2661 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2662 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2663 if ( Nt.Dot( upDir ) < 0 ) {
2664 DUMPSO( "Reverse top face");
2665 swap( 5, 7, idNodes, P );
2668 // DUMPSO( "OUTPUT: ========================================");
2669 // for ( i = 0; i < 8; i++ ) {
2670 // float *p = ugrid->GetPoint(idNodes[i]);
2671 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2677 //================================================================================
2679 * \brief Return nodes linked to the given one
2680 * \param theNode - the node
2681 * \param linkedNodes - the found nodes
2682 * \param type - the type of elements to check
2684 * Medium nodes are ignored
2686 //================================================================================
2688 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2689 TIDSortedElemSet & linkedNodes,
2690 SMDSAbs_ElementType type )
2692 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2693 while ( elemIt->more() )
2695 const SMDS_MeshElement* elem = elemIt->next();
2696 if(elem->GetType() == SMDSAbs_0DElement)
2699 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2700 if ( elem->GetType() == SMDSAbs_Volume )
2702 SMDS_VolumeTool vol( elem );
2703 while ( nodeIt->more() ) {
2704 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2705 if ( theNode != n && vol.IsLinked( theNode, n ))
2706 linkedNodes.insert( n );
2711 for ( int i = 0; nodeIt->more(); ++i ) {
2712 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2713 if ( n == theNode ) {
2714 int iBefore = i - 1;
2716 if ( elem->IsQuadratic() ) {
2717 int nb = elem->NbNodes() / 2;
2718 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2719 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2721 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2722 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2729 //=======================================================================
2730 //function : laplacianSmooth
2731 //purpose : pulls theNode toward the center of surrounding nodes directly
2732 // connected to that node along an element edge
2733 //=======================================================================
2735 void laplacianSmooth(const SMDS_MeshNode* theNode,
2736 const Handle(Geom_Surface)& theSurface,
2737 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2739 // find surrounding nodes
2741 TIDSortedElemSet nodeSet;
2742 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2744 // compute new coodrs
2746 double coord[] = { 0., 0., 0. };
2747 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2748 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2749 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2750 if ( theSurface.IsNull() ) { // smooth in 3D
2751 coord[0] += node->X();
2752 coord[1] += node->Y();
2753 coord[2] += node->Z();
2755 else { // smooth in 2D
2756 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2757 gp_XY* uv = theUVMap[ node ];
2758 coord[0] += uv->X();
2759 coord[1] += uv->Y();
2762 int nbNodes = nodeSet.size();
2765 coord[0] /= nbNodes;
2766 coord[1] /= nbNodes;
2768 if ( !theSurface.IsNull() ) {
2769 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2770 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2771 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2777 coord[2] /= nbNodes;
2781 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2784 //=======================================================================
2785 //function : centroidalSmooth
2786 //purpose : pulls theNode toward the element-area-weighted centroid of the
2787 // surrounding elements
2788 //=======================================================================
2790 void centroidalSmooth(const SMDS_MeshNode* theNode,
2791 const Handle(Geom_Surface)& theSurface,
2792 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2794 gp_XYZ aNewXYZ(0.,0.,0.);
2795 SMESH::Controls::Area anAreaFunc;
2796 double totalArea = 0.;
2801 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2802 while ( elemIt->more() )
2804 const SMDS_MeshElement* elem = elemIt->next();
2807 gp_XYZ elemCenter(0.,0.,0.);
2808 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2809 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2810 int nn = elem->NbNodes();
2811 if(elem->IsQuadratic()) nn = nn/2;
2813 //while ( itN->more() ) {
2815 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2817 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2818 aNodePoints.push_back( aP );
2819 if ( !theSurface.IsNull() ) { // smooth in 2D
2820 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2821 gp_XY* uv = theUVMap[ aNode ];
2822 aP.SetCoord( uv->X(), uv->Y(), 0. );
2826 double elemArea = anAreaFunc.GetValue( aNodePoints );
2827 totalArea += elemArea;
2829 aNewXYZ += elemCenter * elemArea;
2831 aNewXYZ /= totalArea;
2832 if ( !theSurface.IsNull() ) {
2833 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2834 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2839 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2842 //=======================================================================
2843 //function : getClosestUV
2844 //purpose : return UV of closest projection
2845 //=======================================================================
2847 static bool getClosestUV (Extrema_GenExtPS& projector,
2848 const gp_Pnt& point,
2851 projector.Perform( point );
2852 if ( projector.IsDone() ) {
2853 double u, v, minVal = DBL_MAX;
2854 for ( int i = projector.NbExt(); i > 0; i-- )
2855 if ( projector.Value( i ) < minVal ) {
2856 minVal = projector.Value( i );
2857 projector.Point( i ).Parameter( u, v );
2859 result.SetCoord( u, v );
2865 //=======================================================================
2867 //purpose : Smooth theElements during theNbIterations or until a worst
2868 // element has aspect ratio <= theTgtAspectRatio.
2869 // Aspect Ratio varies in range [1.0, inf].
2870 // If theElements is empty, the whole mesh is smoothed.
2871 // theFixedNodes contains additionally fixed nodes. Nodes built
2872 // on edges and boundary nodes are always fixed.
2873 //=======================================================================
2875 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2876 set<const SMDS_MeshNode*> & theFixedNodes,
2877 const SmoothMethod theSmoothMethod,
2878 const int theNbIterations,
2879 double theTgtAspectRatio,
2882 myLastCreatedElems.Clear();
2883 myLastCreatedNodes.Clear();
2885 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2887 if ( theTgtAspectRatio < 1.0 )
2888 theTgtAspectRatio = 1.0;
2890 const double disttol = 1.e-16;
2892 SMESH::Controls::AspectRatio aQualityFunc;
2894 SMESHDS_Mesh* aMesh = GetMeshDS();
2896 if ( theElems.empty() ) {
2897 // add all faces to theElems
2898 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2899 while ( fIt->more() ) {
2900 const SMDS_MeshElement* face = fIt->next();
2901 theElems.insert( face );
2904 // get all face ids theElems are on
2905 set< int > faceIdSet;
2906 TIDSortedElemSet::iterator itElem;
2908 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2909 int fId = FindShape( *itElem );
2910 // check that corresponding submesh exists and a shape is face
2912 faceIdSet.find( fId ) == faceIdSet.end() &&
2913 aMesh->MeshElements( fId )) {
2914 TopoDS_Shape F = aMesh->IndexToShape( fId );
2915 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2916 faceIdSet.insert( fId );
2919 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2921 // ===============================================
2922 // smooth elements on each TopoDS_Face separately
2923 // ===============================================
2925 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2926 for ( ; fId != faceIdSet.rend(); ++fId ) {
2927 // get face surface and submesh
2928 Handle(Geom_Surface) surface;
2929 SMESHDS_SubMesh* faceSubMesh = 0;
2931 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2932 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2933 bool isUPeriodic = false, isVPeriodic = false;
2935 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2936 surface = BRep_Tool::Surface( face );
2937 faceSubMesh = aMesh->MeshElements( *fId );
2938 fToler2 = BRep_Tool::Tolerance( face );
2939 fToler2 *= fToler2 * 10.;
2940 isUPeriodic = surface->IsUPeriodic();
2942 vPeriod = surface->UPeriod();
2943 isVPeriodic = surface->IsVPeriodic();
2945 uPeriod = surface->VPeriod();
2946 surface->Bounds( u1, u2, v1, v2 );
2948 // ---------------------------------------------------------
2949 // for elements on a face, find movable and fixed nodes and
2950 // compute UV for them
2951 // ---------------------------------------------------------
2952 bool checkBoundaryNodes = false;
2953 bool isQuadratic = false;
2954 set<const SMDS_MeshNode*> setMovableNodes;
2955 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2956 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2957 list< const SMDS_MeshElement* > elemsOnFace;
2959 Extrema_GenExtPS projector;
2960 GeomAdaptor_Surface surfAdaptor;
2961 if ( !surface.IsNull() ) {
2962 surfAdaptor.Load( surface );
2963 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2965 int nbElemOnFace = 0;
2966 itElem = theElems.begin();
2967 // loop on not yet smoothed elements: look for elems on a face
2968 while ( itElem != theElems.end() ) {
2969 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2970 break; // all elements found
2972 const SMDS_MeshElement* elem = *itElem;
2973 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2974 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2978 elemsOnFace.push_back( elem );
2979 theElems.erase( itElem++ );
2983 isQuadratic = elem->IsQuadratic();
2985 // get movable nodes of elem
2986 const SMDS_MeshNode* node;
2987 SMDS_TypeOfPosition posType;
2988 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2989 int nn = 0, nbn = elem->NbNodes();
2990 if(elem->IsQuadratic())
2992 while ( nn++ < nbn ) {
2993 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2994 const SMDS_PositionPtr& pos = node->GetPosition();
2995 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2996 if (posType != SMDS_TOP_EDGE &&
2997 posType != SMDS_TOP_VERTEX &&
2998 theFixedNodes.find( node ) == theFixedNodes.end())
3000 // check if all faces around the node are on faceSubMesh
3001 // because a node on edge may be bound to face
3002 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3004 if ( faceSubMesh ) {
3005 while ( eIt->more() && all ) {
3006 const SMDS_MeshElement* e = eIt->next();
3007 all = faceSubMesh->Contains( e );
3011 setMovableNodes.insert( node );
3013 checkBoundaryNodes = true;
3015 if ( posType == SMDS_TOP_3DSPACE )
3016 checkBoundaryNodes = true;
3019 if ( surface.IsNull() )
3022 // get nodes to check UV
3023 list< const SMDS_MeshNode* > uvCheckNodes;
3024 itN = elem->nodesIterator();
3025 nn = 0; nbn = elem->NbNodes();
3026 if(elem->IsQuadratic())
3028 while ( nn++ < nbn ) {
3029 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3030 if ( uvMap.find( node ) == uvMap.end() )
3031 uvCheckNodes.push_back( node );
3032 // add nodes of elems sharing node
3033 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3034 // while ( eIt->more() ) {
3035 // const SMDS_MeshElement* e = eIt->next();
3036 // if ( e != elem ) {
3037 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3038 // while ( nIt->more() ) {
3039 // const SMDS_MeshNode* n =
3040 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3041 // if ( uvMap.find( n ) == uvMap.end() )
3042 // uvCheckNodes.push_back( n );
3048 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3049 for ( ; n != uvCheckNodes.end(); ++n ) {
3052 const SMDS_PositionPtr& pos = node->GetPosition();
3053 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3055 switch ( posType ) {
3056 case SMDS_TOP_FACE: {
3057 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3058 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3061 case SMDS_TOP_EDGE: {
3062 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3063 Handle(Geom2d_Curve) pcurve;
3064 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3065 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3066 if ( !pcurve.IsNull() ) {
3067 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3068 uv = pcurve->Value( u ).XY();
3072 case SMDS_TOP_VERTEX: {
3073 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3074 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3075 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3080 // check existing UV
3081 bool project = true;
3082 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3083 double dist1 = DBL_MAX, dist2 = 0;
3084 if ( posType != SMDS_TOP_3DSPACE ) {
3085 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3086 project = dist1 > fToler2;
3088 if ( project ) { // compute new UV
3090 if ( !getClosestUV( projector, pNode, newUV )) {
3091 MESSAGE("Node Projection Failed " << node);
3095 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3097 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3099 if ( posType != SMDS_TOP_3DSPACE )
3100 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3101 if ( dist2 < dist1 )
3105 // store UV in the map
3106 listUV.push_back( uv );
3107 uvMap.insert( make_pair( node, &listUV.back() ));
3109 } // loop on not yet smoothed elements
3111 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3112 checkBoundaryNodes = true;
3114 // fix nodes on mesh boundary
3116 if ( checkBoundaryNodes ) {
3117 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3118 map< NLink, int >::iterator link_nb;
3119 // put all elements links to linkNbMap
3120 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3121 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3122 const SMDS_MeshElement* elem = (*elemIt);
3123 int nbn = elem->NbNodes();
3124 if(elem->IsQuadratic())
3126 // loop on elem links: insert them in linkNbMap
3127 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3128 for ( int iN = 0; iN < nbn; ++iN ) {
3129 curNode = elem->GetNode( iN );
3131 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3132 else link = make_pair( prevNode , curNode );
3134 link_nb = linkNbMap.find( link );
3135 if ( link_nb == linkNbMap.end() )
3136 linkNbMap.insert( make_pair ( link, 1 ));
3141 // remove nodes that are in links encountered only once from setMovableNodes
3142 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3143 if ( link_nb->second == 1 ) {
3144 setMovableNodes.erase( link_nb->first.first );
3145 setMovableNodes.erase( link_nb->first.second );
3150 // -----------------------------------------------------
3151 // for nodes on seam edge, compute one more UV ( uvMap2 );
3152 // find movable nodes linked to nodes on seam and which
3153 // are to be smoothed using the second UV ( uvMap2 )
3154 // -----------------------------------------------------
3156 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3157 if ( !surface.IsNull() ) {
3158 TopExp_Explorer eExp( face, TopAbs_EDGE );
3159 for ( ; eExp.More(); eExp.Next() ) {
3160 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3161 if ( !BRep_Tool::IsClosed( edge, face ))
3163 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3164 if ( !sm ) continue;
3165 // find out which parameter varies for a node on seam
3168 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3169 if ( pcurve.IsNull() ) continue;
3170 uv1 = pcurve->Value( f );
3172 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3173 if ( pcurve.IsNull() ) continue;
3174 uv2 = pcurve->Value( f );
3175 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3177 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3178 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3180 // get nodes on seam and its vertices
3181 list< const SMDS_MeshNode* > seamNodes;
3182 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3183 while ( nSeamIt->more() ) {
3184 const SMDS_MeshNode* node = nSeamIt->next();
3185 if ( !isQuadratic || !IsMedium( node ))
3186 seamNodes.push_back( node );
3188 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3189 for ( ; vExp.More(); vExp.Next() ) {
3190 sm = aMesh->MeshElements( vExp.Current() );
3192 nSeamIt = sm->GetNodes();
3193 while ( nSeamIt->more() )
3194 seamNodes.push_back( nSeamIt->next() );
3197 // loop on nodes on seam
3198 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3199 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3200 const SMDS_MeshNode* nSeam = *noSeIt;
3201 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3202 if ( n_uv == uvMap.end() )
3205 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3206 // set the second UV
3207 listUV.push_back( *n_uv->second );
3208 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3209 if ( uvMap2.empty() )
3210 uvMap2 = uvMap; // copy the uvMap contents
3211 uvMap2[ nSeam ] = &listUV.back();
3213 // collect movable nodes linked to ones on seam in nodesNearSeam
3214 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3215 while ( eIt->more() ) {
3216 const SMDS_MeshElement* e = eIt->next();
3217 int nbUseMap1 = 0, nbUseMap2 = 0;
3218 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3219 int nn = 0, nbn = e->NbNodes();
3220 if(e->IsQuadratic()) nbn = nbn/2;
3221 while ( nn++ < nbn )
3223 const SMDS_MeshNode* n =
3224 static_cast<const SMDS_MeshNode*>( nIt->next() );
3226 setMovableNodes.find( n ) == setMovableNodes.end() )
3228 // add only nodes being closer to uv2 than to uv1
3229 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3230 0.5 * ( n->Y() + nSeam->Y() ),
3231 0.5 * ( n->Z() + nSeam->Z() ));
3233 getClosestUV( projector, pMid, uv );
3234 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3235 nodesNearSeam.insert( n );
3241 // for centroidalSmooth all element nodes must
3242 // be on one side of a seam
3243 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3244 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3246 while ( nn++ < nbn ) {
3247 const SMDS_MeshNode* n =
3248 static_cast<const SMDS_MeshNode*>( nIt->next() );
3249 setMovableNodes.erase( n );
3253 } // loop on nodes on seam
3254 } // loop on edge of a face
3255 } // if ( !face.IsNull() )
3257 if ( setMovableNodes.empty() ) {
3258 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3259 continue; // goto next face
3267 double maxRatio = -1., maxDisplacement = -1.;
3268 set<const SMDS_MeshNode*>::iterator nodeToMove;
3269 for ( it = 0; it < theNbIterations; it++ ) {
3270 maxDisplacement = 0.;
3271 nodeToMove = setMovableNodes.begin();
3272 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3273 const SMDS_MeshNode* node = (*nodeToMove);
3274 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3277 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3278 if ( theSmoothMethod == LAPLACIAN )
3279 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3281 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3283 // node displacement
3284 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3285 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3286 if ( aDispl > maxDisplacement )
3287 maxDisplacement = aDispl;
3289 // no node movement => exit
3290 //if ( maxDisplacement < 1.e-16 ) {
3291 if ( maxDisplacement < disttol ) {
3292 MESSAGE("-- no node movement --");
3296 // check elements quality
3298 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3299 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3300 const SMDS_MeshElement* elem = (*elemIt);
3301 if ( !elem || elem->GetType() != SMDSAbs_Face )
3303 SMESH::Controls::TSequenceOfXYZ aPoints;
3304 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3305 double aValue = aQualityFunc.GetValue( aPoints );
3306 if ( aValue > maxRatio )
3310 if ( maxRatio <= theTgtAspectRatio ) {
3311 MESSAGE("-- quality achived --");
3314 if (it+1 == theNbIterations) {
3315 MESSAGE("-- Iteration limit exceeded --");
3317 } // smoothing iterations
3319 MESSAGE(" Face id: " << *fId <<
3320 " Nb iterstions: " << it <<
3321 " Displacement: " << maxDisplacement <<
3322 " Aspect Ratio " << maxRatio);
3324 // ---------------------------------------
3325 // new nodes positions are computed,
3326 // record movement in DS and set new UV
3327 // ---------------------------------------
3328 nodeToMove = setMovableNodes.begin();
3329 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3330 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3331 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3332 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3333 if ( node_uv != uvMap.end() ) {
3334 gp_XY* uv = node_uv->second;
3336 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3340 // move medium nodes of quadratic elements
3343 SMESH_MesherHelper helper( *GetMesh() );
3344 if ( !face.IsNull() )
3345 helper.SetSubShape( face );
3346 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3347 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3348 const SMDS_VtkFace* QF =
3349 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3350 if(QF && QF->IsQuadratic()) {
3351 vector<const SMDS_MeshNode*> Ns;
3352 Ns.reserve(QF->NbNodes()+1);
3353 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3354 while ( anIter->more() )
3355 Ns.push_back( cast2Node(anIter->next()) );
3356 Ns.push_back( Ns[0] );
3358 for(int i=0; i<QF->NbNodes(); i=i+2) {
3359 if ( !surface.IsNull() ) {
3360 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3361 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3362 gp_XY uv = ( uv1 + uv2 ) / 2.;
3363 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3364 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3367 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3368 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3369 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3371 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3372 fabs( Ns[i+1]->Y() - y ) > disttol ||
3373 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3374 // we have to move i+1 node
3375 aMesh->MoveNode( Ns[i+1], x, y, z );
3382 } // loop on face ids
3386 //=======================================================================
3387 //function : isReverse
3388 //purpose : Return true if normal of prevNodes is not co-directied with
3389 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3390 // iNotSame is where prevNodes and nextNodes are different
3391 //=======================================================================
3393 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3394 vector<const SMDS_MeshNode*> nextNodes,
3398 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3399 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3401 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3402 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3403 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3404 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3406 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3407 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3408 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3409 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3411 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3413 return (vA ^ vB) * vN < 0.0;
3416 //=======================================================================
3418 * \brief Create elements by sweeping an element
3419 * \param elem - element to sweep
3420 * \param newNodesItVec - nodes generated from each node of the element
3421 * \param newElems - generated elements
3422 * \param nbSteps - number of sweeping steps
3423 * \param srcElements - to append elem for each generated element
3425 //=======================================================================
3427 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3428 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3429 list<const SMDS_MeshElement*>& newElems,
3431 SMESH_SequenceOfElemPtr& srcElements)
3433 //MESSAGE("sweepElement " << nbSteps);
3434 SMESHDS_Mesh* aMesh = GetMeshDS();
3436 // Loop on elem nodes:
3437 // find new nodes and detect same nodes indices
3438 int nbNodes = elem->NbNodes();
3439 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3440 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3441 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3442 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3444 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3445 vector<int> sames(nbNodes);
3446 vector<bool> issimple(nbNodes);
3448 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3449 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3450 const SMDS_MeshNode* node = nnIt->first;
3451 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3452 if ( listNewNodes.empty() ) {
3456 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3458 itNN[ iNode ] = listNewNodes.begin();
3459 prevNod[ iNode ] = node;
3460 nextNod[ iNode ] = listNewNodes.front();
3461 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3462 if ( prevNod[ iNode ] != nextNod [ iNode ])
3463 iNotSameNode = iNode;
3467 sames[nbSame++] = iNode;
3472 //cerr<<" nbSame = "<<nbSame<<endl;
3473 if ( nbSame == nbNodes || nbSame > 2) {
3474 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3475 //INFOS( " Too many same nodes of element " << elem->GetID() );
3479 // if( elem->IsQuadratic() && nbSame>0 ) {
3480 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3484 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3485 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3487 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3488 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3489 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3493 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3494 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3495 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3496 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3498 // check element orientation
3500 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3501 //MESSAGE("Reversed elem " << elem );
3505 std::swap( iBeforeSame, iAfterSame );
3508 // make new elements
3509 const SMDS_MeshElement* lastElem = elem;
3510 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3512 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3513 if(issimple[iNode]) {
3514 nextNod[ iNode ] = *itNN[ iNode ];
3518 if( elem->GetType()==SMDSAbs_Node ) {
3519 // we have to use two nodes
3520 midlNod[ iNode ] = *itNN[ iNode ];
3522 nextNod[ iNode ] = *itNN[ iNode ];
3525 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3526 // we have to use each second node
3528 nextNod[ iNode ] = *itNN[ iNode ];
3532 // we have to use two nodes
3533 midlNod[ iNode ] = *itNN[ iNode ];
3535 nextNod[ iNode ] = *itNN[ iNode ];
3540 SMDS_MeshElement* aNewElem = 0;
3541 if(!elem->IsPoly()) {
3542 switch ( nbNodes ) {
3546 if ( nbSame == 0 ) {
3548 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3550 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3556 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3557 nextNod[ 1 ], nextNod[ 0 ] );
3559 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3560 nextNod[ iNotSameNode ] );
3564 case 3: { // TRIANGLE or quadratic edge
3565 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3567 if ( nbSame == 0 ) // --- pentahedron
3568 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3569 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3571 else if ( nbSame == 1 ) // --- pyramid
3572 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3573 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3574 nextNod[ iSameNode ]);
3576 else // 2 same nodes: --- tetrahedron
3577 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3578 nextNod[ iNotSameNode ]);
3580 else { // quadratic edge
3581 if(nbSame==0) { // quadratic quadrangle
3582 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3583 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3585 else if(nbSame==1) { // quadratic triangle
3587 return; // medium node on axis
3589 else if(sames[0]==0) {
3590 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3591 nextNod[2], midlNod[1], prevNod[2]);
3593 else { // sames[0]==1
3594 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3595 midlNod[0], nextNod[2], prevNod[2]);
3604 case 4: { // QUADRANGLE
3606 if ( nbSame == 0 ) // --- hexahedron
3607 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3608 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3610 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3611 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3612 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3613 nextNod[ iSameNode ]);
3614 newElems.push_back( aNewElem );
3615 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3616 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3617 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3619 else if ( nbSame == 2 ) { // pentahedron
3620 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3621 // iBeforeSame is same too
3622 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3623 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3624 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3626 // iAfterSame is same too
3627 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3628 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3629 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3633 case 6: { // quadratic triangle
3634 // create pentahedron with 15 nodes
3636 if(i0>0) { // reversed case
3637 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3638 nextNod[0], nextNod[2], nextNod[1],
3639 prevNod[5], prevNod[4], prevNod[3],
3640 nextNod[5], nextNod[4], nextNod[3],
3641 midlNod[0], midlNod[2], midlNod[1]);
3643 else { // not reversed case
3644 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3645 nextNod[0], nextNod[1], nextNod[2],
3646 prevNod[3], prevNod[4], prevNod[5],
3647 nextNod[3], nextNod[4], nextNod[5],
3648 midlNod[0], midlNod[1], midlNod[2]);
3651 else if(nbSame==1) {
3652 // 2d order pyramid of 13 nodes
3653 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3654 // int n12,int n23,int n34,int n41,
3655 // int n15,int n25,int n35,int n45, int ID);
3657 int n1,n4,n41,n15,n45;
3658 if(i0>0) { // reversed case
3659 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3660 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3666 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3667 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3672 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3673 nextNod[n4], prevNod[n4], prevNod[n5],
3674 midlNod[n1], nextNod[n41],
3675 midlNod[n4], prevNod[n41],
3676 prevNod[n15], nextNod[n15],
3677 nextNod[n45], prevNod[n45]);
3679 else if(nbSame==2) {
3680 // 2d order tetrahedron of 10 nodes
3681 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3682 // int n12,int n23,int n31,
3683 // int n14,int n24,int n34, int ID);
3684 int n1 = iNotSameNode;
3685 int n2,n3,n12,n23,n31;
3686 if(i0>0) { // reversed case
3687 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3688 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3694 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3695 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3700 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3701 prevNod[n12], prevNod[n23], prevNod[n31],
3702 midlNod[n1], nextNod[n12], nextNod[n31]);
3706 case 8: { // quadratic quadrangle
3708 // create hexahedron with 20 nodes
3709 if(i0>0) { // reversed case
3710 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3711 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3712 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3713 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3714 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3716 else { // not reversed case
3717 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3718 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3719 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3720 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3721 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3724 else if(nbSame==1) {
3725 // --- pyramid + pentahedron - can not be created since it is needed
3726 // additional middle node ot the center of face
3727 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3730 else if(nbSame==2) {
3731 // 2d order Pentahedron with 15 nodes
3732 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3733 // int n12,int n23,int n31,int n45,int n56,int n64,
3734 // int n14,int n25,int n36, int ID);
3736 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3737 // iBeforeSame is same too
3744 // iAfterSame is same too
3750 int n12,n45,n14,n25;
3751 if(i0>0) { //reversed case
3763 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3764 prevNod[n4], prevNod[n5], nextNod[n5],
3765 prevNod[n12], midlNod[n2], nextNod[n12],
3766 prevNod[n45], midlNod[n5], nextNod[n45],
3767 prevNod[n14], prevNod[n25], nextNod[n25]);
3772 // realized for extrusion only
3773 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3774 //vector<int> quantities (nbNodes + 2);
3776 //quantities[0] = nbNodes; // bottom of prism
3777 //for (int inode = 0; inode < nbNodes; inode++) {
3778 // polyedre_nodes[inode] = prevNod[inode];
3781 //quantities[1] = nbNodes; // top of prism
3782 //for (int inode = 0; inode < nbNodes; inode++) {
3783 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3786 //for (int iface = 0; iface < nbNodes; iface++) {
3787 // quantities[iface + 2] = 4;
3788 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3789 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3790 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3791 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3792 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3794 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3801 // realized for extrusion only
3802 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3803 vector<int> quantities (nbNodes + 2);
3805 quantities[0] = nbNodes; // bottom of prism
3806 for (int inode = 0; inode < nbNodes; inode++) {
3807 polyedre_nodes[inode] = prevNod[inode];
3810 quantities[1] = nbNodes; // top of prism
3811 for (int inode = 0; inode < nbNodes; inode++) {
3812 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3815 for (int iface = 0; iface < nbNodes; iface++) {
3816 quantities[iface + 2] = 4;
3817 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3818 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3819 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3820 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3821 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3823 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3827 newElems.push_back( aNewElem );
3828 myLastCreatedElems.Append(aNewElem);
3829 srcElements.Append( elem );
3830 lastElem = aNewElem;
3833 // set new prev nodes
3834 for ( iNode = 0; iNode < nbNodes; iNode++ )
3835 prevNod[ iNode ] = nextNod[ iNode ];
3840 //=======================================================================
3842 * \brief Create 1D and 2D elements around swept elements
3843 * \param mapNewNodes - source nodes and ones generated from them
3844 * \param newElemsMap - source elements and ones generated from them
3845 * \param elemNewNodesMap - nodes generated from each node of each element
3846 * \param elemSet - all swept elements
3847 * \param nbSteps - number of sweeping steps
3848 * \param srcElements - to append elem for each generated element
3850 //=======================================================================
3852 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3853 TElemOfElemListMap & newElemsMap,
3854 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3855 TIDSortedElemSet& elemSet,
3857 SMESH_SequenceOfElemPtr& srcElements)
3859 MESSAGE("makeWalls");
3860 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3861 SMESHDS_Mesh* aMesh = GetMeshDS();
3863 // Find nodes belonging to only one initial element - sweep them to get edges.
3865 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3866 for ( ; nList != mapNewNodes.end(); nList++ ) {
3867 const SMDS_MeshNode* node =
3868 static_cast<const SMDS_MeshNode*>( nList->first );
3869 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3870 int nbInitElems = 0;
3871 const SMDS_MeshElement* el = 0;
3872 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3873 while ( eIt->more() && nbInitElems < 2 ) {
3875 SMDSAbs_ElementType type = el->GetType();
3876 if ( type == SMDSAbs_Volume || type < highType ) continue;
3877 if ( type > highType ) {
3881 if ( elemSet.find(el) != elemSet.end() )
3884 if ( nbInitElems < 2 ) {
3885 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3886 if(!NotCreateEdge) {
3887 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3888 list<const SMDS_MeshElement*> newEdges;
3889 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3894 // Make a ceiling for each element ie an equal element of last new nodes.
3895 // Find free links of faces - make edges and sweep them into faces.
3897 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3898 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3899 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3900 const SMDS_MeshElement* elem = itElem->first;
3901 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3903 if(itElem->second.size()==0) continue;
3905 if ( elem->GetType() == SMDSAbs_Edge ) {
3906 // create a ceiling edge
3907 if (!elem->IsQuadratic()) {
3908 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3909 vecNewNodes[ 1 ]->second.back())) {
3910 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3911 vecNewNodes[ 1 ]->second.back()));
3912 srcElements.Append( myLastCreatedElems.Last() );
3916 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3917 vecNewNodes[ 1 ]->second.back(),
3918 vecNewNodes[ 2 ]->second.back())) {
3919 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3920 vecNewNodes[ 1 ]->second.back(),
3921 vecNewNodes[ 2 ]->second.back()));
3922 srcElements.Append( myLastCreatedElems.Last() );
3926 if ( elem->GetType() != SMDSAbs_Face )
3929 bool hasFreeLinks = false;
3931 TIDSortedElemSet avoidSet;
3932 avoidSet.insert( elem );
3934 set<const SMDS_MeshNode*> aFaceLastNodes;
3935 int iNode, nbNodes = vecNewNodes.size();
3936 if(!elem->IsQuadratic()) {
3937 // loop on the face nodes
3938 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3939 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3940 // look for free links of the face
3941 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3942 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3943 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3944 // check if a link is free
3945 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3946 hasFreeLinks = true;
3947 // make an edge and a ceiling for a new edge
3948 if ( !aMesh->FindEdge( n1, n2 )) {
3949 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3950 srcElements.Append( myLastCreatedElems.Last() );
3952 n1 = vecNewNodes[ iNode ]->second.back();
3953 n2 = vecNewNodes[ iNext ]->second.back();
3954 if ( !aMesh->FindEdge( n1, n2 )) {
3955 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3956 srcElements.Append( myLastCreatedElems.Last() );
3961 else { // elem is quadratic face
3962 int nbn = nbNodes/2;
3963 for ( iNode = 0; iNode < nbn; iNode++ ) {
3964 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3965 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3966 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3967 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3968 // check if a link is free
3969 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3970 hasFreeLinks = true;
3971 // make an edge and a ceiling for a new edge
3973 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3974 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3975 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3976 srcElements.Append( myLastCreatedElems.Last() );
3978 n1 = vecNewNodes[ iNode ]->second.back();
3979 n2 = vecNewNodes[ iNext ]->second.back();
3980 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3981 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3982 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3983 srcElements.Append( myLastCreatedElems.Last() );
3987 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3988 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3992 // sweep free links into faces
3994 if ( hasFreeLinks ) {
3995 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3996 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3998 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3999 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
4000 initNodeSet.insert( vecNewNodes[ iNode ]->first );
4001 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
4003 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
4004 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
4006 while ( iVol++ < volNb ) v++;
4007 // find indices of free faces of a volume and their source edges
4008 list< int > freeInd;
4009 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
4010 SMDS_VolumeTool vTool( *v );
4011 int iF, nbF = vTool.NbFaces();
4012 for ( iF = 0; iF < nbF; iF ++ ) {
4013 if (vTool.IsFreeFace( iF ) &&
4014 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4015 initNodeSet != faceNodeSet) // except an initial face
4017 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4019 freeInd.push_back( iF );
4020 // find source edge of a free face iF
4021 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4022 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4023 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4024 initNodeSet.begin(), initNodeSet.end(),
4025 commonNodes.begin());
4026 if ( (*v)->IsQuadratic() )
4027 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4029 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4031 if ( !srcEdges.back() )
4033 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4034 << iF << " of volume #" << vTool.ID() << endl;
4039 if ( freeInd.empty() )
4042 // create faces for all steps;
4043 // if such a face has been already created by sweep of edge,
4044 // assure that its orientation is OK
4045 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4047 vTool.SetExternalNormal();
4048 list< int >::iterator ind = freeInd.begin();
4049 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4050 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4052 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4053 int nbn = vTool.NbFaceNodes( *ind );
4055 case 3: { ///// triangle
4056 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4058 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4059 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4061 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4062 aMesh->RemoveElement(f);
4066 case 4: { ///// quadrangle
4067 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4069 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4070 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4072 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4073 aMesh->RemoveElement(f);
4078 if( (*v)->IsQuadratic() ) {
4079 if(nbn==6) { /////// quadratic triangle
4080 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4081 nodes[1], nodes[3], nodes[5] );
4083 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4084 nodes[1], nodes[3], nodes[5]));
4086 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4087 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4088 tmpnodes[0] = nodes[0];
4089 tmpnodes[1] = nodes[2];
4090 tmpnodes[2] = nodes[4];
4091 tmpnodes[3] = nodes[1];
4092 tmpnodes[4] = nodes[3];
4093 tmpnodes[5] = nodes[5];
4094 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4095 nodes[1], nodes[3], nodes[5]));
4096 aMesh->RemoveElement(f);
4099 else { /////// quadratic quadrangle
4100 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4101 nodes[1], nodes[3], nodes[5], nodes[7] );
4103 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4104 nodes[1], nodes[3], nodes[5], nodes[7]));
4106 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4107 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4108 tmpnodes[0] = nodes[0];
4109 tmpnodes[1] = nodes[2];
4110 tmpnodes[2] = nodes[4];
4111 tmpnodes[3] = nodes[6];
4112 tmpnodes[4] = nodes[1];
4113 tmpnodes[5] = nodes[3];
4114 tmpnodes[6] = nodes[5];
4115 tmpnodes[7] = nodes[7];
4116 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4117 nodes[1], nodes[3], nodes[5], nodes[7]));
4118 aMesh->RemoveElement(f);
4122 else { //////// polygon
4123 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4124 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4126 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4127 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4129 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4130 MESSAGE("ChangeElementNodes");
4131 aMesh->ChangeElementNodes( f, nodes, nbn );
4135 while ( srcElements.Length() < myLastCreatedElems.Length() )
4136 srcElements.Append( *srcEdge );
4138 } // loop on free faces
4140 // go to the next volume
4142 while ( iVol++ < nbVolumesByStep ) v++;
4145 } // sweep free links into faces
4147 // Make a ceiling face with a normal external to a volume
4149 SMDS_VolumeTool lastVol( itElem->second.back() );
4151 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4153 lastVol.SetExternalNormal();
4154 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4155 int nbn = lastVol.NbFaceNodes( iF );
4158 if (!hasFreeLinks ||
4159 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4160 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4163 if (!hasFreeLinks ||
4164 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4165 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4168 if(itElem->second.back()->IsQuadratic()) {
4170 if (!hasFreeLinks ||
4171 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4172 nodes[1], nodes[3], nodes[5]) ) {
4173 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4174 nodes[1], nodes[3], nodes[5]));
4178 if (!hasFreeLinks ||
4179 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4180 nodes[1], nodes[3], nodes[5], nodes[7]) )
4181 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4182 nodes[1], nodes[3], nodes[5], nodes[7]));
4186 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4187 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4188 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4192 while ( srcElements.Length() < myLastCreatedElems.Length() )
4193 srcElements.Append( myLastCreatedElems.Last() );
4195 } // loop on swept elements
4198 //=======================================================================
4199 //function : RotationSweep
4201 //=======================================================================
4203 SMESH_MeshEditor::PGroupIDs
4204 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4205 const gp_Ax1& theAxis,
4206 const double theAngle,
4207 const int theNbSteps,
4208 const double theTol,
4209 const bool theMakeGroups,
4210 const bool theMakeWalls)
4212 myLastCreatedElems.Clear();
4213 myLastCreatedNodes.Clear();
4215 // source elements for each generated one
4216 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4218 MESSAGE( "RotationSweep()");
4220 aTrsf.SetRotation( theAxis, theAngle );
4222 aTrsf2.SetRotation( theAxis, theAngle/2. );
4224 gp_Lin aLine( theAxis );
4225 double aSqTol = theTol * theTol;
4227 SMESHDS_Mesh* aMesh = GetMeshDS();
4229 TNodeOfNodeListMap mapNewNodes;
4230 TElemOfVecOfNnlmiMap mapElemNewNodes;
4231 TElemOfElemListMap newElemsMap;
4234 TIDSortedElemSet::iterator itElem;
4235 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4236 const SMDS_MeshElement* elem = *itElem;
4237 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4239 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4240 newNodesItVec.reserve( elem->NbNodes() );
4242 // loop on elem nodes
4243 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4244 while ( itN->more() ) {
4245 // check if a node has been already sweeped
4246 const SMDS_MeshNode* node = cast2Node( itN->next() );
4248 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4250 aXYZ.Coord( coord[0], coord[1], coord[2] );
4251 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4253 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4254 if ( nIt == mapNewNodes.end() ) {
4255 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4256 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4259 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4261 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4262 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4263 const SMDS_MeshNode * newNode = node;
4264 for ( int i = 0; i < theNbSteps; i++ ) {
4266 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4268 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4269 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4270 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4271 myLastCreatedNodes.Append(newNode);
4272 srcNodes.Append( node );
4273 listNewNodes.push_back( newNode );
4274 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4275 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4278 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4280 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4281 myLastCreatedNodes.Append(newNode);
4282 srcNodes.Append( node );
4283 listNewNodes.push_back( newNode );
4286 listNewNodes.push_back( newNode );
4287 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4288 listNewNodes.push_back( newNode );
4295 // if current elem is quadratic and current node is not medium
4296 // we have to check - may be it is needed to insert additional nodes
4297 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4298 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4299 if(listNewNodes.size()==theNbSteps) {
4300 listNewNodes.clear();
4302 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4304 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4305 const SMDS_MeshNode * newNode = node;
4307 for(int i = 0; i<theNbSteps; i++) {
4308 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4309 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4310 cout<<" 3 AddNode: "<<newNode;
4311 myLastCreatedNodes.Append(newNode);
4312 listNewNodes.push_back( newNode );
4313 srcNodes.Append( node );
4314 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4315 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4316 cout<<" 4 AddNode: "<<newNode;
4317 myLastCreatedNodes.Append(newNode);
4318 srcNodes.Append( node );
4319 listNewNodes.push_back( newNode );
4323 listNewNodes.push_back( newNode );
4329 newNodesItVec.push_back( nIt );
4331 // make new elements
4332 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4336 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4338 PGroupIDs newGroupIDs;
4339 if ( theMakeGroups )
4340 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4346 //=======================================================================
4347 //function : CreateNode
4349 //=======================================================================
4350 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4353 const double tolnode,
4354 SMESH_SequenceOfNode& aNodes)
4356 myLastCreatedElems.Clear();
4357 myLastCreatedNodes.Clear();
4360 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4362 // try to search in sequence of existing nodes
4363 // if aNodes.Length()>0 we 'nave to use given sequence
4364 // else - use all nodes of mesh
4365 if(aNodes.Length()>0) {
4367 for(i=1; i<=aNodes.Length(); i++) {
4368 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4369 if(P1.Distance(P2)<tolnode)
4370 return aNodes.Value(i);
4374 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4375 while(itn->more()) {
4376 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4377 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4378 if(P1.Distance(P2)<tolnode)
4383 // create new node and return it
4384 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4385 myLastCreatedNodes.Append(NewNode);
4390 //=======================================================================
4391 //function : ExtrusionSweep
4393 //=======================================================================
4395 SMESH_MeshEditor::PGroupIDs
4396 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4397 const gp_Vec& theStep,
4398 const int theNbSteps,
4399 TElemOfElemListMap& newElemsMap,
4400 const bool theMakeGroups,
4402 const double theTolerance)
4404 ExtrusParam aParams;
4405 aParams.myDir = gp_Dir(theStep);
4406 aParams.myNodes.Clear();
4407 aParams.mySteps = new TColStd_HSequenceOfReal;
4409 for(i=1; i<=theNbSteps; i++)
4410 aParams.mySteps->Append(theStep.Magnitude());
4413 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4417 //=======================================================================
4418 //function : ExtrusionSweep
4420 //=======================================================================
4422 SMESH_MeshEditor::PGroupIDs
4423 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4424 ExtrusParam& theParams,
4425 TElemOfElemListMap& newElemsMap,
4426 const bool theMakeGroups,
4428 const double theTolerance)
4430 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4431 myLastCreatedElems.Clear();
4432 myLastCreatedNodes.Clear();
4434 // source elements for each generated one
4435 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4437 SMESHDS_Mesh* aMesh = GetMeshDS();
4439 int nbsteps = theParams.mySteps->Length();
4441 TNodeOfNodeListMap mapNewNodes;
4442 //TNodeOfNodeVecMap mapNewNodes;
4443 TElemOfVecOfNnlmiMap mapElemNewNodes;
4444 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4447 TIDSortedElemSet::iterator itElem;
4448 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4449 // check element type
4450 const SMDS_MeshElement* elem = *itElem;
4451 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4454 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4455 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4456 newNodesItVec.reserve( elem->NbNodes() );
4458 // loop on elem nodes
4459 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4460 while ( itN->more() )
4462 // check if a node has been already sweeped
4463 const SMDS_MeshNode* node = cast2Node( itN->next() );
4464 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4465 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4466 if ( nIt == mapNewNodes.end() ) {
4467 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4468 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4469 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4470 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4471 //vecNewNodes.reserve(nbsteps);
4474 double coord[] = { node->X(), node->Y(), node->Z() };
4475 //int nbsteps = theParams.mySteps->Length();
4476 for ( int i = 0; i < nbsteps; i++ ) {
4477 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4478 // create additional node
4479 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4480 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4481 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4482 if( theFlags & EXTRUSION_FLAG_SEW ) {
4483 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4484 theTolerance, theParams.myNodes);
4485 listNewNodes.push_back( newNode );
4488 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4489 myLastCreatedNodes.Append(newNode);
4490 srcNodes.Append( node );
4491 listNewNodes.push_back( newNode );
4494 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4495 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4496 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4497 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4498 if( theFlags & EXTRUSION_FLAG_SEW ) {
4499 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4500 theTolerance, theParams.myNodes);
4501 listNewNodes.push_back( newNode );
4502 //vecNewNodes[i]=newNode;
4505 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4506 myLastCreatedNodes.Append(newNode);
4507 srcNodes.Append( node );
4508 listNewNodes.push_back( newNode );
4509 //vecNewNodes[i]=newNode;
4514 // if current elem is quadratic and current node is not medium
4515 // we have to check - may be it is needed to insert additional nodes
4516 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4517 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4518 if(listNewNodes.size()==nbsteps) {
4519 listNewNodes.clear();
4520 double coord[] = { node->X(), node->Y(), node->Z() };
4521 for ( int i = 0; i < nbsteps; i++ ) {
4522 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4523 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4524 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4525 if( theFlags & EXTRUSION_FLAG_SEW ) {
4526 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4527 theTolerance, theParams.myNodes);
4528 listNewNodes.push_back( newNode );
4531 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4532 myLastCreatedNodes.Append(newNode);
4533 srcNodes.Append( node );
4534 listNewNodes.push_back( newNode );
4536 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4537 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4538 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4539 if( theFlags & EXTRUSION_FLAG_SEW ) {
4540 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4541 theTolerance, theParams.myNodes);
4542 listNewNodes.push_back( newNode );
4545 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4546 myLastCreatedNodes.Append(newNode);
4547 srcNodes.Append( node );
4548 listNewNodes.push_back( newNode );
4554 newNodesItVec.push_back( nIt );
4556 // make new elements
4557 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4560 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4561 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4563 PGroupIDs newGroupIDs;
4564 if ( theMakeGroups )
4565 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4571 //=======================================================================
4572 //class : SMESH_MeshEditor_PathPoint
4573 //purpose : auxiliary class
4574 //=======================================================================
4575 class SMESH_MeshEditor_PathPoint {
4577 SMESH_MeshEditor_PathPoint() {
4578 myPnt.SetCoord(99., 99., 99.);
4579 myTgt.SetCoord(1.,0.,0.);
4583 void SetPnt(const gp_Pnt& aP3D){
4586 void SetTangent(const gp_Dir& aTgt){
4589 void SetAngle(const double& aBeta){
4592 void SetParameter(const double& aPrm){
4595 const gp_Pnt& Pnt()const{
4598 const gp_Dir& Tangent()const{
4601 double Angle()const{
4604 double Parameter()const{
4616 //=======================================================================
4617 //function : ExtrusionAlongTrack
4619 //=======================================================================
4620 SMESH_MeshEditor::Extrusion_Error
4621 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4622 SMESH_subMesh* theTrack,
4623 const SMDS_MeshNode* theN1,
4624 const bool theHasAngles,
4625 list<double>& theAngles,
4626 const bool theLinearVariation,
4627 const bool theHasRefPoint,
4628 const gp_Pnt& theRefPoint,
4629 const bool theMakeGroups)
4631 MESSAGE("ExtrusionAlongTrack");
4632 myLastCreatedElems.Clear();
4633 myLastCreatedNodes.Clear();
4636 std::list<double> aPrms;
4637 TIDSortedElemSet::iterator itElem;
4640 TopoDS_Edge aTrackEdge;
4641 TopoDS_Vertex aV1, aV2;
4643 SMDS_ElemIteratorPtr aItE;
4644 SMDS_NodeIteratorPtr aItN;
4645 SMDSAbs_ElementType aTypeE;
4647 TNodeOfNodeListMap mapNewNodes;
4650 aNbE = theElements.size();
4653 return EXTR_NO_ELEMENTS;
4655 // 1.1 Track Pattern
4658 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4660 aItE = pSubMeshDS->GetElements();
4661 while ( aItE->more() ) {
4662 const SMDS_MeshElement* pE = aItE->next();
4663 aTypeE = pE->GetType();
4664 // Pattern must contain links only
4665 if ( aTypeE != SMDSAbs_Edge )
4666 return EXTR_PATH_NOT_EDGE;
4669 list<SMESH_MeshEditor_PathPoint> fullList;
4671 const TopoDS_Shape& aS = theTrack->GetSubShape();
4672 // Sub shape for the Pattern must be an Edge or Wire
4673 if( aS.ShapeType() == TopAbs_EDGE ) {
4674 aTrackEdge = TopoDS::Edge( aS );
4675 // the Edge must not be degenerated
4676 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4677 return EXTR_BAD_PATH_SHAPE;
4678 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4679 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4680 const SMDS_MeshNode* aN1 = aItN->next();
4681 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4682 const SMDS_MeshNode* aN2 = aItN->next();
4683 // starting node must be aN1 or aN2
4684 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4685 return EXTR_BAD_STARTING_NODE;
4686 aItN = pSubMeshDS->GetNodes();
4687 while ( aItN->more() ) {
4688 const SMDS_MeshNode* pNode = aItN->next();
4689 const SMDS_EdgePosition* pEPos =
4690 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4691 double aT = pEPos->GetUParameter();
4692 aPrms.push_back( aT );
4694 //Extrusion_Error err =
4695 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4697 else if( aS.ShapeType() == TopAbs_WIRE ) {
4698 list< SMESH_subMesh* > LSM;
4699 TopTools_SequenceOfShape Edges;
4700 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4701 while(itSM->more()) {
4702 SMESH_subMesh* SM = itSM->next();
4704 const TopoDS_Shape& aS = SM->GetSubShape();
4707 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4708 int startNid = theN1->GetID();
4709 TColStd_MapOfInteger UsedNums;
4710 int NbEdges = Edges.Length();
4712 for(; i<=NbEdges; i++) {
4714 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4715 for(; itLSM!=LSM.end(); itLSM++) {
4717 if(UsedNums.Contains(k)) continue;
4718 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4719 SMESH_subMesh* locTrack = *itLSM;
4720 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4721 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4722 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4723 const SMDS_MeshNode* aN1 = aItN->next();
4724 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4725 const SMDS_MeshNode* aN2 = aItN->next();
4726 // starting node must be aN1 or aN2
4727 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4728 // 2. Collect parameters on the track edge
4730 aItN = locMeshDS->GetNodes();
4731 while ( aItN->more() ) {
4732 const SMDS_MeshNode* pNode = aItN->next();
4733 const SMDS_EdgePosition* pEPos =
4734 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4735 double aT = pEPos->GetUParameter();
4736 aPrms.push_back( aT );
4738 list<SMESH_MeshEditor_PathPoint> LPP;
4739 //Extrusion_Error err =
4740 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4741 LLPPs.push_back(LPP);
4743 // update startN for search following egde
4744 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4745 else startNid = aN1->GetID();
4749 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4750 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4751 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4752 for(; itPP!=firstList.end(); itPP++) {
4753 fullList.push_back( *itPP );
4755 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4756 fullList.pop_back();
4758 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4759 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4760 itPP = currList.begin();
4761 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4762 gp_Dir D1 = PP1.Tangent();
4763 gp_Dir D2 = PP2.Tangent();
4764 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4765 (D1.Z()+D2.Z())/2 ) );
4766 PP1.SetTangent(Dnew);
4767 fullList.push_back(PP1);
4769 for(; itPP!=firstList.end(); itPP++) {
4770 fullList.push_back( *itPP );
4772 PP1 = fullList.back();
4773 fullList.pop_back();
4775 // if wire not closed
4776 fullList.push_back(PP1);
4780 return EXTR_BAD_PATH_SHAPE;
4783 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4784 theHasRefPoint, theRefPoint, theMakeGroups);
4788 //=======================================================================
4789 //function : ExtrusionAlongTrack
4791 //=======================================================================
4792 SMESH_MeshEditor::Extrusion_Error
4793 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4794 SMESH_Mesh* theTrack,
4795 const SMDS_MeshNode* theN1,
4796 const bool theHasAngles,
4797 list<double>& theAngles,
4798 const bool theLinearVariation,
4799 const bool theHasRefPoint,
4800 const gp_Pnt& theRefPoint,
4801 const bool theMakeGroups)
4803 myLastCreatedElems.Clear();
4804 myLastCreatedNodes.Clear();
4807 std::list<double> aPrms;
4808 TIDSortedElemSet::iterator itElem;
4811 TopoDS_Edge aTrackEdge;
4812 TopoDS_Vertex aV1, aV2;
4814 SMDS_ElemIteratorPtr aItE;
4815 SMDS_NodeIteratorPtr aItN;
4816 SMDSAbs_ElementType aTypeE;
4818 TNodeOfNodeListMap mapNewNodes;
4821 aNbE = theElements.size();
4824 return EXTR_NO_ELEMENTS;
4826 // 1.1 Track Pattern
4829 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4831 aItE = pMeshDS->elementsIterator();
4832 while ( aItE->more() ) {
4833 const SMDS_MeshElement* pE = aItE->next();
4834 aTypeE = pE->GetType();
4835 // Pattern must contain links only
4836 if ( aTypeE != SMDSAbs_Edge )
4837 return EXTR_PATH_NOT_EDGE;
4840 list<SMESH_MeshEditor_PathPoint> fullList;
4842 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4843 // Sub shape for the Pattern must be an Edge or Wire
4844 if( aS.ShapeType() == TopAbs_EDGE ) {
4845 aTrackEdge = TopoDS::Edge( aS );
4846 // the Edge must not be degenerated
4847 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4848 return EXTR_BAD_PATH_SHAPE;
4849 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4850 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4851 const SMDS_MeshNode* aN1 = aItN->next();
4852 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4853 const SMDS_MeshNode* aN2 = aItN->next();
4854 // starting node must be aN1 or aN2
4855 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4856 return EXTR_BAD_STARTING_NODE;
4857 aItN = pMeshDS->nodesIterator();
4858 while ( aItN->more() ) {
4859 const SMDS_MeshNode* pNode = aItN->next();
4860 if( pNode==aN1 || pNode==aN2 ) continue;
4861 const SMDS_EdgePosition* pEPos =
4862 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4863 double aT = pEPos->GetUParameter();
4864 aPrms.push_back( aT );
4866 //Extrusion_Error err =
4867 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4869 else if( aS.ShapeType() == TopAbs_WIRE ) {
4870 list< SMESH_subMesh* > LSM;
4871 TopTools_SequenceOfShape Edges;
4872 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4873 for(; eExp.More(); eExp.Next()) {
4874 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4875 if( BRep_Tool::Degenerated(E) ) continue;
4876 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4882 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4883 int startNid = theN1->GetID();
4884 TColStd_MapOfInteger UsedNums;
4885 int NbEdges = Edges.Length();
4887 for(; i<=NbEdges; i++) {
4889 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4890 for(; itLSM!=LSM.end(); itLSM++) {
4892 if(UsedNums.Contains(k)) continue;
4893 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4894 SMESH_subMesh* locTrack = *itLSM;
4895 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4896 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4897 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4898 const SMDS_MeshNode* aN1 = aItN->next();
4899 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4900 const SMDS_MeshNode* aN2 = aItN->next();
4901 // starting node must be aN1 or aN2
4902 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4903 // 2. Collect parameters on the track edge
4905 aItN = locMeshDS->GetNodes();
4906 while ( aItN->more() ) {
4907 const SMDS_MeshNode* pNode = aItN->next();
4908 const SMDS_EdgePosition* pEPos =
4909 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4910 double aT = pEPos->GetUParameter();
4911 aPrms.push_back( aT );
4913 list<SMESH_MeshEditor_PathPoint> LPP;
4914 //Extrusion_Error err =
4915 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4916 LLPPs.push_back(LPP);
4918 // update startN for search following egde
4919 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4920 else startNid = aN1->GetID();
4924 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4925 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4926 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4927 for(; itPP!=firstList.end(); itPP++) {
4928 fullList.push_back( *itPP );
4930 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4931 fullList.pop_back();
4933 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4934 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4935 itPP = currList.begin();
4936 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4937 gp_Pnt P1 = PP1.Pnt();
4938 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4939 gp_Pnt P2 = PP2.Pnt();
4940 gp_Dir D1 = PP1.Tangent();
4941 gp_Dir D2 = PP2.Tangent();
4942 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4943 (D1.Z()+D2.Z())/2 ) );
4944 PP1.SetTangent(Dnew);
4945 fullList.push_back(PP1);
4947 for(; itPP!=currList.end(); itPP++) {
4948 fullList.push_back( *itPP );
4950 PP1 = fullList.back();
4951 fullList.pop_back();
4953 // if wire not closed
4954 fullList.push_back(PP1);
4958 return EXTR_BAD_PATH_SHAPE;
4961 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4962 theHasRefPoint, theRefPoint, theMakeGroups);
4966 //=======================================================================
4967 //function : MakeEdgePathPoints
4968 //purpose : auxilary for ExtrusionAlongTrack
4969 //=======================================================================
4970 SMESH_MeshEditor::Extrusion_Error
4971 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4972 const TopoDS_Edge& aTrackEdge,
4974 list<SMESH_MeshEditor_PathPoint>& LPP)
4976 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4978 aTolVec2=aTolVec*aTolVec;
4980 TopoDS_Vertex aV1, aV2;
4981 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4982 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4983 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4984 // 2. Collect parameters on the track edge
4985 aPrms.push_front( aT1 );
4986 aPrms.push_back( aT2 );
4989 if( FirstIsStart ) {
5000 SMESH_MeshEditor_PathPoint aPP;
5001 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
5002 std::list<double>::iterator aItD = aPrms.begin();
5003 for(; aItD != aPrms.end(); ++aItD) {
5007 aC3D->D1( aT, aP3D, aVec );
5008 aL2 = aVec.SquareMagnitude();
5009 if ( aL2 < aTolVec2 )
5010 return EXTR_CANT_GET_TANGENT;
5011 gp_Dir aTgt( aVec );
5013 aPP.SetTangent( aTgt );
5014 aPP.SetParameter( aT );
5021 //=======================================================================
5022 //function : MakeExtrElements
5023 //purpose : auxilary for ExtrusionAlongTrack
5024 //=======================================================================
5025 SMESH_MeshEditor::Extrusion_Error
5026 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5027 list<SMESH_MeshEditor_PathPoint>& fullList,
5028 const bool theHasAngles,
5029 list<double>& theAngles,
5030 const bool theLinearVariation,
5031 const bool theHasRefPoint,
5032 const gp_Pnt& theRefPoint,
5033 const bool theMakeGroups)
5035 MESSAGE("MakeExtrElements");
5036 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5037 int aNbTP = fullList.size();
5038 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5040 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5041 LinearAngleVariation(aNbTP-1, theAngles);
5043 vector<double> aAngles( aNbTP );
5045 for(; j<aNbTP; ++j) {
5048 if ( theHasAngles ) {
5050 std::list<double>::iterator aItD = theAngles.begin();
5051 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5053 aAngles[j] = anAngle;
5056 // fill vector of path points with angles
5057 //aPPs.resize(fullList.size());
5059 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5060 for(; itPP!=fullList.end(); itPP++) {
5062 SMESH_MeshEditor_PathPoint PP = *itPP;
5063 PP.SetAngle(aAngles[j]);
5067 TNodeOfNodeListMap mapNewNodes;
5068 TElemOfVecOfNnlmiMap mapElemNewNodes;
5069 TElemOfElemListMap newElemsMap;
5070 TIDSortedElemSet::iterator itElem;
5073 SMDSAbs_ElementType aTypeE;
5074 // source elements for each generated one
5075 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5077 // 3. Center of rotation aV0
5078 gp_Pnt aV0 = theRefPoint;
5080 if ( !theHasRefPoint ) {
5082 aGC.SetCoord( 0.,0.,0. );
5084 itElem = theElements.begin();
5085 for ( ; itElem != theElements.end(); itElem++ ) {
5086 const SMDS_MeshElement* elem = *itElem;
5088 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5089 while ( itN->more() ) {
5090 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5095 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5096 list<const SMDS_MeshNode*> aLNx;
5097 mapNewNodes[node] = aLNx;
5099 gp_XYZ aXYZ( aX, aY, aZ );
5107 } // if (!theHasRefPoint) {
5108 mapNewNodes.clear();
5110 // 4. Processing the elements
5111 SMESHDS_Mesh* aMesh = GetMeshDS();
5113 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5114 // check element type
5115 const SMDS_MeshElement* elem = *itElem;
5116 aTypeE = elem->GetType();
5117 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5120 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5121 newNodesItVec.reserve( elem->NbNodes() );
5123 // loop on elem nodes
5125 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5126 while ( itN->more() )
5129 // check if a node has been already processed
5130 const SMDS_MeshNode* node =
5131 static_cast<const SMDS_MeshNode*>( itN->next() );
5132 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5133 if ( nIt == mapNewNodes.end() ) {
5134 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5135 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5138 aX = node->X(); aY = node->Y(); aZ = node->Z();
5140 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5141 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5142 gp_Ax1 anAx1, anAxT1T0;
5143 gp_Dir aDT1x, aDT0x, aDT1T0;
5148 aPN0.SetCoord(aX, aY, aZ);
5150 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5152 aDT0x= aPP0.Tangent();
5153 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5155 for ( j = 1; j < aNbTP; ++j ) {
5156 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5158 aDT1x = aPP1.Tangent();
5159 aAngle1x = aPP1.Angle();
5161 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5163 gp_Vec aV01x( aP0x, aP1x );
5164 aTrsf.SetTranslation( aV01x );
5167 aV1x = aV0x.Transformed( aTrsf );
5168 aPN1 = aPN0.Transformed( aTrsf );
5170 // rotation 1 [ T1,T0 ]
5171 aAngleT1T0=-aDT1x.Angle( aDT0x );
5172 if (fabs(aAngleT1T0) > aTolAng) {
5174 anAxT1T0.SetLocation( aV1x );
5175 anAxT1T0.SetDirection( aDT1T0 );
5176 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5178 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5182 if ( theHasAngles ) {
5183 anAx1.SetLocation( aV1x );
5184 anAx1.SetDirection( aDT1x );
5185 aTrsfRot.SetRotation( anAx1, aAngle1x );
5187 aPN1 = aPN1.Transformed( aTrsfRot );
5191 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5192 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5193 // create additional node
5194 double x = ( aPN1.X() + aPN0.X() )/2.;
5195 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5196 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5197 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5198 myLastCreatedNodes.Append(newNode);
5199 srcNodes.Append( node );
5200 listNewNodes.push_back( newNode );
5205 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5206 myLastCreatedNodes.Append(newNode);
5207 srcNodes.Append( node );
5208 listNewNodes.push_back( newNode );
5218 // if current elem is quadratic and current node is not medium
5219 // we have to check - may be it is needed to insert additional nodes
5220 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5221 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5222 if(listNewNodes.size()==aNbTP-1) {
5223 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5224 gp_XYZ P(node->X(), node->Y(), node->Z());
5225 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5227 for(i=0; i<aNbTP-1; i++) {
5228 const SMDS_MeshNode* N = *it;
5229 double x = ( N->X() + P.X() )/2.;
5230 double y = ( N->Y() + P.Y() )/2.;
5231 double z = ( N->Z() + P.Z() )/2.;
5232 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5233 srcNodes.Append( node );
5234 myLastCreatedNodes.Append(newN);
5237 P = gp_XYZ(N->X(),N->Y(),N->Z());
5239 listNewNodes.clear();
5240 for(i=0; i<2*(aNbTP-1); i++) {
5241 listNewNodes.push_back(aNodes[i]);
5247 newNodesItVec.push_back( nIt );
5249 // make new elements
5250 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5251 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5252 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5255 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5257 if ( theMakeGroups )
5258 generateGroups( srcNodes, srcElems, "extruded");
5264 //=======================================================================
5265 //function : LinearAngleVariation
5266 //purpose : auxilary for ExtrusionAlongTrack
5267 //=======================================================================
5268 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5269 list<double>& Angles)
5271 int nbAngles = Angles.size();
5272 if( nbSteps > nbAngles ) {
5273 vector<double> theAngles(nbAngles);
5274 list<double>::iterator it = Angles.begin();
5276 for(; it!=Angles.end(); it++) {
5278 theAngles[i] = (*it);
5281 double rAn2St = double( nbAngles ) / double( nbSteps );
5282 double angPrev = 0, angle;
5283 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5284 double angCur = rAn2St * ( iSt+1 );
5285 double angCurFloor = floor( angCur );
5286 double angPrevFloor = floor( angPrev );
5287 if ( angPrevFloor == angCurFloor )
5288 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5290 int iP = int( angPrevFloor );
5291 double angPrevCeil = ceil(angPrev);
5292 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5294 int iC = int( angCurFloor );
5295 if ( iC < nbAngles )
5296 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5298 iP = int( angPrevCeil );
5300 angle += theAngles[ iC ];
5302 res.push_back(angle);
5307 for(; it!=res.end(); it++)
5308 Angles.push_back( *it );
5313 //================================================================================
5315 * \brief Move or copy theElements applying theTrsf to their nodes
5316 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5317 * \param theTrsf - transformation to apply
5318 * \param theCopy - if true, create translated copies of theElems
5319 * \param theMakeGroups - if true and theCopy, create translated groups
5320 * \param theTargetMesh - mesh to copy translated elements into
5321 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5323 //================================================================================
5325 SMESH_MeshEditor::PGroupIDs
5326 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5327 const gp_Trsf& theTrsf,
5329 const bool theMakeGroups,
5330 SMESH_Mesh* theTargetMesh)
5332 myLastCreatedElems.Clear();
5333 myLastCreatedNodes.Clear();
5335 bool needReverse = false;
5336 string groupPostfix;
5337 switch ( theTrsf.Form() ) {
5339 MESSAGE("gp_PntMirror");
5341 groupPostfix = "mirrored";
5344 MESSAGE("gp_Ax1Mirror");
5345 groupPostfix = "mirrored";
5348 MESSAGE("gp_Ax2Mirror");
5350 groupPostfix = "mirrored";
5353 MESSAGE("gp_Rotation");
5354 groupPostfix = "rotated";
5356 case gp_Translation:
5357 MESSAGE("gp_Translation");
5358 groupPostfix = "translated";
5361 MESSAGE("gp_Scale");
5362 groupPostfix = "scaled";
5364 case gp_CompoundTrsf: // different scale by axis
5365 MESSAGE("gp_CompoundTrsf");
5366 groupPostfix = "scaled";
5370 needReverse = false;
5371 groupPostfix = "transformed";
5374 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5375 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5376 SMESHDS_Mesh* aMesh = GetMeshDS();
5379 // map old node to new one
5380 TNodeNodeMap nodeMap;
5382 // elements sharing moved nodes; those of them which have all
5383 // nodes mirrored but are not in theElems are to be reversed
5384 TIDSortedElemSet inverseElemSet;
5386 // source elements for each generated one
5387 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5389 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5390 TIDSortedElemSet orphanNode;
5392 if ( theElems.empty() ) // transform the whole mesh
5395 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5396 while ( eIt->more() ) theElems.insert( eIt->next() );
5398 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5399 while ( nIt->more() )
5401 const SMDS_MeshNode* node = nIt->next();
5402 if ( node->NbInverseElements() == 0)
5403 orphanNode.insert( node );
5407 // loop on elements to transform nodes : first orphan nodes then elems
5408 TIDSortedElemSet::iterator itElem;
5409 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5410 for (int i=0; i<2; i++)
5411 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5412 const SMDS_MeshElement* elem = *itElem;
5416 // loop on elem nodes
5417 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5418 while ( itN->more() ) {
5420 const SMDS_MeshNode* node = cast2Node( itN->next() );
5421 // check if a node has been already transformed
5422 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5423 nodeMap.insert( make_pair ( node, node ));
5424 if ( !n2n_isnew.second )
5428 coord[0] = node->X();
5429 coord[1] = node->Y();
5430 coord[2] = node->Z();
5431 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5432 if ( theTargetMesh ) {
5433 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5434 n2n_isnew.first->second = newNode;
5435 myLastCreatedNodes.Append(newNode);
5436 srcNodes.Append( node );
5438 else if ( theCopy ) {
5439 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5440 n2n_isnew.first->second = newNode;
5441 myLastCreatedNodes.Append(newNode);
5442 srcNodes.Append( node );
5445 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5446 // node position on shape becomes invalid
5447 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5448 ( SMDS_SpacePosition::originSpacePosition() );
5451 // keep inverse elements
5452 if ( !theCopy && !theTargetMesh && needReverse ) {
5453 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5454 while ( invElemIt->more() ) {
5455 const SMDS_MeshElement* iel = invElemIt->next();
5456 inverseElemSet.insert( iel );
5462 // either create new elements or reverse mirrored ones
5463 if ( !theCopy && !needReverse && !theTargetMesh )
5466 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5467 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5468 theElems.insert( *invElemIt );
5470 // replicate or reverse elements
5471 // TODO revoir ordre reverse vtk
5473 REV_TETRA = 0, // = nbNodes - 4
5474 REV_PYRAMID = 1, // = nbNodes - 4
5475 REV_PENTA = 2, // = nbNodes - 4
5477 REV_HEXA = 4, // = nbNodes - 4
5481 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5482 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5483 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5484 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5485 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5486 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5489 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5491 const SMDS_MeshElement* elem = *itElem;
5492 if ( !elem || elem->GetType() == SMDSAbs_Node )
5495 int nbNodes = elem->NbNodes();
5496 int elemType = elem->GetType();
5498 if (elem->IsPoly()) {
5499 // Polygon or Polyhedral Volume
5500 switch ( elemType ) {
5503 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5505 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5506 while (itN->more()) {
5507 const SMDS_MeshNode* node =
5508 static_cast<const SMDS_MeshNode*>(itN->next());
5509 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5510 if (nodeMapIt == nodeMap.end())
5511 break; // not all nodes transformed
5513 // reverse mirrored faces and volumes
5514 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5516 poly_nodes[iNode] = (*nodeMapIt).second;
5520 if ( iNode != nbNodes )
5521 continue; // not all nodes transformed
5523 if ( theTargetMesh ) {
5524 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5525 srcElems.Append( elem );
5527 else if ( theCopy ) {
5528 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5529 srcElems.Append( elem );
5532 aMesh->ChangePolygonNodes(elem, poly_nodes);
5536 case SMDSAbs_Volume:
5538 // ATTENTION: Reversing is not yet done!!!
5539 const SMDS_VtkVolume* aPolyedre =
5540 dynamic_cast<const SMDS_VtkVolume*>( elem );
5542 MESSAGE("Warning: bad volumic element");
5546 vector<const SMDS_MeshNode*> poly_nodes;
5547 vector<int> quantities;
5549 bool allTransformed = true;
5550 int nbFaces = aPolyedre->NbFaces();
5551 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5552 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5553 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5554 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5555 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5556 if (nodeMapIt == nodeMap.end()) {
5557 allTransformed = false; // not all nodes transformed
5559 poly_nodes.push_back((*nodeMapIt).second);
5562 quantities.push_back(nbFaceNodes);
5564 if ( !allTransformed )
5565 continue; // not all nodes transformed
5567 if ( theTargetMesh ) {
5568 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5569 srcElems.Append( elem );
5571 else if ( theCopy ) {
5572 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5573 srcElems.Append( elem );
5576 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5586 int* i = index[ FORWARD ];
5587 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5588 if ( elemType == SMDSAbs_Face )
5589 i = index[ REV_FACE ];
5591 i = index[ nbNodes - 4 ];
5593 if(elem->IsQuadratic()) {
5594 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5597 if(nbNodes==3) { // quadratic edge
5598 static int anIds[] = {1,0,2};
5601 else if(nbNodes==6) { // quadratic triangle
5602 static int anIds[] = {0,2,1,5,4,3};
5605 else if(nbNodes==8) { // quadratic quadrangle
5606 static int anIds[] = {0,3,2,1,7,6,5,4};
5609 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5610 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5613 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5614 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5617 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5618 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5621 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5622 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5628 // find transformed nodes
5629 vector<const SMDS_MeshNode*> nodes(nbNodes);
5631 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5632 while ( itN->more() ) {
5633 const SMDS_MeshNode* node =
5634 static_cast<const SMDS_MeshNode*>( itN->next() );
5635 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5636 if ( nodeMapIt == nodeMap.end() )
5637 break; // not all nodes transformed
5638 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5640 if ( iNode != nbNodes )
5641 continue; // not all nodes transformed
5643 if ( theTargetMesh ) {
5644 if ( SMDS_MeshElement* copy =
5645 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5646 myLastCreatedElems.Append( copy );
5647 srcElems.Append( elem );
5650 else if ( theCopy ) {
5651 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5652 srcElems.Append( elem );
5655 // reverse element as it was reversed by transformation
5657 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5661 PGroupIDs newGroupIDs;
5663 if ( theMakeGroups && theCopy ||
5664 theMakeGroups && theTargetMesh )
5665 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5671 ////=======================================================================
5672 ////function : Scale
5674 ////=======================================================================
5676 //SMESH_MeshEditor::PGroupIDs
5677 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5678 // const gp_Pnt& thePoint,
5679 // const std::list<double>& theScaleFact,
5680 // const bool theCopy,
5681 // const bool theMakeGroups,
5682 // SMESH_Mesh* theTargetMesh)
5684 // MESSAGE("Scale");
5685 // myLastCreatedElems.Clear();
5686 // myLastCreatedNodes.Clear();
5688 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5689 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5690 // SMESHDS_Mesh* aMesh = GetMeshDS();
5692 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5693 // std::list<double>::const_iterator itS = theScaleFact.begin();
5695 // if(theScaleFact.size()==1) {
5699 // if(theScaleFact.size()==2) {
5704 // if(theScaleFact.size()>2) {
5711 // // map old node to new one
5712 // TNodeNodeMap nodeMap;
5714 // // elements sharing moved nodes; those of them which have all
5715 // // nodes mirrored but are not in theElems are to be reversed
5716 // TIDSortedElemSet inverseElemSet;
5718 // // source elements for each generated one
5719 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5721 // // loop on theElems
5722 // TIDSortedElemSet::iterator itElem;
5723 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5724 // const SMDS_MeshElement* elem = *itElem;
5728 // // loop on elem nodes
5729 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5730 // while ( itN->more() ) {
5732 // // check if a node has been already transformed
5733 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5734 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5735 // nodeMap.insert( make_pair ( node, node ));
5736 // if ( !n2n_isnew.second )
5739 // //double coord[3];
5740 // //coord[0] = node->X();
5741 // //coord[1] = node->Y();
5742 // //coord[2] = node->Z();
5743 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5744 // double dx = (node->X() - thePoint.X()) * scaleX;
5745 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5746 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5747 // if ( theTargetMesh ) {
5748 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5749 // const SMDS_MeshNode * newNode =
5750 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5751 // n2n_isnew.first->second = newNode;
5752 // myLastCreatedNodes.Append(newNode);
5753 // srcNodes.Append( node );
5755 // else if ( theCopy ) {
5756 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5757 // const SMDS_MeshNode * newNode =
5758 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5759 // n2n_isnew.first->second = newNode;
5760 // myLastCreatedNodes.Append(newNode);
5761 // srcNodes.Append( node );
5764 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5765 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5766 // // node position on shape becomes invalid
5767 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5768 // ( SMDS_SpacePosition::originSpacePosition() );
5771 // // keep inverse elements
5772 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5773 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5774 // // while ( invElemIt->more() ) {
5775 // // const SMDS_MeshElement* iel = invElemIt->next();
5776 // // inverseElemSet.insert( iel );
5782 // // either create new elements or reverse mirrored ones
5783 // //if ( !theCopy && !needReverse && !theTargetMesh )
5784 // if ( !theCopy && !theTargetMesh )
5785 // return PGroupIDs();
5787 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5788 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5789 // theElems.insert( *invElemIt );
5791 // // replicate or reverse elements
5794 // REV_TETRA = 0, // = nbNodes - 4
5795 // REV_PYRAMID = 1, // = nbNodes - 4
5796 // REV_PENTA = 2, // = nbNodes - 4
5798 // REV_HEXA = 4, // = nbNodes - 4
5801 // int index[][8] = {
5802 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5803 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5804 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5805 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5806 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5807 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5810 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5812 // const SMDS_MeshElement* elem = *itElem;
5813 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5816 // int nbNodes = elem->NbNodes();
5817 // int elemType = elem->GetType();
5819 // if (elem->IsPoly()) {
5820 // // Polygon or Polyhedral Volume
5821 // switch ( elemType ) {
5822 // case SMDSAbs_Face:
5824 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5826 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5827 // while (itN->more()) {
5828 // const SMDS_MeshNode* node =
5829 // static_cast<const SMDS_MeshNode*>(itN->next());
5830 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5831 // if (nodeMapIt == nodeMap.end())
5832 // break; // not all nodes transformed
5833 // //if (needReverse) {
5834 // // // reverse mirrored faces and volumes
5835 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5837 // poly_nodes[iNode] = (*nodeMapIt).second;
5841 // if ( iNode != nbNodes )
5842 // continue; // not all nodes transformed
5844 // if ( theTargetMesh ) {
5845 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5846 // srcElems.Append( elem );
5848 // else if ( theCopy ) {
5849 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5850 // srcElems.Append( elem );
5853 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5857 // case SMDSAbs_Volume:
5859 // // ATTENTION: Reversing is not yet done!!!
5860 // const SMDS_VtkVolume* aPolyedre =
5861 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5862 // if (!aPolyedre) {
5863 // MESSAGE("Warning: bad volumic element");
5867 // vector<const SMDS_MeshNode*> poly_nodes;
5868 // vector<int> quantities;
5870 // bool allTransformed = true;
5871 // int nbFaces = aPolyedre->NbFaces();
5872 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5873 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5874 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5875 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5876 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5877 // if (nodeMapIt == nodeMap.end()) {
5878 // allTransformed = false; // not all nodes transformed
5880 // poly_nodes.push_back((*nodeMapIt).second);
5883 // quantities.push_back(nbFaceNodes);
5885 // if ( !allTransformed )
5886 // continue; // not all nodes transformed
5888 // if ( theTargetMesh ) {
5889 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5890 // srcElems.Append( elem );
5892 // else if ( theCopy ) {
5893 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5894 // srcElems.Append( elem );
5897 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5906 // // Regular elements
5907 // int* i = index[ FORWARD ];
5908 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5909 // // if ( elemType == SMDSAbs_Face )
5910 // // i = index[ REV_FACE ];
5912 // // i = index[ nbNodes - 4 ];
5914 // if(elem->IsQuadratic()) {
5915 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5917 // //if(needReverse) {
5918 // // if(nbNodes==3) { // quadratic edge
5919 // // static int anIds[] = {1,0,2};
5922 // // else if(nbNodes==6) { // quadratic triangle
5923 // // static int anIds[] = {0,2,1,5,4,3};
5926 // // else if(nbNodes==8) { // quadratic quadrangle
5927 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5930 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5931 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5934 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5935 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5938 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5939 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5942 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5943 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5949 // // find transformed nodes
5950 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5952 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5953 // while ( itN->more() ) {
5954 // const SMDS_MeshNode* node =
5955 // static_cast<const SMDS_MeshNode*>( itN->next() );
5956 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5957 // if ( nodeMapIt == nodeMap.end() )
5958 // break; // not all nodes transformed
5959 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5961 // if ( iNode != nbNodes )
5962 // continue; // not all nodes transformed
5964 // if ( theTargetMesh ) {
5965 // if ( SMDS_MeshElement* copy =
5966 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5967 // myLastCreatedElems.Append( copy );
5968 // srcElems.Append( elem );
5971 // else if ( theCopy ) {
5972 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5973 // myLastCreatedElems.Append( copy );
5974 // srcElems.Append( elem );
5978 // // reverse element as it was reversed by transformation
5979 // if ( nbNodes > 2 )
5980 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5984 // PGroupIDs newGroupIDs;
5986 // if ( theMakeGroups && theCopy ||
5987 // theMakeGroups && theTargetMesh ) {
5988 // string groupPostfix = "scaled";
5989 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5992 // return newGroupIDs;
5996 //=======================================================================
5998 * \brief Create groups of elements made during transformation
5999 * \param nodeGens - nodes making corresponding myLastCreatedNodes
6000 * \param elemGens - elements making corresponding myLastCreatedElems
6001 * \param postfix - to append to names of new groups
6003 //=======================================================================
6005 SMESH_MeshEditor::PGroupIDs
6006 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
6007 const SMESH_SequenceOfElemPtr& elemGens,
6008 const std::string& postfix,
6009 SMESH_Mesh* targetMesh)
6011 PGroupIDs newGroupIDs( new list<int> );
6012 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6014 // Sort existing groups by types and collect their names
6016 // to store an old group and a generated new one
6017 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6018 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6020 set< string > groupNames;
6022 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6023 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6024 while ( groupIt->more() ) {
6025 SMESH_Group * group = groupIt->next();
6026 if ( !group ) continue;
6027 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6028 if ( !groupDS || groupDS->IsEmpty() ) continue;
6029 groupNames.insert( group->GetName() );
6030 groupDS->SetStoreName( group->GetName() );
6031 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6036 // loop on nodes and elements
6037 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6039 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6040 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6041 if ( gens.Length() != elems.Length() )
6042 throw SALOME_Exception(LOCALIZED("invalid args"));
6044 // loop on created elements
6045 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6047 const SMDS_MeshElement* sourceElem = gens( iElem );
6048 if ( !sourceElem ) {
6049 MESSAGE("generateGroups(): NULL source element");
6052 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6053 if ( groupsOldNew.empty() ) {
6054 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6055 ++iElem; // skip all elements made by sourceElem
6058 // collect all elements made by sourceElem
6059 list< const SMDS_MeshElement* > resultElems;
6060 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6061 if ( resElem != sourceElem )
6062 resultElems.push_back( resElem );
6063 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6064 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6065 if ( resElem != sourceElem )
6066 resultElems.push_back( resElem );
6067 // do not generate element groups from node ones
6068 if ( sourceElem->GetType() == SMDSAbs_Node &&
6069 elems( iElem )->GetType() != SMDSAbs_Node )
6072 // add resultElems to groups made by ones the sourceElem belongs to
6073 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6074 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6076 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6077 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6079 SMDS_MeshGroup* & newGroup = gOldNew->second;
6080 if ( !newGroup )// create a new group
6083 string name = oldGroup->GetStoreName();
6084 if ( !targetMesh ) {
6088 while ( !groupNames.insert( name ).second ) // name exists
6094 TCollection_AsciiString nbStr(nb+1);
6095 name.resize( name.rfind('_')+1 );
6096 name += nbStr.ToCString();
6103 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6105 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6106 newGroup = & groupDS->SMDSGroup();
6107 newGroupIDs->push_back( id );
6110 // fill in a new group
6111 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6112 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6113 newGroup->Add( *resElemIt );
6116 } // loop on created elements
6117 }// loop on nodes and elements
6122 //================================================================================
6124 * \brief Return list of group of nodes close to each other within theTolerance
6125 * Search among theNodes or in the whole mesh if theNodes is empty using
6126 * an Octree algorithm
6128 //================================================================================
6130 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6131 const double theTolerance,
6132 TListOfListOfNodes & theGroupsOfNodes)
6134 myLastCreatedElems.Clear();
6135 myLastCreatedNodes.Clear();
6137 if ( theNodes.empty() )
6138 { // get all nodes in the mesh
6139 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6140 while ( nIt->more() )
6141 theNodes.insert( theNodes.end(),nIt->next());
6144 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6148 //=======================================================================
6150 * \brief Implementation of search for the node closest to point
6152 //=======================================================================
6154 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6156 //---------------------------------------------------------------------
6158 * \brief Constructor
6160 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6162 myMesh = ( SMESHDS_Mesh* ) theMesh;
6164 TIDSortedNodeSet nodes;
6166 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6167 while ( nIt->more() )
6168 nodes.insert( nodes.end(), nIt->next() );
6170 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6172 // get max size of a leaf box
6173 SMESH_OctreeNode* tree = myOctreeNode;
6174 while ( !tree->isLeaf() )
6176 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6180 myHalfLeafSize = tree->maxSize() / 2.;
6183 //---------------------------------------------------------------------
6185 * \brief Move node and update myOctreeNode accordingly
6187 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6189 myOctreeNode->UpdateByMoveNode( node, toPnt );
6190 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6193 //---------------------------------------------------------------------
6195 * \brief Do it's job
6197 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6199 map<double, const SMDS_MeshNode*> dist2Nodes;
6200 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6201 if ( !dist2Nodes.empty() )
6202 return dist2Nodes.begin()->second;
6203 list<const SMDS_MeshNode*> nodes;
6204 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6206 double minSqDist = DBL_MAX;
6207 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6209 // sort leafs by their distance from thePnt
6210 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6211 TDistTreeMap treeMap;
6212 list< SMESH_OctreeNode* > treeList;
6213 list< SMESH_OctreeNode* >::iterator trIt;
6214 treeList.push_back( myOctreeNode );
6216 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6217 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6218 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6220 SMESH_OctreeNode* tree = *trIt;
6221 if ( !tree->isLeaf() ) // put children to the queue
6223 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6224 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6225 while ( cIt->more() )
6226 treeList.push_back( cIt->next() );
6228 else if ( tree->NbNodes() ) // put a tree to the treeMap
6230 const Bnd_B3d& box = tree->getBox();
6231 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6232 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6233 if ( !it_in.second ) // not unique distance to box center
6234 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6237 // find distance after which there is no sense to check tree's
6238 double sqLimit = DBL_MAX;
6239 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6240 if ( treeMap.size() > 5 ) {
6241 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6242 const Bnd_B3d& box = closestTree->getBox();
6243 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6244 sqLimit = limit * limit;
6246 // get all nodes from trees
6247 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6248 if ( sqDist_tree->first > sqLimit )
6250 SMESH_OctreeNode* tree = sqDist_tree->second;
6251 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6254 // find closest among nodes
6255 minSqDist = DBL_MAX;
6256 const SMDS_MeshNode* closestNode = 0;
6257 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6258 for ( ; nIt != nodes.end(); ++nIt ) {
6259 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6260 if ( minSqDist > sqDist ) {
6268 //---------------------------------------------------------------------
6272 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6274 //---------------------------------------------------------------------
6276 * \brief Return the node tree
6278 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6281 SMESH_OctreeNode* myOctreeNode;
6282 SMESHDS_Mesh* myMesh;
6283 double myHalfLeafSize; // max size of a leaf box
6286 //=======================================================================
6288 * \brief Return SMESH_NodeSearcher
6290 //=======================================================================
6292 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6294 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6297 // ========================================================================
6298 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6300 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6301 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6302 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6304 //=======================================================================
6306 * \brief Octal tree of bounding boxes of elements
6308 //=======================================================================
6310 class ElementBndBoxTree : public SMESH_Octree
6314 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6315 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6316 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6317 ~ElementBndBoxTree();
6320 ElementBndBoxTree() {}
6321 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6322 void buildChildrenData();
6323 Bnd_B3d* buildRootBox();
6325 //!< Bounding box of element
6326 struct ElementBox : public Bnd_B3d
6328 const SMDS_MeshElement* _element;
6329 int _refCount; // an ElementBox can be included in several tree branches
6330 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6332 vector< ElementBox* > _elements;
6335 //================================================================================
6337 * \brief ElementBndBoxTree creation
6339 //================================================================================
6341 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6342 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6344 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6345 _elements.reserve( nbElems );
6347 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6348 while ( elemIt->more() )
6349 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6351 if ( _elements.size() > MaxNbElemsInLeaf )
6357 //================================================================================
6361 //================================================================================
6363 ElementBndBoxTree::~ElementBndBoxTree()
6365 for ( int i = 0; i < _elements.size(); ++i )
6366 if ( --_elements[i]->_refCount <= 0 )
6367 delete _elements[i];
6370 //================================================================================
6372 * \brief Return the maximal box
6374 //================================================================================
6376 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6378 Bnd_B3d* box = new Bnd_B3d;
6379 for ( int i = 0; i < _elements.size(); ++i )
6380 box->Add( *_elements[i] );
6384 //================================================================================
6386 * \brief Redistrubute element boxes among children
6388 //================================================================================
6390 void ElementBndBoxTree::buildChildrenData()
6392 for ( int i = 0; i < _elements.size(); ++i )
6394 for (int j = 0; j < 8; j++)
6396 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6398 _elements[i]->_refCount++;
6399 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6402 _elements[i]->_refCount--;
6406 for (int j = 0; j < 8; j++)
6408 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6409 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6410 child->myIsLeaf = true;
6412 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6413 child->_elements.resize( child->_elements.size() ); // compact
6417 //================================================================================
6419 * \brief Return elements which can include the point
6421 //================================================================================
6423 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6424 TIDSortedElemSet& foundElems)
6426 if ( level() && getBox().IsOut( point.XYZ() ))
6431 for ( int i = 0; i < _elements.size(); ++i )
6432 if ( !_elements[i]->IsOut( point.XYZ() ))
6433 foundElems.insert( _elements[i]->_element );
6437 for (int i = 0; i < 8; i++)
6438 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6442 //================================================================================
6444 * \brief Return elements which can be intersected by the line
6446 //================================================================================
6448 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6449 TIDSortedElemSet& foundElems)
6451 if ( level() && getBox().IsOut( line ))
6456 for ( int i = 0; i < _elements.size(); ++i )
6457 if ( !_elements[i]->IsOut( line ))
6458 foundElems.insert( _elements[i]->_element );
6462 for (int i = 0; i < 8; i++)
6463 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6467 //================================================================================
6469 * \brief Construct the element box
6471 //================================================================================
6473 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6477 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6478 while ( nIt->more() )
6479 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6480 Enlarge( tolerance );
6485 //=======================================================================
6487 * \brief Implementation of search for the elements by point and
6488 * of classification of point in 2D mesh
6490 //=======================================================================
6492 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6494 SMESHDS_Mesh* _mesh;
6495 SMDS_ElemIteratorPtr _meshPartIt;
6496 ElementBndBoxTree* _ebbTree;
6497 SMESH_NodeSearcherImpl* _nodeSearcher;
6498 SMDSAbs_ElementType _elementType;
6500 bool _outerFacesFound;
6501 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6503 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6504 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6505 ~SMESH_ElementSearcherImpl()
6507 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6508 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6510 virtual int FindElementsByPoint(const gp_Pnt& point,
6511 SMDSAbs_ElementType type,
6512 vector< const SMDS_MeshElement* >& foundElements);
6513 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6515 void GetElementsNearLine( const gp_Ax1& line,
6516 SMDSAbs_ElementType type,
6517 vector< const SMDS_MeshElement* >& foundElems);
6518 double getTolerance();
6519 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6520 const double tolerance, double & param);
6521 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6522 bool isOuterBoundary(const SMDS_MeshElement* face) const
6524 return _outerFaces.empty() || _outerFaces.count(face);
6526 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6528 const SMDS_MeshElement* _face;
6530 bool _coincides; //!< the line lays in face plane
6531 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6532 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6534 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6537 TIDSortedElemSet _faces;
6538 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6539 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6543 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6545 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6546 << ", _coincides="<<i._coincides << ")";
6549 //=======================================================================
6551 * \brief define tolerance for search
6553 //=======================================================================
6555 double SMESH_ElementSearcherImpl::getTolerance()
6557 if ( _tolerance < 0 )
6559 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6562 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6564 double boxSize = _nodeSearcher->getTree()->maxSize();
6565 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6567 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6569 double boxSize = _ebbTree->maxSize();
6570 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6572 if ( _tolerance == 0 )
6574 // define tolerance by size of a most complex element
6575 int complexType = SMDSAbs_Volume;
6576 while ( complexType > SMDSAbs_All &&
6577 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6579 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6581 if ( complexType == int( SMDSAbs_Node ))
6583 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6585 if ( meshInfo.NbNodes() > 2 )
6586 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6590 SMDS_ElemIteratorPtr elemIt =
6591 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6592 const SMDS_MeshElement* elem = elemIt->next();
6593 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6594 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6596 while ( nodeIt->more() )
6598 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6599 elemSize = max( dist, elemSize );
6602 _tolerance = 1e-4 * elemSize;
6608 //================================================================================
6610 * \brief Find intersection of the line and an edge of face and return parameter on line
6612 //================================================================================
6614 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6615 const SMDS_MeshElement* face,
6622 GeomAPI_ExtremaCurveCurve anExtCC;
6623 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6625 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6626 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6628 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6629 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6630 anExtCC.Init( lineCurve, edge);
6631 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6633 Quantity_Parameter pl, pe;
6634 anExtCC.LowerDistanceParameters( pl, pe );
6636 if ( ++nbInts == 2 )
6640 if ( nbInts > 0 ) param /= nbInts;
6643 //================================================================================
6645 * \brief Find all faces belonging to the outer boundary of mesh
6647 //================================================================================
6649 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6651 if ( _outerFacesFound ) return;
6653 // Collect all outer faces by passing from one outer face to another via their links
6654 // and BTW find out if there are internal faces at all.
6656 // checked links and links where outer boundary meets internal one
6657 set< SMESH_TLink > visitedLinks, seamLinks;
6659 // links to treat with already visited faces sharing them
6660 list < TFaceLink > startLinks;
6662 // load startLinks with the first outerFace
6663 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6664 _outerFaces.insert( outerFace );
6666 TIDSortedElemSet emptySet;
6667 while ( !startLinks.empty() )
6669 const SMESH_TLink& link = startLinks.front()._link;
6670 TIDSortedElemSet& faces = startLinks.front()._faces;
6672 outerFace = *faces.begin();
6673 // find other faces sharing the link
6674 const SMDS_MeshElement* f;
6675 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6678 // select another outer face among the found
6679 const SMDS_MeshElement* outerFace2 = 0;
6680 if ( faces.size() == 2 )
6682 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6684 else if ( faces.size() > 2 )
6686 seamLinks.insert( link );
6688 // link direction within the outerFace
6689 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6690 SMESH_TNodeXYZ( link.node2()));
6691 int i1 = outerFace->GetNodeIndex( link.node1() );
6692 int i2 = outerFace->GetNodeIndex( link.node2() );
6693 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6694 if ( rev ) n1n2.Reverse();
6696 gp_XYZ ofNorm, fNorm;
6697 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6699 // direction from the link inside outerFace
6700 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6701 // sort all other faces by angle with the dirInOF
6702 map< double, const SMDS_MeshElement* > angle2Face;
6703 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6704 for ( ; face != faces.end(); ++face )
6706 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6708 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6709 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6710 if ( angle < 0 ) angle += 2*PI;
6711 angle2Face.insert( make_pair( angle, *face ));
6713 if ( !angle2Face.empty() )
6714 outerFace2 = angle2Face.begin()->second;
6717 // store the found outer face and add its links to continue seaching from
6720 _outerFaces.insert( outerFace );
6721 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6722 for ( int i = 0; i < nbNodes; ++i )
6724 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6725 if ( visitedLinks.insert( link2 ).second )
6726 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6729 startLinks.pop_front();
6731 _outerFacesFound = true;
6733 if ( !seamLinks.empty() )
6735 // There are internal boundaries touching the outher one,
6736 // find all faces of internal boundaries in order to find
6737 // faces of boundaries of holes, if any.
6742 _outerFaces.clear();
6746 //=======================================================================
6748 * \brief Find elements of given type where the given point is IN or ON.
6749 * Returns nb of found elements and elements them-selves.
6751 * 'ALL' type means elements of any type excluding nodes and 0D elements
6753 //=======================================================================
6755 int SMESH_ElementSearcherImpl::
6756 FindElementsByPoint(const gp_Pnt& point,
6757 SMDSAbs_ElementType type,
6758 vector< const SMDS_MeshElement* >& foundElements)
6760 foundElements.clear();
6762 double tolerance = getTolerance();
6764 // =================================================================================
6765 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6767 if ( !_nodeSearcher )
6768 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6770 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6771 if ( !closeNode ) return foundElements.size();
6773 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6774 return foundElements.size(); // to far from any node
6776 if ( type == SMDSAbs_Node )
6778 foundElements.push_back( closeNode );
6782 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6783 while ( elemIt->more() )
6784 foundElements.push_back( elemIt->next() );
6787 // =================================================================================
6788 else // elements more complex than 0D
6790 if ( !_ebbTree || _elementType != type )
6792 if ( _ebbTree ) delete _ebbTree;
6793 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6795 TIDSortedElemSet suspectElems;
6796 _ebbTree->getElementsNearPoint( point, suspectElems );
6797 TIDSortedElemSet::iterator elem = suspectElems.begin();
6798 for ( ; elem != suspectElems.end(); ++elem )
6799 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6800 foundElements.push_back( *elem );
6802 return foundElements.size();
6805 //================================================================================
6807 * \brief Classify the given point in the closed 2D mesh
6809 //================================================================================
6811 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6813 double tolerance = getTolerance();
6814 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6816 if ( _ebbTree ) delete _ebbTree;
6817 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6819 // Algo: analyse transition of a line starting at the point through mesh boundary;
6820 // try three lines parallel to axis of the coordinate system and perform rough
6821 // analysis. If solution is not clear perform thorough analysis.
6823 const int nbAxes = 3;
6824 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6825 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6826 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6827 multimap< int, int > nbInt2Axis; // to find the simplest case
6828 for ( int axis = 0; axis < nbAxes; ++axis )
6830 gp_Ax1 lineAxis( point, axisDir[axis]);
6831 gp_Lin line ( lineAxis );
6833 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6834 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6836 // Intersect faces with the line
6838 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6839 TIDSortedElemSet::iterator face = suspectFaces.begin();
6840 for ( ; face != suspectFaces.end(); ++face )
6844 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6845 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6847 // perform intersection
6848 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6849 if ( !intersection.IsDone() )
6851 if ( intersection.IsInQuadric() )
6853 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6855 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6857 gp_Pnt intersectionPoint = intersection.Point(1);
6858 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6859 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6862 // Analyse intersections roughly
6864 int nbInter = u2inters.size();
6868 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6869 if ( nbInter == 1 ) // not closed mesh
6870 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6872 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6875 if ( (f<0) == (l<0) )
6878 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6879 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6880 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6883 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6885 if ( _outerFacesFound ) break; // pass to thorough analysis
6887 } // three attempts - loop on CS axes
6889 // Analyse intersections thoroughly.
6890 // We make two loops maximum, on the first one we only exclude touching intersections,
6891 // on the second, if situation is still unclear, we gather and use information on
6892 // position of faces (internal or outer). If faces position is already gathered,
6893 // we make the second loop right away.
6895 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6897 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6898 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6900 int axis = nb_axis->second;
6901 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6903 gp_Ax1 lineAxis( point, axisDir[axis]);
6904 gp_Lin line ( lineAxis );
6906 // add tangent intersections to u2inters
6908 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6909 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6910 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6911 u2inters.insert(make_pair( param, *tgtInt ));
6912 tangentInters[ axis ].clear();
6914 // Count intersections before and after the point excluding touching ones.
6915 // If hasPositionInfo we count intersections of outer boundary only
6917 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6918 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6919 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6920 bool ok = ! u_int1->second._coincides;
6921 while ( ok && u_int1 != u2inters.end() )
6923 double u = u_int1->first;
6924 bool touchingInt = false;
6925 if ( ++u_int2 != u2inters.end() )
6927 // skip intersections at the same point (if the line passes through edge or node)
6929 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6935 // skip tangent intersections
6937 const SMDS_MeshElement* prevFace = u_int1->second._face;
6938 while ( ok && u_int2->second._coincides )
6940 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6946 ok = ( u_int2 != u2inters.end() );
6951 // skip intersections at the same point after tangent intersections
6954 double u2 = u_int2->first;
6956 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6962 // decide if we skipped a touching intersection
6963 if ( nbSamePnt + nbTgt > 0 )
6965 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6966 map< double, TInters >::iterator u_int = u_int1;
6967 for ( ; u_int != u_int2; ++u_int )
6969 if ( u_int->second._coincides ) continue;
6970 double dot = u_int->second._faceNorm * line.Direction();
6971 if ( dot > maxDot ) maxDot = dot;
6972 if ( dot < minDot ) minDot = dot;
6974 touchingInt = ( minDot*maxDot < 0 );
6979 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6990 u_int1 = u_int2; // to next intersection
6992 } // loop on intersections with one line
6996 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6999 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
7002 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
7003 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
7005 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
7008 if ( (f<0) == (l<0) )
7011 if ( hasPositionInfo )
7012 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7014 } // loop on intersections of the tree lines - thorough analysis
7016 if ( !hasPositionInfo )
7018 // gather info on faces position - is face in the outer boundary or not
7019 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7020 findOuterBoundary( u2inters.begin()->second._face );
7023 } // two attempts - with and w/o faces position info in the mesh
7025 return TopAbs_UNKNOWN;
7028 //=======================================================================
7030 * \brief Return elements possibly intersecting the line
7032 //=======================================================================
7034 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7035 SMDSAbs_ElementType type,
7036 vector< const SMDS_MeshElement* >& foundElems)
7038 if ( !_ebbTree || _elementType != type )
7040 if ( _ebbTree ) delete _ebbTree;
7041 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7043 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7044 _ebbTree->getElementsNearLine( line, suspectFaces );
7045 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7048 //=======================================================================
7050 * \brief Return SMESH_ElementSearcher
7052 //=======================================================================
7054 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7056 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7059 //=======================================================================
7061 * \brief Return SMESH_ElementSearcher
7063 //=======================================================================
7065 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7067 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7070 //=======================================================================
7072 * \brief Return true if the point is IN or ON of the element
7074 //=======================================================================
7076 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7078 if ( element->GetType() == SMDSAbs_Volume)
7080 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7083 // get ordered nodes
7085 vector< gp_XYZ > xyz;
7086 vector<const SMDS_MeshNode*> nodeList;
7088 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7089 if ( element->IsQuadratic() ) {
7090 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7091 nodeIt = f->interlacedNodesElemIterator();
7092 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7093 nodeIt = e->interlacedNodesElemIterator();
7095 while ( nodeIt->more() )
7097 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7098 xyz.push_back( SMESH_TNodeXYZ(node) );
7099 nodeList.push_back(node);
7102 int i, nbNodes = element->NbNodes();
7104 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7106 // compute face normal
7107 gp_Vec faceNorm(0,0,0);
7108 xyz.push_back( xyz.front() );
7109 nodeList.push_back( nodeList.front() );
7110 for ( i = 0; i < nbNodes; ++i )
7112 gp_Vec edge1( xyz[i+1], xyz[i]);
7113 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7114 faceNorm += edge1 ^ edge2;
7116 double normSize = faceNorm.Magnitude();
7117 if ( normSize <= tol )
7119 // degenerated face: point is out if it is out of all face edges
7120 for ( i = 0; i < nbNodes; ++i )
7122 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7123 if ( !isOut( &edge, point, tol ))
7128 faceNorm /= normSize;
7130 // check if the point lays on face plane
7131 gp_Vec n2p( xyz[0], point );
7132 if ( fabs( n2p * faceNorm ) > tol )
7133 return true; // not on face plane
7135 // check if point is out of face boundary:
7136 // define it by closest transition of a ray point->infinity through face boundary
7137 // on the face plane.
7138 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7139 // to find intersections of the ray with the boundary.
7141 gp_Vec plnNorm = ray ^ faceNorm;
7142 normSize = plnNorm.Magnitude();
7143 if ( normSize <= tol ) return false; // point coincides with the first node
7144 plnNorm /= normSize;
7145 // for each node of the face, compute its signed distance to the plane
7146 vector<double> dist( nbNodes + 1);
7147 for ( i = 0; i < nbNodes; ++i )
7149 gp_Vec n2p( xyz[i], point );
7150 dist[i] = n2p * plnNorm;
7152 dist.back() = dist.front();
7153 // find the closest intersection
7155 double rClosest, distClosest = 1e100;;
7157 for ( i = 0; i < nbNodes; ++i )
7160 if ( fabs( dist[i]) < tol )
7162 else if ( fabs( dist[i+1]) < tol )
7164 else if ( dist[i] * dist[i+1] < 0 )
7165 r = dist[i] / ( dist[i] - dist[i+1] );
7167 continue; // no intersection
7168 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7169 gp_Vec p2int ( point, pInt);
7170 if ( p2int * ray > -tol ) // right half-space
7172 double intDist = p2int.SquareMagnitude();
7173 if ( intDist < distClosest )
7178 distClosest = intDist;
7183 return true; // no intesections - out
7185 // analyse transition
7186 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7187 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7188 gp_Vec p2int ( point, pClosest );
7189 bool out = (edgeNorm * p2int) < -tol;
7190 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7193 // ray pass through a face node; analyze transition through an adjacent edge
7194 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7195 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7196 gp_Vec edgeAdjacent( p1, p2 );
7197 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7198 bool out2 = (edgeNorm2 * p2int) < -tol;
7200 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7201 return covexCorner ? (out || out2) : (out && out2);
7203 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7205 // point is out of edge if it is NOT ON any straight part of edge
7206 // (we consider quadratic edge as being composed of two straight parts)
7207 for ( i = 1; i < nbNodes; ++i )
7209 gp_Vec edge( xyz[i-1], xyz[i]);
7210 gp_Vec n1p ( xyz[i-1], point);
7211 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7214 gp_Vec n2p( xyz[i], point );
7215 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7217 return false; // point is ON this part
7221 // Node or 0D element -------------------------------------------------------------------------
7223 gp_Vec n2p ( xyz[0], point );
7224 return n2p.Magnitude() <= tol;
7229 //=======================================================================
7230 //function : SimplifyFace
7232 //=======================================================================
7233 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7234 vector<const SMDS_MeshNode *>& poly_nodes,
7235 vector<int>& quantities) const
7237 int nbNodes = faceNodes.size();
7242 set<const SMDS_MeshNode*> nodeSet;
7244 // get simple seq of nodes
7245 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7246 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7247 int iSimple = 0, nbUnique = 0;
7249 simpleNodes[iSimple++] = faceNodes[0];
7251 for (int iCur = 1; iCur < nbNodes; iCur++) {
7252 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7253 simpleNodes[iSimple++] = faceNodes[iCur];
7254 if (nodeSet.insert( faceNodes[iCur] ).second)
7258 int nbSimple = iSimple;
7259 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7269 bool foundLoop = (nbSimple > nbUnique);
7272 set<const SMDS_MeshNode*> loopSet;
7273 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7274 const SMDS_MeshNode* n = simpleNodes[iSimple];
7275 if (!loopSet.insert( n ).second) {
7279 int iC = 0, curLast = iSimple;
7280 for (; iC < curLast; iC++) {
7281 if (simpleNodes[iC] == n) break;
7283 int loopLen = curLast - iC;
7285 // create sub-element
7287 quantities.push_back(loopLen);
7288 for (; iC < curLast; iC++) {
7289 poly_nodes.push_back(simpleNodes[iC]);
7292 // shift the rest nodes (place from the first loop position)
7293 for (iC = curLast + 1; iC < nbSimple; iC++) {
7294 simpleNodes[iC - loopLen] = simpleNodes[iC];
7296 nbSimple -= loopLen;
7299 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7300 } // while (foundLoop)
7304 quantities.push_back(iSimple);
7305 for (int i = 0; i < iSimple; i++)
7306 poly_nodes.push_back(simpleNodes[i]);
7312 //=======================================================================
7313 //function : MergeNodes
7314 //purpose : In each group, the cdr of nodes are substituted by the first one
7316 //=======================================================================
7318 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7320 MESSAGE("MergeNodes");
7321 myLastCreatedElems.Clear();
7322 myLastCreatedNodes.Clear();
7324 SMESHDS_Mesh* aMesh = GetMeshDS();
7326 TNodeNodeMap nodeNodeMap; // node to replace - new node
7327 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7328 list< int > rmElemIds, rmNodeIds;
7330 // Fill nodeNodeMap and elems
7332 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7333 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7334 list<const SMDS_MeshNode*>& nodes = *grIt;
7335 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7336 const SMDS_MeshNode* nToKeep = *nIt;
7337 //MESSAGE("node to keep " << nToKeep->GetID());
7338 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7339 const SMDS_MeshNode* nToRemove = *nIt;
7340 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7341 if ( nToRemove != nToKeep ) {
7342 //MESSAGE(" node to remove " << nToRemove->GetID());
7343 rmNodeIds.push_back( nToRemove->GetID() );
7344 AddToSameGroups( nToKeep, nToRemove, aMesh );
7347 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7348 while ( invElemIt->more() ) {
7349 const SMDS_MeshElement* elem = invElemIt->next();
7354 // Change element nodes or remove an element
7356 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7357 for ( ; eIt != elems.end(); eIt++ ) {
7358 const SMDS_MeshElement* elem = *eIt;
7359 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7360 int nbNodes = elem->NbNodes();
7361 int aShapeId = FindShape( elem );
7363 set<const SMDS_MeshNode*> nodeSet;
7364 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7365 int iUnique = 0, iCur = 0, nbRepl = 0;
7366 vector<int> iRepl( nbNodes );
7368 // get new seq of nodes
7369 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7370 while ( itN->more() ) {
7371 const SMDS_MeshNode* n =
7372 static_cast<const SMDS_MeshNode*>( itN->next() );
7374 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7375 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7377 // BUG 0020185: begin
7379 bool stopRecur = false;
7380 set<const SMDS_MeshNode*> nodesRecur;
7381 nodesRecur.insert(n);
7382 while (!stopRecur) {
7383 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7384 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7385 n = (*nnIt_i).second;
7386 if (!nodesRecur.insert(n).second) {
7387 // error: recursive dependancy
7396 iRepl[ nbRepl++ ] = iCur;
7398 curNodes[ iCur ] = n;
7399 bool isUnique = nodeSet.insert( n ).second;
7401 uniqueNodes[ iUnique++ ] = n;
7405 // Analyse element topology after replacement
7408 int nbUniqueNodes = nodeSet.size();
7409 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7410 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7411 // Polygons and Polyhedral volumes
7412 if (elem->IsPoly()) {
7414 if (elem->GetType() == SMDSAbs_Face) {
7416 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7418 for (; inode < nbNodes; inode++) {
7419 face_nodes[inode] = curNodes[inode];
7422 vector<const SMDS_MeshNode *> polygons_nodes;
7423 vector<int> quantities;
7424 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7427 for (int iface = 0; iface < nbNew; iface++) {
7428 int nbNodes = quantities[iface];
7429 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7430 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7431 poly_nodes[ii] = polygons_nodes[inode];
7433 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7434 myLastCreatedElems.Append(newElem);
7436 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7439 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7440 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7441 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7443 if (nbNew > 0) quid = nbNew - 1;
7444 vector<int> newquant(quantities.begin()+quid, quantities.end());
7445 const SMDS_MeshElement* newElem = 0;
7446 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7447 myLastCreatedElems.Append(newElem);
7448 if ( aShapeId && newElem )
7449 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7450 rmElemIds.push_back(elem->GetID());
7453 rmElemIds.push_back(elem->GetID());
7457 else if (elem->GetType() == SMDSAbs_Volume) {
7458 // Polyhedral volume
7459 if (nbUniqueNodes < 4) {
7460 rmElemIds.push_back(elem->GetID());
7463 // each face has to be analyzed in order to check volume validity
7464 const SMDS_VtkVolume* aPolyedre =
7465 dynamic_cast<const SMDS_VtkVolume*>( elem );
7467 int nbFaces = aPolyedre->NbFaces();
7469 vector<const SMDS_MeshNode *> poly_nodes;
7470 vector<int> quantities;
7472 for (int iface = 1; iface <= nbFaces; iface++) {
7473 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7474 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7476 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7477 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7478 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7479 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7480 faceNode = (*nnIt).second;
7482 faceNodes[inode - 1] = faceNode;
7485 SimplifyFace(faceNodes, poly_nodes, quantities);
7488 if (quantities.size() > 3) {
7489 // to be done: remove coincident faces
7492 if (quantities.size() > 3)
7494 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7495 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7496 const SMDS_MeshElement* newElem = 0;
7497 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7498 myLastCreatedElems.Append(newElem);
7499 if ( aShapeId && newElem )
7500 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7501 rmElemIds.push_back(elem->GetID());
7505 rmElemIds.push_back(elem->GetID());
7516 // TODO not all the possible cases are solved. Find something more generic?
7517 switch ( nbNodes ) {
7518 case 2: ///////////////////////////////////// EDGE
7519 isOk = false; break;
7520 case 3: ///////////////////////////////////// TRIANGLE
7521 isOk = false; break;
7523 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7525 else { //////////////////////////////////// QUADRANGLE
7526 if ( nbUniqueNodes < 3 )
7528 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7529 isOk = false; // opposite nodes stick
7530 //MESSAGE("isOk " << isOk);
7533 case 6: ///////////////////////////////////// PENTAHEDRON
7534 if ( nbUniqueNodes == 4 ) {
7535 // ---------------------------------> tetrahedron
7537 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7538 // all top nodes stick: reverse a bottom
7539 uniqueNodes[ 0 ] = curNodes [ 1 ];
7540 uniqueNodes[ 1 ] = curNodes [ 0 ];
7542 else if (nbRepl == 3 &&
7543 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7544 // all bottom nodes stick: set a top before
7545 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7546 uniqueNodes[ 0 ] = curNodes [ 3 ];
7547 uniqueNodes[ 1 ] = curNodes [ 4 ];
7548 uniqueNodes[ 2 ] = curNodes [ 5 ];
7550 else if (nbRepl == 4 &&
7551 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7552 // a lateral face turns into a line: reverse a bottom
7553 uniqueNodes[ 0 ] = curNodes [ 1 ];
7554 uniqueNodes[ 1 ] = curNodes [ 0 ];
7559 else if ( nbUniqueNodes == 5 ) {
7560 // PENTAHEDRON --------------------> 2 tetrahedrons
7561 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7562 // a bottom node sticks with a linked top one
7564 SMDS_MeshElement* newElem =
7565 aMesh->AddVolume(curNodes[ 3 ],
7568 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7569 myLastCreatedElems.Append(newElem);
7571 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7572 // 2. : reverse a bottom
7573 uniqueNodes[ 0 ] = curNodes [ 1 ];
7574 uniqueNodes[ 1 ] = curNodes [ 0 ];
7584 if(elem->IsQuadratic()) { // Quadratic quadrangle
7596 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7599 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7601 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7602 uniqueNodes[0] = curNodes[0];
7603 uniqueNodes[1] = curNodes[2];
7604 uniqueNodes[2] = curNodes[3];
7605 uniqueNodes[3] = curNodes[5];
7606 uniqueNodes[4] = curNodes[6];
7607 uniqueNodes[5] = curNodes[7];
7610 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7611 uniqueNodes[0] = curNodes[0];
7612 uniqueNodes[1] = curNodes[1];
7613 uniqueNodes[2] = curNodes[2];
7614 uniqueNodes[3] = curNodes[4];
7615 uniqueNodes[4] = curNodes[5];
7616 uniqueNodes[5] = curNodes[6];
7619 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7620 uniqueNodes[0] = curNodes[1];
7621 uniqueNodes[1] = curNodes[2];
7622 uniqueNodes[2] = curNodes[3];
7623 uniqueNodes[3] = curNodes[5];
7624 uniqueNodes[4] = curNodes[6];
7625 uniqueNodes[5] = curNodes[0];
7628 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7629 uniqueNodes[0] = curNodes[0];
7630 uniqueNodes[1] = curNodes[1];
7631 uniqueNodes[2] = curNodes[3];
7632 uniqueNodes[3] = curNodes[4];
7633 uniqueNodes[4] = curNodes[6];
7634 uniqueNodes[5] = curNodes[7];
7637 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7638 uniqueNodes[0] = curNodes[0];
7639 uniqueNodes[1] = curNodes[2];
7640 uniqueNodes[2] = curNodes[3];
7641 uniqueNodes[3] = curNodes[1];
7642 uniqueNodes[4] = curNodes[6];
7643 uniqueNodes[5] = curNodes[7];
7646 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7647 uniqueNodes[0] = curNodes[0];
7648 uniqueNodes[1] = curNodes[1];
7649 uniqueNodes[2] = curNodes[2];
7650 uniqueNodes[3] = curNodes[4];
7651 uniqueNodes[4] = curNodes[5];
7652 uniqueNodes[5] = curNodes[7];
7655 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7656 uniqueNodes[0] = curNodes[0];
7657 uniqueNodes[1] = curNodes[1];
7658 uniqueNodes[2] = curNodes[3];
7659 uniqueNodes[3] = curNodes[4];
7660 uniqueNodes[4] = curNodes[2];
7661 uniqueNodes[5] = curNodes[7];
7664 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7665 uniqueNodes[0] = curNodes[0];
7666 uniqueNodes[1] = curNodes[1];
7667 uniqueNodes[2] = curNodes[2];
7668 uniqueNodes[3] = curNodes[4];
7669 uniqueNodes[4] = curNodes[5];
7670 uniqueNodes[5] = curNodes[3];
7675 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7678 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7682 //////////////////////////////////// HEXAHEDRON
7684 SMDS_VolumeTool hexa (elem);
7685 hexa.SetExternalNormal();
7686 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7687 //////////////////////// ---> tetrahedron
7688 for ( int iFace = 0; iFace < 6; iFace++ ) {
7689 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7690 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7691 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7692 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7693 // one face turns into a point ...
7694 int iOppFace = hexa.GetOppFaceIndex( iFace );
7695 ind = hexa.GetFaceNodesIndices( iOppFace );
7697 iUnique = 2; // reverse a tetrahedron bottom
7698 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7699 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7701 else if ( iUnique >= 0 )
7702 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7704 if ( nbStick == 1 ) {
7705 // ... and the opposite one - into a triangle.
7707 ind = hexa.GetFaceNodesIndices( iFace );
7708 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7715 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7716 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7717 for ( int iFace = 0; iFace < 6; iFace++ ) {
7718 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7719 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7720 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7721 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7722 // one face turns into a point ...
7723 int iOppFace = hexa.GetOppFaceIndex( iFace );
7724 ind = hexa.GetFaceNodesIndices( iOppFace );
7726 iUnique = 2; // reverse a tetrahedron 1 bottom
7727 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7728 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7730 else if ( iUnique >= 0 )
7731 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7733 if ( nbStick == 0 ) {
7734 // ... and the opposite one is a quadrangle
7736 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7737 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7740 SMDS_MeshElement* newElem =
7741 aMesh->AddVolume(curNodes[ind[ 0 ]],
7744 curNodes[indTop[ 0 ]]);
7745 myLastCreatedElems.Append(newElem);
7747 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7754 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7755 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7756 // find indices of quad and tri faces
7757 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7758 for ( iFace = 0; iFace < 6; iFace++ ) {
7759 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7761 for ( iCur = 0; iCur < 4; iCur++ )
7762 nodeSet.insert( curNodes[ind[ iCur ]] );
7763 nbUniqueNodes = nodeSet.size();
7764 if ( nbUniqueNodes == 3 )
7765 iTriFace[ nbTri++ ] = iFace;
7766 else if ( nbUniqueNodes == 4 )
7767 iQuadFace[ nbQuad++ ] = iFace;
7769 if (nbQuad == 2 && nbTri == 4 &&
7770 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7771 // 2 opposite quadrangles stuck with a diagonal;
7772 // sample groups of merged indices: (0-4)(2-6)
7773 // --------------------------------------------> 2 tetrahedrons
7774 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7775 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7776 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7777 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7778 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7779 // stuck with 0-2 diagonal
7787 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7788 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7789 // stuck with 1-3 diagonal
7801 uniqueNodes[ 0 ] = curNodes [ i0 ];
7802 uniqueNodes[ 1 ] = curNodes [ i1d ];
7803 uniqueNodes[ 2 ] = curNodes [ i3d ];
7804 uniqueNodes[ 3 ] = curNodes [ i0t ];
7807 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7811 myLastCreatedElems.Append(newElem);
7813 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7816 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7817 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7818 // --------------------------------------------> prism
7819 // find 2 opposite triangles
7821 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7822 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7823 // find indices of kept and replaced nodes
7824 // and fill unique nodes of 2 opposite triangles
7825 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7826 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7827 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7828 // fill unique nodes
7831 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7832 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7833 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7835 // iCur of a linked node of the opposite face (make normals co-directed):
7836 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7837 // check that correspondent corners of triangles are linked
7838 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7841 uniqueNodes[ iUnique ] = n;
7842 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7851 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7857 } // switch ( nbNodes )
7859 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7861 if ( isOk ) { // the elem remains valid after sticking nodes
7862 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7864 // Change nodes of polyedre
7865 const SMDS_VtkVolume* aPolyedre =
7866 dynamic_cast<const SMDS_VtkVolume*>( elem );
7868 int nbFaces = aPolyedre->NbFaces();
7870 vector<const SMDS_MeshNode *> poly_nodes;
7871 vector<int> quantities (nbFaces);
7873 for (int iface = 1; iface <= nbFaces; iface++) {
7874 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7875 quantities[iface - 1] = nbFaceNodes;
7877 for (inode = 1; inode <= nbFaceNodes; inode++) {
7878 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7880 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7881 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7882 curNode = (*nnIt).second;
7884 poly_nodes.push_back(curNode);
7887 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7890 else // replace non-polyhedron elements
7892 const SMDSAbs_ElementType etyp = elem->GetType();
7893 const int elemId = elem->GetID();
7894 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
7895 uniqueNodes.resize(nbUniqueNodes);
7897 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7899 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7900 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7901 if ( sm && newElem )
7902 sm->AddElement( newElem );
7903 if ( elem != newElem )
7904 ReplaceElemInGroups( elem, newElem, aMesh );
7908 // Remove invalid regular element or invalid polygon
7909 rmElemIds.push_back( elem->GetID() );
7912 } // loop on elements
7914 // Remove bad elements, then equal nodes (order important)
7916 Remove( rmElemIds, false );
7917 Remove( rmNodeIds, true );
7922 // ========================================================
7923 // class : SortableElement
7924 // purpose : allow sorting elements basing on their nodes
7925 // ========================================================
7926 class SortableElement : public set <const SMDS_MeshElement*>
7930 SortableElement( const SMDS_MeshElement* theElem )
7933 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7934 while ( nodeIt->more() )
7935 this->insert( nodeIt->next() );
7938 const SMDS_MeshElement* Get() const
7941 void Set(const SMDS_MeshElement* e) const
7946 mutable const SMDS_MeshElement* myElem;
7949 //=======================================================================
7950 //function : FindEqualElements
7951 //purpose : Return list of group of elements built on the same nodes.
7952 // Search among theElements or in the whole mesh if theElements is empty
7953 //=======================================================================
7954 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7955 TListOfListOfElementsID & theGroupsOfElementsID)
7957 myLastCreatedElems.Clear();
7958 myLastCreatedNodes.Clear();
7960 typedef set<const SMDS_MeshElement*> TElemsSet;
7961 typedef map< SortableElement, int > TMapOfNodeSet;
7962 typedef list<int> TGroupOfElems;
7965 if ( theElements.empty() )
7966 { // get all elements in the mesh
7967 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7968 while ( eIt->more() )
7969 elems.insert( elems.end(), eIt->next());
7972 elems = theElements;
7974 vector< TGroupOfElems > arrayOfGroups;
7975 TGroupOfElems groupOfElems;
7976 TMapOfNodeSet mapOfNodeSet;
7978 TElemsSet::iterator elemIt = elems.begin();
7979 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7980 const SMDS_MeshElement* curElem = *elemIt;
7981 SortableElement SE(curElem);
7984 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7985 if( !(pp.second) ) {
7986 TMapOfNodeSet::iterator& itSE = pp.first;
7987 ind = (*itSE).second;
7988 arrayOfGroups[ind].push_back(curElem->GetID());
7991 groupOfElems.clear();
7992 groupOfElems.push_back(curElem->GetID());
7993 arrayOfGroups.push_back(groupOfElems);
7998 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7999 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8000 groupOfElems = *groupIt;
8001 if ( groupOfElems.size() > 1 ) {
8002 groupOfElems.sort();
8003 theGroupsOfElementsID.push_back(groupOfElems);
8008 //=======================================================================
8009 //function : MergeElements
8010 //purpose : In each given group, substitute all elements by the first one.
8011 //=======================================================================
8013 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8015 myLastCreatedElems.Clear();
8016 myLastCreatedNodes.Clear();
8018 typedef list<int> TListOfIDs;
8019 TListOfIDs rmElemIds; // IDs of elems to remove
8021 SMESHDS_Mesh* aMesh = GetMeshDS();
8023 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8024 while ( groupsIt != theGroupsOfElementsID.end() ) {
8025 TListOfIDs& aGroupOfElemID = *groupsIt;
8026 aGroupOfElemID.sort();
8027 int elemIDToKeep = aGroupOfElemID.front();
8028 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8029 aGroupOfElemID.pop_front();
8030 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8031 while ( idIt != aGroupOfElemID.end() ) {
8032 int elemIDToRemove = *idIt;
8033 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8034 // add the kept element in groups of removed one (PAL15188)
8035 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8036 rmElemIds.push_back( elemIDToRemove );
8042 Remove( rmElemIds, false );
8045 //=======================================================================
8046 //function : MergeEqualElements
8047 //purpose : Remove all but one of elements built on the same nodes.
8048 //=======================================================================
8050 void SMESH_MeshEditor::MergeEqualElements()
8052 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8053 to merge equal elements in the whole mesh */
8054 TListOfListOfElementsID aGroupsOfElementsID;
8055 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8056 MergeElements(aGroupsOfElementsID);
8059 //=======================================================================
8060 //function : FindFaceInSet
8061 //purpose : Return a face having linked nodes n1 and n2 and which is
8062 // - not in avoidSet,
8063 // - in elemSet provided that !elemSet.empty()
8064 // i1 and i2 optionally returns indices of n1 and n2
8065 //=======================================================================
8067 const SMDS_MeshElement*
8068 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8069 const SMDS_MeshNode* n2,
8070 const TIDSortedElemSet& elemSet,
8071 const TIDSortedElemSet& avoidSet,
8077 const SMDS_MeshElement* face = 0;
8079 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8080 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8081 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8083 //MESSAGE("in while ( invElemIt->more() && !face )");
8084 const SMDS_MeshElement* elem = invElemIt->next();
8085 if (avoidSet.count( elem ))
8087 if ( !elemSet.empty() && !elemSet.count( elem ))
8090 i1 = elem->GetNodeIndex( n1 );
8091 // find a n2 linked to n1
8092 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8093 for ( int di = -1; di < 2 && !face; di += 2 )
8095 i2 = (i1+di+nbN) % nbN;
8096 if ( elem->GetNode( i2 ) == n2 )
8099 if ( !face && elem->IsQuadratic())
8101 // analysis for quadratic elements using all nodes
8102 const SMDS_VtkFace* F =
8103 dynamic_cast<const SMDS_VtkFace*>(elem);
8104 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8105 // use special nodes iterator
8106 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8107 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8108 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8110 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8111 if ( n1 == prevN && n2 == n )
8115 else if ( n2 == prevN && n1 == n )
8117 face = elem; swap( i1, i2 );
8123 if ( n1ind ) *n1ind = i1;
8124 if ( n2ind ) *n2ind = i2;
8128 //=======================================================================
8129 //function : findAdjacentFace
8131 //=======================================================================
8133 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8134 const SMDS_MeshNode* n2,
8135 const SMDS_MeshElement* elem)
8137 TIDSortedElemSet elemSet, avoidSet;
8139 avoidSet.insert ( elem );
8140 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8143 //=======================================================================
8144 //function : FindFreeBorder
8146 //=======================================================================
8148 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8150 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8151 const SMDS_MeshNode* theSecondNode,
8152 const SMDS_MeshNode* theLastNode,
8153 list< const SMDS_MeshNode* > & theNodes,
8154 list< const SMDS_MeshElement* >& theFaces)
8156 if ( !theFirstNode || !theSecondNode )
8158 // find border face between theFirstNode and theSecondNode
8159 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8163 theFaces.push_back( curElem );
8164 theNodes.push_back( theFirstNode );
8165 theNodes.push_back( theSecondNode );
8167 //vector<const SMDS_MeshNode*> nodes;
8168 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8169 TIDSortedElemSet foundElems;
8170 bool needTheLast = ( theLastNode != 0 );
8172 while ( nStart != theLastNode ) {
8173 if ( nStart == theFirstNode )
8174 return !needTheLast;
8176 // find all free border faces sharing form nStart
8178 list< const SMDS_MeshElement* > curElemList;
8179 list< const SMDS_MeshNode* > nStartList;
8180 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8181 while ( invElemIt->more() ) {
8182 const SMDS_MeshElement* e = invElemIt->next();
8183 if ( e == curElem || foundElems.insert( e ).second ) {
8185 int iNode = 0, nbNodes = e->NbNodes();
8186 //const SMDS_MeshNode* nodes[nbNodes+1];
8187 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8189 if(e->IsQuadratic()) {
8190 const SMDS_VtkFace* F =
8191 dynamic_cast<const SMDS_VtkFace*>(e);
8192 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8193 // use special nodes iterator
8194 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8195 while( anIter->more() ) {
8196 nodes[ iNode++ ] = cast2Node(anIter->next());
8200 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8201 while ( nIt->more() )
8202 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8204 nodes[ iNode ] = nodes[ 0 ];
8206 for ( iNode = 0; iNode < nbNodes; iNode++ )
8207 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8208 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8209 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8211 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8212 curElemList.push_back( e );
8216 // analyse the found
8218 int nbNewBorders = curElemList.size();
8219 if ( nbNewBorders == 0 ) {
8220 // no free border furthermore
8221 return !needTheLast;
8223 else if ( nbNewBorders == 1 ) {
8224 // one more element found
8226 nStart = nStartList.front();
8227 curElem = curElemList.front();
8228 theFaces.push_back( curElem );
8229 theNodes.push_back( nStart );
8232 // several continuations found
8233 list< const SMDS_MeshElement* >::iterator curElemIt;
8234 list< const SMDS_MeshNode* >::iterator nStartIt;
8235 // check if one of them reached the last node
8236 if ( needTheLast ) {
8237 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8238 curElemIt!= curElemList.end();
8239 curElemIt++, nStartIt++ )
8240 if ( *nStartIt == theLastNode ) {
8241 theFaces.push_back( *curElemIt );
8242 theNodes.push_back( *nStartIt );
8246 // find the best free border by the continuations
8247 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8248 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8249 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8250 curElemIt!= curElemList.end();
8251 curElemIt++, nStartIt++ )
8253 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8254 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8255 // find one more free border
8256 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8260 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8261 // choice: clear a worse one
8262 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8263 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8264 contNodes[ iWorse ].clear();
8265 contFaces[ iWorse ].clear();
8268 if ( contNodes[0].empty() && contNodes[1].empty() )
8271 // append the best free border
8272 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8273 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8274 theNodes.pop_back(); // remove nIgnore
8275 theNodes.pop_back(); // remove nStart
8276 theFaces.pop_back(); // remove curElem
8277 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8278 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8279 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8280 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8283 } // several continuations found
8284 } // while ( nStart != theLastNode )
8289 //=======================================================================
8290 //function : CheckFreeBorderNodes
8291 //purpose : Return true if the tree nodes are on a free border
8292 //=======================================================================
8294 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8295 const SMDS_MeshNode* theNode2,
8296 const SMDS_MeshNode* theNode3)
8298 list< const SMDS_MeshNode* > nodes;
8299 list< const SMDS_MeshElement* > faces;
8300 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8303 //=======================================================================
8304 //function : SewFreeBorder
8306 //=======================================================================
8308 SMESH_MeshEditor::Sew_Error
8309 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8310 const SMDS_MeshNode* theBordSecondNode,
8311 const SMDS_MeshNode* theBordLastNode,
8312 const SMDS_MeshNode* theSideFirstNode,
8313 const SMDS_MeshNode* theSideSecondNode,
8314 const SMDS_MeshNode* theSideThirdNode,
8315 const bool theSideIsFreeBorder,
8316 const bool toCreatePolygons,
8317 const bool toCreatePolyedrs)
8319 myLastCreatedElems.Clear();
8320 myLastCreatedNodes.Clear();
8322 MESSAGE("::SewFreeBorder()");
8323 Sew_Error aResult = SEW_OK;
8325 // ====================================
8326 // find side nodes and elements
8327 // ====================================
8329 list< const SMDS_MeshNode* > nSide[ 2 ];
8330 list< const SMDS_MeshElement* > eSide[ 2 ];
8331 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8332 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8336 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8337 nSide[0], eSide[0])) {
8338 MESSAGE(" Free Border 1 not found " );
8339 aResult = SEW_BORDER1_NOT_FOUND;
8341 if (theSideIsFreeBorder) {
8344 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8345 nSide[1], eSide[1])) {
8346 MESSAGE(" Free Border 2 not found " );
8347 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8350 if ( aResult != SEW_OK )
8353 if (!theSideIsFreeBorder) {
8357 // -------------------------------------------------------------------------
8359 // 1. If nodes to merge are not coincident, move nodes of the free border
8360 // from the coord sys defined by the direction from the first to last
8361 // nodes of the border to the correspondent sys of the side 2
8362 // 2. On the side 2, find the links most co-directed with the correspondent
8363 // links of the free border
8364 // -------------------------------------------------------------------------
8366 // 1. Since sewing may break if there are volumes to split on the side 2,
8367 // we wont move nodes but just compute new coordinates for them
8368 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8369 TNodeXYZMap nBordXYZ;
8370 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8371 list< const SMDS_MeshNode* >::iterator nBordIt;
8373 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8374 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8375 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8376 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8377 double tol2 = 1.e-8;
8378 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8379 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8380 // Need node movement.
8382 // find X and Z axes to create trsf
8383 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8385 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8387 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8390 gp_Ax3 toBordAx( Pb1, Zb, X );
8391 gp_Ax3 fromSideAx( Ps1, Zs, X );
8392 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8394 gp_Trsf toBordSys, fromSide2Sys;
8395 toBordSys.SetTransformation( toBordAx );
8396 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8397 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8400 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8401 const SMDS_MeshNode* n = *nBordIt;
8402 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8403 toBordSys.Transforms( xyz );
8404 fromSide2Sys.Transforms( xyz );
8405 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8409 // just insert nodes XYZ in the nBordXYZ map
8410 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8411 const SMDS_MeshNode* n = *nBordIt;
8412 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8416 // 2. On the side 2, find the links most co-directed with the correspondent
8417 // links of the free border
8419 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8420 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8421 sideNodes.push_back( theSideFirstNode );
8423 bool hasVolumes = false;
8424 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8425 set<long> foundSideLinkIDs, checkedLinkIDs;
8426 SMDS_VolumeTool volume;
8427 //const SMDS_MeshNode* faceNodes[ 4 ];
8429 const SMDS_MeshNode* sideNode;
8430 const SMDS_MeshElement* sideElem;
8431 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8432 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8433 nBordIt = bordNodes.begin();
8435 // border node position and border link direction to compare with
8436 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8437 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8438 // choose next side node by link direction or by closeness to
8439 // the current border node:
8440 bool searchByDir = ( *nBordIt != theBordLastNode );
8442 // find the next node on the Side 2
8444 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8446 checkedLinkIDs.clear();
8447 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8449 // loop on inverse elements of current node (prevSideNode) on the Side 2
8450 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8451 while ( invElemIt->more() )
8453 const SMDS_MeshElement* elem = invElemIt->next();
8454 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8455 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8456 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8457 bool isVolume = volume.Set( elem );
8458 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8459 if ( isVolume ) // --volume
8461 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8462 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8463 if(elem->IsQuadratic()) {
8464 const SMDS_VtkFace* F =
8465 dynamic_cast<const SMDS_VtkFace*>(elem);
8466 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8467 // use special nodes iterator
8468 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8469 while( anIter->more() ) {
8470 nodes[ iNode ] = cast2Node(anIter->next());
8471 if ( nodes[ iNode++ ] == prevSideNode )
8472 iPrevNode = iNode - 1;
8476 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8477 while ( nIt->more() ) {
8478 nodes[ iNode ] = cast2Node( nIt->next() );
8479 if ( nodes[ iNode++ ] == prevSideNode )
8480 iPrevNode = iNode - 1;
8483 // there are 2 links to check
8488 // loop on links, to be precise, on the second node of links
8489 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8490 const SMDS_MeshNode* n = nodes[ iNode ];
8492 if ( !volume.IsLinked( n, prevSideNode ))
8496 if ( iNode ) // a node before prevSideNode
8497 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8498 else // a node after prevSideNode
8499 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8501 // check if this link was already used
8502 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8503 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8504 if (!isJustChecked &&
8505 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8507 // test a link geometrically
8508 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8509 bool linkIsBetter = false;
8510 double dot = 0.0, dist = 0.0;
8511 if ( searchByDir ) { // choose most co-directed link
8512 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8513 linkIsBetter = ( dot > maxDot );
8515 else { // choose link with the node closest to bordPos
8516 dist = ( nextXYZ - bordPos ).SquareModulus();
8517 linkIsBetter = ( dist < minDist );
8519 if ( linkIsBetter ) {
8528 } // loop on inverse elements of prevSideNode
8531 MESSAGE(" Cant find path by links of the Side 2 ");
8532 return SEW_BAD_SIDE_NODES;
8534 sideNodes.push_back( sideNode );
8535 sideElems.push_back( sideElem );
8536 foundSideLinkIDs.insert ( linkID );
8537 prevSideNode = sideNode;
8539 if ( *nBordIt == theBordLastNode )
8540 searchByDir = false;
8542 // find the next border link to compare with
8543 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8544 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8545 // move to next border node if sideNode is before forward border node (bordPos)
8546 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8547 prevBordNode = *nBordIt;
8549 bordPos = nBordXYZ[ *nBordIt ];
8550 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8551 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8555 while ( sideNode != theSideSecondNode );
8557 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8558 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8559 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8561 } // end nodes search on the side 2
8563 // ============================
8564 // sew the border to the side 2
8565 // ============================
8567 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8568 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8570 TListOfListOfNodes nodeGroupsToMerge;
8571 if ( nbNodes[0] == nbNodes[1] ||
8572 ( theSideIsFreeBorder && !theSideThirdNode)) {
8574 // all nodes are to be merged
8576 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8577 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8578 nIt[0]++, nIt[1]++ )
8580 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8581 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8582 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8587 // insert new nodes into the border and the side to get equal nb of segments
8589 // get normalized parameters of nodes on the borders
8590 //double param[ 2 ][ maxNbNodes ];
8592 param[0] = new double [ maxNbNodes ];
8593 param[1] = new double [ maxNbNodes ];
8595 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8596 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8597 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8598 const SMDS_MeshNode* nPrev = *nIt;
8599 double bordLength = 0;
8600 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8601 const SMDS_MeshNode* nCur = *nIt;
8602 gp_XYZ segment (nCur->X() - nPrev->X(),
8603 nCur->Y() - nPrev->Y(),
8604 nCur->Z() - nPrev->Z());
8605 double segmentLen = segment.Modulus();
8606 bordLength += segmentLen;
8607 param[ iBord ][ iNode ] = bordLength;
8610 // normalize within [0,1]
8611 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8612 param[ iBord ][ iNode ] /= bordLength;
8616 // loop on border segments
8617 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8618 int i[ 2 ] = { 0, 0 };
8619 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8620 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8622 TElemOfNodeListMap insertMap;
8623 TElemOfNodeListMap::iterator insertMapIt;
8625 // key: elem to insert nodes into
8626 // value: 2 nodes to insert between + nodes to be inserted
8628 bool next[ 2 ] = { false, false };
8630 // find min adjacent segment length after sewing
8631 double nextParam = 10., prevParam = 0;
8632 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8633 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8634 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8635 if ( i[ iBord ] > 0 )
8636 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8638 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8639 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8640 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8642 // choose to insert or to merge nodes
8643 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8644 if ( Abs( du ) <= minSegLen * 0.2 ) {
8647 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8648 const SMDS_MeshNode* n0 = *nIt[0];
8649 const SMDS_MeshNode* n1 = *nIt[1];
8650 nodeGroupsToMerge.back().push_back( n1 );
8651 nodeGroupsToMerge.back().push_back( n0 );
8652 // position of node of the border changes due to merge
8653 param[ 0 ][ i[0] ] += du;
8654 // move n1 for the sake of elem shape evaluation during insertion.
8655 // n1 will be removed by MergeNodes() anyway
8656 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8657 next[0] = next[1] = true;
8662 int intoBord = ( du < 0 ) ? 0 : 1;
8663 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8664 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8665 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8666 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8667 if ( intoBord == 1 ) {
8668 // move node of the border to be on a link of elem of the side
8669 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8670 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8671 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8672 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8673 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8675 insertMapIt = insertMap.find( elem );
8676 bool notFound = ( insertMapIt == insertMap.end() );
8677 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8679 // insert into another link of the same element:
8680 // 1. perform insertion into the other link of the elem
8681 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8682 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8683 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8684 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8685 // 2. perform insertion into the link of adjacent faces
8687 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8689 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8693 if (toCreatePolyedrs) {
8694 // perform insertion into the links of adjacent volumes
8695 UpdateVolumes(n12, n22, nodeList);
8697 // 3. find an element appeared on n1 and n2 after the insertion
8698 insertMap.erase( elem );
8699 elem = findAdjacentFace( n1, n2, 0 );
8701 if ( notFound || otherLink ) {
8702 // add element and nodes of the side into the insertMap
8703 insertMapIt = insertMap.insert
8704 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8705 (*insertMapIt).second.push_back( n1 );
8706 (*insertMapIt).second.push_back( n2 );
8708 // add node to be inserted into elem
8709 (*insertMapIt).second.push_back( nIns );
8710 next[ 1 - intoBord ] = true;
8713 // go to the next segment
8714 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8715 if ( next[ iBord ] ) {
8716 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8718 nPrev[ iBord ] = *nIt[ iBord ];
8719 nIt[ iBord ]++; i[ iBord ]++;
8723 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8725 // perform insertion of nodes into elements
8727 for (insertMapIt = insertMap.begin();
8728 insertMapIt != insertMap.end();
8731 const SMDS_MeshElement* elem = (*insertMapIt).first;
8732 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8733 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8734 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8736 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8738 if ( !theSideIsFreeBorder ) {
8739 // look for and insert nodes into the faces adjacent to elem
8741 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8743 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8748 if (toCreatePolyedrs) {
8749 // perform insertion into the links of adjacent volumes
8750 UpdateVolumes(n1, n2, nodeList);
8756 } // end: insert new nodes
8758 MergeNodes ( nodeGroupsToMerge );
8763 //=======================================================================
8764 //function : InsertNodesIntoLink
8765 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8766 // and theBetweenNode2 and split theElement
8767 //=======================================================================
8769 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8770 const SMDS_MeshNode* theBetweenNode1,
8771 const SMDS_MeshNode* theBetweenNode2,
8772 list<const SMDS_MeshNode*>& theNodesToInsert,
8773 const bool toCreatePoly)
8775 if ( theFace->GetType() != SMDSAbs_Face ) return;
8777 // find indices of 2 link nodes and of the rest nodes
8778 int iNode = 0, il1, il2, i3, i4;
8779 il1 = il2 = i3 = i4 = -1;
8780 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8781 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8783 if(theFace->IsQuadratic()) {
8784 const SMDS_VtkFace* F =
8785 dynamic_cast<const SMDS_VtkFace*>(theFace);
8786 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8787 // use special nodes iterator
8788 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8789 while( anIter->more() ) {
8790 const SMDS_MeshNode* n = cast2Node(anIter->next());
8791 if ( n == theBetweenNode1 )
8793 else if ( n == theBetweenNode2 )
8799 nodes[ iNode++ ] = n;
8803 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8804 while ( nodeIt->more() ) {
8805 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8806 if ( n == theBetweenNode1 )
8808 else if ( n == theBetweenNode2 )
8814 nodes[ iNode++ ] = n;
8817 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8820 // arrange link nodes to go one after another regarding the face orientation
8821 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8822 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8827 aNodesToInsert.reverse();
8829 // check that not link nodes of a quadrangles are in good order
8830 int nbFaceNodes = theFace->NbNodes();
8831 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8837 if (toCreatePoly || theFace->IsPoly()) {
8840 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8842 // add nodes of face up to first node of link
8845 if(theFace->IsQuadratic()) {
8846 const SMDS_VtkFace* F =
8847 dynamic_cast<const SMDS_VtkFace*>(theFace);
8848 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8849 // use special nodes iterator
8850 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8851 while( anIter->more() && !isFLN ) {
8852 const SMDS_MeshNode* n = cast2Node(anIter->next());
8853 poly_nodes[iNode++] = n;
8854 if (n == nodes[il1]) {
8858 // add nodes to insert
8859 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8860 for (; nIt != aNodesToInsert.end(); nIt++) {
8861 poly_nodes[iNode++] = *nIt;
8863 // add nodes of face starting from last node of link
8864 while ( anIter->more() ) {
8865 poly_nodes[iNode++] = cast2Node(anIter->next());
8869 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8870 while ( nodeIt->more() && !isFLN ) {
8871 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8872 poly_nodes[iNode++] = n;
8873 if (n == nodes[il1]) {
8877 // add nodes to insert
8878 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8879 for (; nIt != aNodesToInsert.end(); nIt++) {
8880 poly_nodes[iNode++] = *nIt;
8882 // add nodes of face starting from last node of link
8883 while ( nodeIt->more() ) {
8884 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8885 poly_nodes[iNode++] = n;
8889 // edit or replace the face
8890 SMESHDS_Mesh *aMesh = GetMeshDS();
8892 if (theFace->IsPoly()) {
8893 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8896 int aShapeId = FindShape( theFace );
8898 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8899 myLastCreatedElems.Append(newElem);
8900 if ( aShapeId && newElem )
8901 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8903 aMesh->RemoveElement(theFace);
8908 SMESHDS_Mesh *aMesh = GetMeshDS();
8909 if( !theFace->IsQuadratic() ) {
8911 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8912 int nbLinkNodes = 2 + aNodesToInsert.size();
8913 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8914 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8915 linkNodes[ 0 ] = nodes[ il1 ];
8916 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8917 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8918 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8919 linkNodes[ iNode++ ] = *nIt;
8921 // decide how to split a quadrangle: compare possible variants
8922 // and choose which of splits to be a quadrangle
8923 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8924 if ( nbFaceNodes == 3 ) {
8925 iBestQuad = nbSplits;
8928 else if ( nbFaceNodes == 4 ) {
8929 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8930 double aBestRate = DBL_MAX;
8931 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8933 double aBadRate = 0;
8934 // evaluate elements quality
8935 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8936 if ( iSplit == iQuad ) {
8937 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8941 aBadRate += getBadRate( &quad, aCrit );
8944 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8946 nodes[ iSplit < iQuad ? i4 : i3 ]);
8947 aBadRate += getBadRate( &tria, aCrit );
8951 if ( aBadRate < aBestRate ) {
8953 aBestRate = aBadRate;
8958 // create new elements
8959 int aShapeId = FindShape( theFace );
8962 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8963 SMDS_MeshElement* newElem = 0;
8964 if ( iSplit == iBestQuad )
8965 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8970 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8972 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8973 myLastCreatedElems.Append(newElem);
8974 if ( aShapeId && newElem )
8975 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8978 // change nodes of theFace
8979 const SMDS_MeshNode* newNodes[ 4 ];
8980 newNodes[ 0 ] = linkNodes[ i1 ];
8981 newNodes[ 1 ] = linkNodes[ i2 ];
8982 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8983 newNodes[ 3 ] = nodes[ i4 ];
8984 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8985 const SMDS_MeshElement* newElem = 0;
8986 if (iSplit == iBestQuad)
8987 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8989 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8990 myLastCreatedElems.Append(newElem);
8991 if ( aShapeId && newElem )
8992 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8993 } // end if(!theFace->IsQuadratic())
8994 else { // theFace is quadratic
8995 // we have to split theFace on simple triangles and one simple quadrangle
8997 int nbshift = tmp*2;
8998 // shift nodes in nodes[] by nbshift
9000 for(i=0; i<nbshift; i++) {
9001 const SMDS_MeshNode* n = nodes[0];
9002 for(j=0; j<nbFaceNodes-1; j++) {
9003 nodes[j] = nodes[j+1];
9005 nodes[nbFaceNodes-1] = n;
9007 il1 = il1 - nbshift;
9008 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9009 // n0 n1 n2 n0 n1 n2
9010 // +-----+-----+ +-----+-----+
9019 // create new elements
9020 int aShapeId = FindShape( theFace );
9023 if(nbFaceNodes==6) { // quadratic triangle
9024 SMDS_MeshElement* newElem =
9025 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9026 myLastCreatedElems.Append(newElem);
9027 if ( aShapeId && newElem )
9028 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9029 if(theFace->IsMediumNode(nodes[il1])) {
9030 // create quadrangle
9031 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9032 myLastCreatedElems.Append(newElem);
9033 if ( aShapeId && newElem )
9034 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9040 // create quadrangle
9041 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9042 myLastCreatedElems.Append(newElem);
9043 if ( aShapeId && newElem )
9044 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9050 else { // nbFaceNodes==8 - quadratic quadrangle
9051 SMDS_MeshElement* newElem =
9052 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9053 myLastCreatedElems.Append(newElem);
9054 if ( aShapeId && newElem )
9055 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9056 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9057 myLastCreatedElems.Append(newElem);
9058 if ( aShapeId && newElem )
9059 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9060 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9061 myLastCreatedElems.Append(newElem);
9062 if ( aShapeId && newElem )
9063 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9064 if(theFace->IsMediumNode(nodes[il1])) {
9065 // create quadrangle
9066 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9067 myLastCreatedElems.Append(newElem);
9068 if ( aShapeId && newElem )
9069 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9075 // create quadrangle
9076 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9077 myLastCreatedElems.Append(newElem);
9078 if ( aShapeId && newElem )
9079 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9085 // create needed triangles using n1,n2,n3 and inserted nodes
9086 int nbn = 2 + aNodesToInsert.size();
9087 //const SMDS_MeshNode* aNodes[nbn];
9088 vector<const SMDS_MeshNode*> aNodes(nbn);
9089 aNodes[0] = nodes[n1];
9090 aNodes[nbn-1] = nodes[n2];
9091 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9092 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9093 aNodes[iNode++] = *nIt;
9095 for(i=1; i<nbn; i++) {
9096 SMDS_MeshElement* newElem =
9097 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9098 myLastCreatedElems.Append(newElem);
9099 if ( aShapeId && newElem )
9100 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9104 aMesh->RemoveElement(theFace);
9107 //=======================================================================
9108 //function : UpdateVolumes
9110 //=======================================================================
9111 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9112 const SMDS_MeshNode* theBetweenNode2,
9113 list<const SMDS_MeshNode*>& theNodesToInsert)
9115 myLastCreatedElems.Clear();
9116 myLastCreatedNodes.Clear();
9118 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9119 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9120 const SMDS_MeshElement* elem = invElemIt->next();
9122 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9123 SMDS_VolumeTool aVolume (elem);
9124 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9127 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9128 int iface, nbFaces = aVolume.NbFaces();
9129 vector<const SMDS_MeshNode *> poly_nodes;
9130 vector<int> quantities (nbFaces);
9132 for (iface = 0; iface < nbFaces; iface++) {
9133 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9134 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9135 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9137 for (int inode = 0; inode < nbFaceNodes; inode++) {
9138 poly_nodes.push_back(faceNodes[inode]);
9140 if (nbInserted == 0) {
9141 if (faceNodes[inode] == theBetweenNode1) {
9142 if (faceNodes[inode + 1] == theBetweenNode2) {
9143 nbInserted = theNodesToInsert.size();
9145 // add nodes to insert
9146 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9147 for (; nIt != theNodesToInsert.end(); nIt++) {
9148 poly_nodes.push_back(*nIt);
9152 else if (faceNodes[inode] == theBetweenNode2) {
9153 if (faceNodes[inode + 1] == theBetweenNode1) {
9154 nbInserted = theNodesToInsert.size();
9156 // add nodes to insert in reversed order
9157 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9159 for (; nIt != theNodesToInsert.begin(); nIt--) {
9160 poly_nodes.push_back(*nIt);
9162 poly_nodes.push_back(*nIt);
9169 quantities[iface] = nbFaceNodes + nbInserted;
9172 // Replace or update the volume
9173 SMESHDS_Mesh *aMesh = GetMeshDS();
9175 if (elem->IsPoly()) {
9176 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9180 int aShapeId = FindShape( elem );
9182 SMDS_MeshElement* newElem =
9183 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9184 myLastCreatedElems.Append(newElem);
9185 if (aShapeId && newElem)
9186 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9188 aMesh->RemoveElement(elem);
9193 //=======================================================================
9195 * \brief Convert elements contained in a submesh to quadratic
9196 * \return int - nb of checked elements
9198 //=======================================================================
9200 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9201 SMESH_MesherHelper& theHelper,
9202 const bool theForce3d)
9205 if( !theSm ) return nbElem;
9207 vector<int> nbNodeInFaces;
9208 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9209 while(ElemItr->more())
9212 const SMDS_MeshElement* elem = ElemItr->next();
9213 if( !elem || elem->IsQuadratic() ) continue;
9215 int id = elem->GetID();
9216 int nbNodes = elem->NbNodes();
9217 SMDSAbs_ElementType aType = elem->GetType();
9219 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9220 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9221 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9223 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9225 const SMDS_MeshElement* NewElem = 0;
9231 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9239 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9242 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9245 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9250 case SMDSAbs_Volume :
9255 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9258 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9261 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9264 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9265 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9268 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9275 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9277 theSm->AddElement( NewElem );
9279 // if (!GetMeshDS()->isCompacted())
9280 // GetMeshDS()->compactMesh();
9284 //=======================================================================
9285 //function : ConvertToQuadratic
9287 //=======================================================================
9288 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9290 SMESHDS_Mesh* meshDS = GetMeshDS();
9292 SMESH_MesherHelper aHelper(*myMesh);
9293 aHelper.SetIsQuadratic( true );
9295 int nbCheckedElems = 0;
9296 if ( myMesh->HasShapeToMesh() )
9298 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9300 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9301 while ( smIt->more() ) {
9302 SMESH_subMesh* sm = smIt->next();
9303 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9304 aHelper.SetSubShape( sm->GetSubShape() );
9305 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9310 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9311 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9313 SMESHDS_SubMesh *smDS = 0;
9314 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9315 while(aEdgeItr->more())
9317 const SMDS_MeshEdge* edge = aEdgeItr->next();
9318 if(edge && !edge->IsQuadratic())
9320 int id = edge->GetID();
9321 //MESSAGE("edge->GetID() " << id);
9322 const SMDS_MeshNode* n1 = edge->GetNode(0);
9323 const SMDS_MeshNode* n2 = edge->GetNode(1);
9325 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9327 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9328 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9331 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9332 while(aFaceItr->more())
9334 const SMDS_MeshFace* face = aFaceItr->next();
9335 if(!face || face->IsQuadratic() ) continue;
9337 int id = face->GetID();
9338 int nbNodes = face->NbNodes();
9339 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9341 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9343 SMDS_MeshFace * NewFace = 0;
9347 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9350 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9353 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9355 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9357 vector<int> nbNodeInFaces;
9358 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9359 while(aVolumeItr->more())
9361 const SMDS_MeshVolume* volume = aVolumeItr->next();
9362 if(!volume || volume->IsQuadratic() ) continue;
9364 int id = volume->GetID();
9365 int nbNodes = volume->NbNodes();
9366 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9367 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9368 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9370 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9372 SMDS_MeshVolume * NewVolume = 0;
9376 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9377 nodes[3], id, theForce3d );
9380 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9381 nodes[3], nodes[4], id, theForce3d);
9384 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9385 nodes[3], nodes[4], nodes[5], id, theForce3d);
9388 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9389 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9392 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9394 ReplaceElemInGroups(volume, NewVolume, meshDS);
9398 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9399 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9400 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9401 aHelper.FixQuadraticElements();
9405 //================================================================================
9407 * \brief Makes given elements quadratic
9408 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9409 * \param theElements - elements to make quadratic
9411 //================================================================================
9413 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9414 TIDSortedElemSet& theElements)
9416 if ( theElements.empty() ) return;
9418 // we believe that all theElements are of the same type
9419 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9421 // get all nodes shared by theElements
9422 TIDSortedNodeSet allNodes;
9423 TIDSortedElemSet::iterator eIt = theElements.begin();
9424 for ( ; eIt != theElements.end(); ++eIt )
9425 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9427 // complete theElements with elements of lower dim whose all nodes are in allNodes
9429 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9430 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9431 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9432 for ( ; nIt != allNodes.end(); ++nIt )
9434 const SMDS_MeshNode* n = *nIt;
9435 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9436 while ( invIt->more() )
9438 const SMDS_MeshElement* e = invIt->next();
9439 if ( e->IsQuadratic() )
9441 quadAdjacentElems[ e->GetType() ].insert( e );
9444 if ( e->GetType() >= elemType )
9446 continue; // same type of more complex linear element
9449 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9450 continue; // e is already checked
9454 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9455 while ( nodeIt->more() && allIn )
9456 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9458 theElements.insert(e );
9462 SMESH_MesherHelper helper(*myMesh);
9463 helper.SetIsQuadratic( true );
9465 // add links of quadratic adjacent elements to the helper
9467 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9468 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9469 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9471 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9473 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9474 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9475 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9477 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9479 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9480 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9481 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9483 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9486 // make quadratic elements instead of linear ones
9488 SMESHDS_Mesh* meshDS = GetMeshDS();
9489 SMESHDS_SubMesh* smDS = 0;
9490 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9492 const SMDS_MeshElement* elem = *eIt;
9493 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9496 int id = elem->GetID();
9497 SMDSAbs_ElementType type = elem->GetType();
9498 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9500 if ( !smDS || !smDS->Contains( elem ))
9501 smDS = meshDS->MeshElements( elem->getshapeId() );
9502 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9504 SMDS_MeshElement * newElem = 0;
9505 switch( nodes.size() )
9507 case 4: // cases for most multiple element types go first (for optimization)
9508 if ( type == SMDSAbs_Volume )
9509 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9511 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9514 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9515 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9518 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9521 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9524 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9525 nodes[4], id, theForce3d);
9528 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9529 nodes[4], nodes[5], id, theForce3d);
9533 ReplaceElemInGroups( elem, newElem, meshDS);
9534 if( newElem && smDS )
9535 smDS->AddElement( newElem );
9538 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9539 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9540 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9541 helper.FixQuadraticElements();
9545 //=======================================================================
9547 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9548 * \return int - nb of checked elements
9550 //=======================================================================
9552 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9553 SMDS_ElemIteratorPtr theItr,
9554 const int theShapeID)
9557 SMESHDS_Mesh* meshDS = GetMeshDS();
9559 while( theItr->more() )
9561 const SMDS_MeshElement* elem = theItr->next();
9563 if( elem && elem->IsQuadratic())
9565 int id = elem->GetID();
9566 int nbCornerNodes = elem->NbCornerNodes();
9567 SMDSAbs_ElementType aType = elem->GetType();
9569 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9571 //remove a quadratic element
9572 if ( !theSm || !theSm->Contains( elem ))
9573 theSm = meshDS->MeshElements( elem->getshapeId() );
9574 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9576 // remove medium nodes
9577 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9578 if ( nodes[i]->NbInverseElements() == 0 )
9579 meshDS->RemoveFreeNode( nodes[i], theSm );
9581 // add a linear element
9582 nodes.resize( nbCornerNodes );
9583 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9584 ReplaceElemInGroups(elem, newElem, meshDS);
9585 if( theSm && newElem )
9586 theSm->AddElement( newElem );
9592 //=======================================================================
9593 //function : ConvertFromQuadratic
9595 //=======================================================================
9597 bool SMESH_MeshEditor::ConvertFromQuadratic()
9599 int nbCheckedElems = 0;
9600 if ( myMesh->HasShapeToMesh() )
9602 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9604 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9605 while ( smIt->more() ) {
9606 SMESH_subMesh* sm = smIt->next();
9607 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9608 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9614 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9615 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9617 SMESHDS_SubMesh *aSM = 0;
9618 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9626 //================================================================================
9628 * \brief Return true if all medium nodes of the element are in the node set
9630 //================================================================================
9632 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9634 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9635 if ( !nodeSet.count( elem->GetNode(i) ))
9641 //================================================================================
9643 * \brief Makes given elements linear
9645 //================================================================================
9647 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9649 if ( theElements.empty() ) return;
9651 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9652 set<int> mediumNodeIDs;
9653 TIDSortedElemSet::iterator eIt = theElements.begin();
9654 for ( ; eIt != theElements.end(); ++eIt )
9656 const SMDS_MeshElement* e = *eIt;
9657 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9658 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9661 // replace given elements by linear ones
9662 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9663 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9664 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9666 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9667 // except those elements sharing medium nodes of quadratic element whose medium nodes
9668 // are not all in mediumNodeIDs
9670 // get remaining medium nodes
9671 TIDSortedNodeSet mediumNodes;
9672 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9673 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9674 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9675 mediumNodes.insert( mediumNodes.end(), n );
9677 // find more quadratic elements to convert
9678 TIDSortedElemSet moreElemsToConvert;
9679 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9680 for ( ; nIt != mediumNodes.end(); ++nIt )
9682 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9683 while ( invIt->more() )
9685 const SMDS_MeshElement* e = invIt->next();
9686 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9688 // find a more complex element including e and
9689 // whose medium nodes are not in mediumNodes
9690 bool complexFound = false;
9691 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9693 SMDS_ElemIteratorPtr invIt2 =
9694 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9695 while ( invIt2->more() )
9697 const SMDS_MeshElement* eComplex = invIt2->next();
9698 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9700 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9701 if ( nbCommonNodes == e->NbNodes())
9703 complexFound = true;
9704 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9710 if ( !complexFound )
9711 moreElemsToConvert.insert( e );
9715 elemIt = SMDS_ElemIteratorPtr
9716 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9717 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9720 //=======================================================================
9721 //function : SewSideElements
9723 //=======================================================================
9725 SMESH_MeshEditor::Sew_Error
9726 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9727 TIDSortedElemSet& theSide2,
9728 const SMDS_MeshNode* theFirstNode1,
9729 const SMDS_MeshNode* theFirstNode2,
9730 const SMDS_MeshNode* theSecondNode1,
9731 const SMDS_MeshNode* theSecondNode2)
9733 myLastCreatedElems.Clear();
9734 myLastCreatedNodes.Clear();
9736 MESSAGE ("::::SewSideElements()");
9737 if ( theSide1.size() != theSide2.size() )
9738 return SEW_DIFF_NB_OF_ELEMENTS;
9740 Sew_Error aResult = SEW_OK;
9742 // 1. Build set of faces representing each side
9743 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9744 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9746 // =======================================================================
9747 // 1. Build set of faces representing each side:
9748 // =======================================================================
9749 // a. build set of nodes belonging to faces
9750 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9751 // c. create temporary faces representing side of volumes if correspondent
9752 // face does not exist
9754 SMESHDS_Mesh* aMesh = GetMeshDS();
9755 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9756 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9757 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9758 set<const SMDS_MeshElement*> volSet1, volSet2;
9759 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9760 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9761 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9762 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9763 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9764 int iSide, iFace, iNode;
9766 list<const SMDS_MeshElement* > tempFaceList;
9767 for ( iSide = 0; iSide < 2; iSide++ ) {
9768 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9769 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9770 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9771 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9772 set<const SMDS_MeshElement*>::iterator vIt;
9773 TIDSortedElemSet::iterator eIt;
9774 set<const SMDS_MeshNode*>::iterator nIt;
9776 // check that given nodes belong to given elements
9777 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9778 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9779 int firstIndex = -1, secondIndex = -1;
9780 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9781 const SMDS_MeshElement* elem = *eIt;
9782 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9783 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9784 if ( firstIndex > -1 && secondIndex > -1 ) break;
9786 if ( firstIndex < 0 || secondIndex < 0 ) {
9787 // we can simply return until temporary faces created
9788 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9791 // -----------------------------------------------------------
9792 // 1a. Collect nodes of existing faces
9793 // and build set of face nodes in order to detect missing
9794 // faces corresponding to sides of volumes
9795 // -----------------------------------------------------------
9797 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9799 // loop on the given element of a side
9800 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9801 //const SMDS_MeshElement* elem = *eIt;
9802 const SMDS_MeshElement* elem = *eIt;
9803 if ( elem->GetType() == SMDSAbs_Face ) {
9804 faceSet->insert( elem );
9805 set <const SMDS_MeshNode*> faceNodeSet;
9806 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9807 while ( nodeIt->more() ) {
9808 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9809 nodeSet->insert( n );
9810 faceNodeSet.insert( n );
9812 setOfFaceNodeSet.insert( faceNodeSet );
9814 else if ( elem->GetType() == SMDSAbs_Volume )
9815 volSet->insert( elem );
9817 // ------------------------------------------------------------------------------
9818 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9819 // ------------------------------------------------------------------------------
9821 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9822 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9823 while ( fIt->more() ) { // loop on faces sharing a node
9824 const SMDS_MeshElement* f = fIt->next();
9825 if ( faceSet->find( f ) == faceSet->end() ) {
9826 // check if all nodes are in nodeSet and
9827 // complete setOfFaceNodeSet if they are
9828 set <const SMDS_MeshNode*> faceNodeSet;
9829 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9830 bool allInSet = true;
9831 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9832 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9833 if ( nodeSet->find( n ) == nodeSet->end() )
9836 faceNodeSet.insert( n );
9839 faceSet->insert( f );
9840 setOfFaceNodeSet.insert( faceNodeSet );
9846 // -------------------------------------------------------------------------
9847 // 1c. Create temporary faces representing sides of volumes if correspondent
9848 // face does not exist
9849 // -------------------------------------------------------------------------
9851 if ( !volSet->empty() ) {
9852 //int nodeSetSize = nodeSet->size();
9854 // loop on given volumes
9855 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9856 SMDS_VolumeTool vol (*vIt);
9857 // loop on volume faces: find free faces
9858 // --------------------------------------
9859 list<const SMDS_MeshElement* > freeFaceList;
9860 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9861 if ( !vol.IsFreeFace( iFace ))
9863 // check if there is already a face with same nodes in a face set
9864 const SMDS_MeshElement* aFreeFace = 0;
9865 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9866 int nbNodes = vol.NbFaceNodes( iFace );
9867 set <const SMDS_MeshNode*> faceNodeSet;
9868 vol.GetFaceNodes( iFace, faceNodeSet );
9869 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9871 // no such a face is given but it still can exist, check it
9872 if ( nbNodes == 3 ) {
9873 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9875 else if ( nbNodes == 4 ) {
9876 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9879 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9880 aFreeFace = aMesh->FindFace(poly_nodes);
9884 // create a temporary face
9885 if ( nbNodes == 3 ) {
9886 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9887 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9889 else if ( nbNodes == 4 ) {
9890 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9891 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9894 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9895 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9896 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9900 freeFaceList.push_back( aFreeFace );
9901 tempFaceList.push_back( aFreeFace );
9904 } // loop on faces of a volume
9906 // choose one of several free faces
9907 // --------------------------------------
9908 if ( freeFaceList.size() > 1 ) {
9909 // choose a face having max nb of nodes shared by other elems of a side
9910 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9911 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9912 while ( fIt != freeFaceList.end() ) { // loop on free faces
9913 int nbSharedNodes = 0;
9914 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9915 while ( nodeIt->more() ) { // loop on free face nodes
9916 const SMDS_MeshNode* n =
9917 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9918 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9919 while ( invElemIt->more() ) {
9920 const SMDS_MeshElement* e = invElemIt->next();
9921 if ( faceSet->find( e ) != faceSet->end() )
9923 if ( elemSet->find( e ) != elemSet->end() )
9927 if ( nbSharedNodes >= maxNbNodes ) {
9928 maxNbNodes = nbSharedNodes;
9932 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9934 if ( freeFaceList.size() > 1 )
9936 // could not choose one face, use another way
9937 // choose a face most close to the bary center of the opposite side
9938 gp_XYZ aBC( 0., 0., 0. );
9939 set <const SMDS_MeshNode*> addedNodes;
9940 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9941 eIt = elemSet2->begin();
9942 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9943 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9944 while ( nodeIt->more() ) { // loop on free face nodes
9945 const SMDS_MeshNode* n =
9946 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9947 if ( addedNodes.insert( n ).second )
9948 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9951 aBC /= addedNodes.size();
9952 double minDist = DBL_MAX;
9953 fIt = freeFaceList.begin();
9954 while ( fIt != freeFaceList.end() ) { // loop on free faces
9956 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9957 while ( nodeIt->more() ) { // loop on free face nodes
9958 const SMDS_MeshNode* n =
9959 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9960 gp_XYZ p( n->X(),n->Y(),n->Z() );
9961 dist += ( aBC - p ).SquareModulus();
9963 if ( dist < minDist ) {
9965 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9968 fIt = freeFaceList.erase( fIt++ );
9971 } // choose one of several free faces of a volume
9973 if ( freeFaceList.size() == 1 ) {
9974 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9975 faceSet->insert( aFreeFace );
9976 // complete a node set with nodes of a found free face
9977 // for ( iNode = 0; iNode < ; iNode++ )
9978 // nodeSet->insert( fNodes[ iNode ] );
9981 } // loop on volumes of a side
9983 // // complete a set of faces if new nodes in a nodeSet appeared
9984 // // ----------------------------------------------------------
9985 // if ( nodeSetSize != nodeSet->size() ) {
9986 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9987 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9988 // while ( fIt->more() ) { // loop on faces sharing a node
9989 // const SMDS_MeshElement* f = fIt->next();
9990 // if ( faceSet->find( f ) == faceSet->end() ) {
9991 // // check if all nodes are in nodeSet and
9992 // // complete setOfFaceNodeSet if they are
9993 // set <const SMDS_MeshNode*> faceNodeSet;
9994 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9995 // bool allInSet = true;
9996 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9997 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9998 // if ( nodeSet->find( n ) == nodeSet->end() )
9999 // allInSet = false;
10001 // faceNodeSet.insert( n );
10003 // if ( allInSet ) {
10004 // faceSet->insert( f );
10005 // setOfFaceNodeSet.insert( faceNodeSet );
10011 } // Create temporary faces, if there are volumes given
10014 if ( faceSet1.size() != faceSet2.size() ) {
10015 // delete temporary faces: they are in reverseElements of actual nodes
10016 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10017 // while ( tmpFaceIt->more() )
10018 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10019 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10020 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10021 // aMesh->RemoveElement(*tmpFaceIt);
10022 MESSAGE("Diff nb of faces");
10023 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10026 // ============================================================
10027 // 2. Find nodes to merge:
10028 // bind a node to remove to a node to put instead
10029 // ============================================================
10031 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10032 if ( theFirstNode1 != theFirstNode2 )
10033 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10034 if ( theSecondNode1 != theSecondNode2 )
10035 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10037 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10038 set< long > linkIdSet; // links to process
10039 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10041 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10042 list< NLink > linkList[2];
10043 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10044 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10045 // loop on links in linkList; find faces by links and append links
10046 // of the found faces to linkList
10047 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10048 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10049 NLink link[] = { *linkIt[0], *linkIt[1] };
10050 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10051 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10054 // by links, find faces in the face sets,
10055 // and find indices of link nodes in the found faces;
10056 // in a face set, there is only one or no face sharing a link
10057 // ---------------------------------------------------------------
10059 const SMDS_MeshElement* face[] = { 0, 0 };
10060 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10061 vector<const SMDS_MeshNode*> fnodes1(9);
10062 vector<const SMDS_MeshNode*> fnodes2(9);
10063 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10064 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10065 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10066 int iLinkNode[2][2];
10067 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10068 const SMDS_MeshNode* n1 = link[iSide].first;
10069 const SMDS_MeshNode* n2 = link[iSide].second;
10070 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10071 set< const SMDS_MeshElement* > fMap;
10072 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10073 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10074 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10075 while ( fIt->more() ) { // loop on faces sharing a node
10076 const SMDS_MeshElement* f = fIt->next();
10077 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10078 ! fMap.insert( f ).second ) // f encounters twice
10080 if ( face[ iSide ] ) {
10081 MESSAGE( "2 faces per link " );
10082 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10086 faceSet->erase( f );
10087 // get face nodes and find ones of a link
10092 fnodes1.resize(f->NbNodes()+1);
10093 notLinkNodes1.resize(f->NbNodes()-2);
10096 fnodes2.resize(f->NbNodes()+1);
10097 notLinkNodes2.resize(f->NbNodes()-2);
10100 if(!f->IsQuadratic()) {
10101 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10102 while ( nIt->more() ) {
10103 const SMDS_MeshNode* n =
10104 static_cast<const SMDS_MeshNode*>( nIt->next() );
10106 iLinkNode[ iSide ][ 0 ] = iNode;
10108 else if ( n == n2 ) {
10109 iLinkNode[ iSide ][ 1 ] = iNode;
10111 //else if ( notLinkNodes[ iSide ][ 0 ] )
10112 // notLinkNodes[ iSide ][ 1 ] = n;
10114 // notLinkNodes[ iSide ][ 0 ] = n;
10118 notLinkNodes1[nbl] = n;
10119 //notLinkNodes1.push_back(n);
10121 notLinkNodes2[nbl] = n;
10122 //notLinkNodes2.push_back(n);
10124 //faceNodes[ iSide ][ iNode++ ] = n;
10126 fnodes1[iNode++] = n;
10129 fnodes2[iNode++] = n;
10133 else { // f->IsQuadratic()
10134 const SMDS_VtkFace* F =
10135 dynamic_cast<const SMDS_VtkFace*>(f);
10136 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10137 // use special nodes iterator
10138 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10139 while ( anIter->more() ) {
10140 const SMDS_MeshNode* n =
10141 static_cast<const SMDS_MeshNode*>( anIter->next() );
10143 iLinkNode[ iSide ][ 0 ] = iNode;
10145 else if ( n == n2 ) {
10146 iLinkNode[ iSide ][ 1 ] = iNode;
10151 notLinkNodes1[nbl] = n;
10154 notLinkNodes2[nbl] = n;
10158 fnodes1[iNode++] = n;
10161 fnodes2[iNode++] = n;
10165 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10167 fnodes1[iNode] = fnodes1[0];
10170 fnodes2[iNode] = fnodes1[0];
10177 // check similarity of elements of the sides
10178 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10179 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10180 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10181 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10184 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10186 break; // do not return because it s necessary to remove tmp faces
10189 // set nodes to merge
10190 // -------------------
10192 if ( face[0] && face[1] ) {
10193 int nbNodes = face[0]->NbNodes();
10194 if ( nbNodes != face[1]->NbNodes() ) {
10195 MESSAGE("Diff nb of face nodes");
10196 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10197 break; // do not return because it s necessary to remove tmp faces
10199 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10200 if ( nbNodes == 3 ) {
10201 //nReplaceMap.insert( TNodeNodeMap::value_type
10202 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10203 nReplaceMap.insert( TNodeNodeMap::value_type
10204 ( notLinkNodes1[0], notLinkNodes2[0] ));
10207 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10208 // analyse link orientation in faces
10209 int i1 = iLinkNode[ iSide ][ 0 ];
10210 int i2 = iLinkNode[ iSide ][ 1 ];
10211 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10212 // if notLinkNodes are the first and the last ones, then
10213 // their order does not correspond to the link orientation
10214 if (( i1 == 1 && i2 == 2 ) ||
10215 ( i1 == 2 && i2 == 1 ))
10216 reverse[ iSide ] = !reverse[ iSide ];
10218 if ( reverse[0] == reverse[1] ) {
10219 //nReplaceMap.insert( TNodeNodeMap::value_type
10220 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10221 //nReplaceMap.insert( TNodeNodeMap::value_type
10222 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10223 for(int nn=0; nn<nbNodes-2; nn++) {
10224 nReplaceMap.insert( TNodeNodeMap::value_type
10225 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10229 //nReplaceMap.insert( TNodeNodeMap::value_type
10230 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10231 //nReplaceMap.insert( TNodeNodeMap::value_type
10232 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10233 for(int nn=0; nn<nbNodes-2; nn++) {
10234 nReplaceMap.insert( TNodeNodeMap::value_type
10235 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10240 // add other links of the faces to linkList
10241 // -----------------------------------------
10243 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10244 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10245 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10246 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10247 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10248 if ( !iter_isnew.second ) { // already in a set: no need to process
10249 linkIdSet.erase( iter_isnew.first );
10251 else // new in set == encountered for the first time: add
10253 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10254 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10255 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10256 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10257 linkList[0].push_back ( NLink( n1, n2 ));
10258 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10262 } // loop on link lists
10264 if ( aResult == SEW_OK &&
10265 ( linkIt[0] != linkList[0].end() ||
10266 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10267 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10268 " " << (faceSetPtr[1]->empty()));
10269 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10272 // ====================================================================
10273 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10274 // ====================================================================
10276 // delete temporary faces: they are in reverseElements of actual nodes
10277 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10278 // while ( tmpFaceIt->more() )
10279 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10280 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10281 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10282 // aMesh->RemoveElement(*tmpFaceIt);
10284 if ( aResult != SEW_OK)
10287 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10288 // loop on nodes replacement map
10289 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10290 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10291 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10292 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10293 nodeIDsToRemove.push_back( nToRemove->GetID() );
10294 // loop on elements sharing nToRemove
10295 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10296 while ( invElemIt->more() ) {
10297 const SMDS_MeshElement* e = invElemIt->next();
10298 // get a new suite of nodes: make replacement
10299 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10300 vector< const SMDS_MeshNode*> nodes( nbNodes );
10301 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10302 while ( nIt->more() ) {
10303 const SMDS_MeshNode* n =
10304 static_cast<const SMDS_MeshNode*>( nIt->next() );
10305 nnIt = nReplaceMap.find( n );
10306 if ( nnIt != nReplaceMap.end() ) {
10308 n = (*nnIt).second;
10312 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10313 // elemIDsToRemove.push_back( e->GetID() );
10317 SMDSAbs_ElementType etyp = e->GetType();
10318 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10321 myLastCreatedElems.Append(newElem);
10322 AddToSameGroups(newElem, e, aMesh);
10323 int aShapeId = e->getshapeId();
10326 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10329 aMesh->RemoveElement(e);
10334 Remove( nodeIDsToRemove, true );
10339 //================================================================================
10341 * \brief Find corresponding nodes in two sets of faces
10342 * \param theSide1 - first face set
10343 * \param theSide2 - second first face
10344 * \param theFirstNode1 - a boundary node of set 1
10345 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10346 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10347 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10348 * \param nReplaceMap - output map of corresponding nodes
10349 * \return bool - is a success or not
10351 //================================================================================
10354 //#define DEBUG_MATCHING_NODES
10357 SMESH_MeshEditor::Sew_Error
10358 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10359 set<const SMDS_MeshElement*>& theSide2,
10360 const SMDS_MeshNode* theFirstNode1,
10361 const SMDS_MeshNode* theFirstNode2,
10362 const SMDS_MeshNode* theSecondNode1,
10363 const SMDS_MeshNode* theSecondNode2,
10364 TNodeNodeMap & nReplaceMap)
10366 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10368 nReplaceMap.clear();
10369 if ( theFirstNode1 != theFirstNode2 )
10370 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10371 if ( theSecondNode1 != theSecondNode2 )
10372 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10374 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10375 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10377 list< NLink > linkList[2];
10378 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10379 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10381 // loop on links in linkList; find faces by links and append links
10382 // of the found faces to linkList
10383 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10384 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10385 NLink link[] = { *linkIt[0], *linkIt[1] };
10386 if ( linkSet.find( link[0] ) == linkSet.end() )
10389 // by links, find faces in the face sets,
10390 // and find indices of link nodes in the found faces;
10391 // in a face set, there is only one or no face sharing a link
10392 // ---------------------------------------------------------------
10394 const SMDS_MeshElement* face[] = { 0, 0 };
10395 list<const SMDS_MeshNode*> notLinkNodes[2];
10396 //bool reverse[] = { false, false }; // order of notLinkNodes
10398 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10400 const SMDS_MeshNode* n1 = link[iSide].first;
10401 const SMDS_MeshNode* n2 = link[iSide].second;
10402 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10403 set< const SMDS_MeshElement* > facesOfNode1;
10404 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10406 // during a loop of the first node, we find all faces around n1,
10407 // during a loop of the second node, we find one face sharing both n1 and n2
10408 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10409 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10410 while ( fIt->more() ) { // loop on faces sharing a node
10411 const SMDS_MeshElement* f = fIt->next();
10412 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10413 ! facesOfNode1.insert( f ).second ) // f encounters twice
10415 if ( face[ iSide ] ) {
10416 MESSAGE( "2 faces per link " );
10417 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10420 faceSet->erase( f );
10422 // get not link nodes
10423 int nbN = f->NbNodes();
10424 if ( f->IsQuadratic() )
10426 nbNodes[ iSide ] = nbN;
10427 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10428 int i1 = f->GetNodeIndex( n1 );
10429 int i2 = f->GetNodeIndex( n2 );
10430 int iEnd = nbN, iBeg = -1, iDelta = 1;
10431 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10433 std::swap( iEnd, iBeg ); iDelta = -1;
10438 if ( i == iEnd ) i = iBeg + iDelta;
10439 if ( i == i1 ) break;
10440 nodes.push_back ( f->GetNode( i ) );
10446 // check similarity of elements of the sides
10447 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10448 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10449 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10450 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10453 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10457 // set nodes to merge
10458 // -------------------
10460 if ( face[0] && face[1] ) {
10461 if ( nbNodes[0] != nbNodes[1] ) {
10462 MESSAGE("Diff nb of face nodes");
10463 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10465 #ifdef DEBUG_MATCHING_NODES
10466 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10467 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10468 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10470 int nbN = nbNodes[0];
10472 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10473 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10474 for ( int i = 0 ; i < nbN - 2; ++i ) {
10475 #ifdef DEBUG_MATCHING_NODES
10476 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10478 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10482 // add other links of the face 1 to linkList
10483 // -----------------------------------------
10485 const SMDS_MeshElement* f0 = face[0];
10486 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10487 for ( int i = 0; i < nbN; i++ )
10489 const SMDS_MeshNode* n2 = f0->GetNode( i );
10490 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10491 linkSet.insert( SMESH_TLink( n1, n2 ));
10492 if ( !iter_isnew.second ) { // already in a set: no need to process
10493 linkSet.erase( iter_isnew.first );
10495 else // new in set == encountered for the first time: add
10497 #ifdef DEBUG_MATCHING_NODES
10498 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10499 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10501 linkList[0].push_back ( NLink( n1, n2 ));
10502 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10507 } // loop on link lists
10512 //================================================================================
10514 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10515 \param theElems - the list of elements (edges or faces) to be replicated
10516 The nodes for duplication could be found from these elements
10517 \param theNodesNot - list of nodes to NOT replicate
10518 \param theAffectedElems - the list of elements (cells and edges) to which the
10519 replicated nodes should be associated to.
10520 \return TRUE if operation has been completed successfully, FALSE otherwise
10522 //================================================================================
10524 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10525 const TIDSortedElemSet& theNodesNot,
10526 const TIDSortedElemSet& theAffectedElems )
10528 myLastCreatedElems.Clear();
10529 myLastCreatedNodes.Clear();
10531 if ( theElems.size() == 0 )
10534 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10539 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10540 // duplicate elements and nodes
10541 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10542 // replce nodes by duplications
10543 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10547 //================================================================================
10549 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10550 \param theMeshDS - mesh instance
10551 \param theElems - the elements replicated or modified (nodes should be changed)
10552 \param theNodesNot - nodes to NOT replicate
10553 \param theNodeNodeMap - relation of old node to new created node
10554 \param theIsDoubleElem - flag os to replicate element or modify
10555 \return TRUE if operation has been completed successfully, FALSE otherwise
10557 //================================================================================
10559 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10560 const TIDSortedElemSet& theElems,
10561 const TIDSortedElemSet& theNodesNot,
10562 std::map< const SMDS_MeshNode*,
10563 const SMDS_MeshNode* >& theNodeNodeMap,
10564 const bool theIsDoubleElem )
10566 MESSAGE("doubleNodes");
10567 // iterate on through element and duplicate them (by nodes duplication)
10569 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10570 for ( ; elemItr != theElems.end(); ++elemItr )
10572 const SMDS_MeshElement* anElem = *elemItr;
10576 bool isDuplicate = false;
10577 // duplicate nodes to duplicate element
10578 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10579 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10581 while ( anIter->more() )
10584 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10585 SMDS_MeshNode* aNewNode = aCurrNode;
10586 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10587 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10588 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10591 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10592 theNodeNodeMap[ aCurrNode ] = aNewNode;
10593 myLastCreatedNodes.Append( aNewNode );
10595 isDuplicate |= (aCurrNode != aNewNode);
10596 newNodes[ ind++ ] = aNewNode;
10598 if ( !isDuplicate )
10601 if ( theIsDoubleElem )
10602 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10605 MESSAGE("ChangeElementNodes");
10606 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10613 //================================================================================
10615 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10616 \param theNodes - identifiers of nodes to be doubled
10617 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10618 nodes. If list of element identifiers is empty then nodes are doubled but
10619 they not assigned to elements
10620 \return TRUE if operation has been completed successfully, FALSE otherwise
10622 //================================================================================
10624 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10625 const std::list< int >& theListOfModifiedElems )
10627 MESSAGE("DoubleNodes");
10628 myLastCreatedElems.Clear();
10629 myLastCreatedNodes.Clear();
10631 if ( theListOfNodes.size() == 0 )
10634 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10638 // iterate through nodes and duplicate them
10640 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10642 std::list< int >::const_iterator aNodeIter;
10643 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10645 int aCurr = *aNodeIter;
10646 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10652 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10655 anOldNodeToNewNode[ aNode ] = aNewNode;
10656 myLastCreatedNodes.Append( aNewNode );
10660 // Create map of new nodes for modified elements
10662 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10664 std::list< int >::const_iterator anElemIter;
10665 for ( anElemIter = theListOfModifiedElems.begin();
10666 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10668 int aCurr = *anElemIter;
10669 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10673 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10675 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10677 while ( anIter->more() )
10679 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10680 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10682 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10683 aNodeArr[ ind++ ] = aNewNode;
10686 aNodeArr[ ind++ ] = aCurrNode;
10688 anElemToNodes[ anElem ] = aNodeArr;
10691 // Change nodes of elements
10693 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10694 anElemToNodesIter = anElemToNodes.begin();
10695 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10697 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10698 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10701 MESSAGE("ChangeElementNodes");
10702 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10711 //================================================================================
10713 \brief Check if element located inside shape
10714 \return TRUE if IN or ON shape, FALSE otherwise
10716 //================================================================================
10718 template<class Classifier>
10719 bool isInside(const SMDS_MeshElement* theElem,
10720 Classifier& theClassifier,
10721 const double theTol)
10723 gp_XYZ centerXYZ (0, 0, 0);
10724 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10725 while (aNodeItr->more())
10726 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10728 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10729 theClassifier.Perform(aPnt, theTol);
10730 TopAbs_State aState = theClassifier.State();
10731 return (aState == TopAbs_IN || aState == TopAbs_ON );
10734 //================================================================================
10736 * \brief Classifier of the 3D point on the TopoDS_Face
10737 * with interaface suitable for isInside()
10739 //================================================================================
10741 struct _FaceClassifier
10743 Extrema_ExtPS _extremum;
10744 BRepAdaptor_Surface _surface;
10745 TopAbs_State _state;
10747 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10749 _extremum.Initialize( _surface,
10750 _surface.FirstUParameter(), _surface.LastUParameter(),
10751 _surface.FirstVParameter(), _surface.LastVParameter(),
10752 _surface.Tolerance(), _surface.Tolerance() );
10754 void Perform(const gp_Pnt& aPnt, double theTol)
10756 _state = TopAbs_OUT;
10757 _extremum.Perform(aPnt);
10758 if ( _extremum.IsDone() )
10759 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10760 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10762 TopAbs_State State() const
10769 //================================================================================
10771 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10772 \param theElems - group of of elements (edges or faces) to be replicated
10773 \param theNodesNot - group of nodes not to replicate
10774 \param theShape - shape to detect affected elements (element which geometric center
10775 located on or inside shape).
10776 The replicated nodes should be associated to affected elements.
10777 \return TRUE if operation has been completed successfully, FALSE otherwise
10779 //================================================================================
10781 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10782 const TIDSortedElemSet& theNodesNot,
10783 const TopoDS_Shape& theShape )
10785 if ( theShape.IsNull() )
10788 const double aTol = Precision::Confusion();
10789 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10790 auto_ptr<_FaceClassifier> aFaceClassifier;
10791 if ( theShape.ShapeType() == TopAbs_SOLID )
10793 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10794 bsc3d->PerformInfinitePoint(aTol);
10796 else if (theShape.ShapeType() == TopAbs_FACE )
10798 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10801 // iterates on indicated elements and get elements by back references from their nodes
10802 TIDSortedElemSet anAffected;
10803 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10804 for ( ; elemItr != theElems.end(); ++elemItr )
10806 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10810 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10811 while ( nodeItr->more() )
10813 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10814 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10816 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10817 while ( backElemItr->more() )
10819 const SMDS_MeshElement* curElem = backElemItr->next();
10820 if ( curElem && theElems.find(curElem) == theElems.end() &&
10822 isInside( curElem, *bsc3d, aTol ) :
10823 isInside( curElem, *aFaceClassifier, aTol )))
10824 anAffected.insert( curElem );
10828 return DoubleNodes( theElems, theNodesNot, anAffected );
10832 * \brief compute an oriented angle between two planes defined by four points.
10833 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10834 * @param p0 base of the rotation axe
10835 * @param p1 extremity of the rotation axe
10836 * @param g1 belongs to the first plane
10837 * @param g2 belongs to the second plane
10839 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10841 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10842 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10843 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10844 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10845 gp_Vec vref(p0, p1);
10848 gp_Vec n1 = vref.Crossed(v1);
10849 gp_Vec n2 = vref.Crossed(v2);
10850 return n2.AngleWithRef(n1, vref);
10854 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10855 * The list of groups must describe a partition of the mesh volumes.
10856 * The nodes of the internal faces at the boundaries of the groups are doubled.
10857 * In option, the internal faces are replaced by flat elements.
10858 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10859 * The flat elements are stored in groups of volumes.
10860 * @param theElems - list of groups of volumes, where a group of volume is a set of
10861 * SMDS_MeshElements sorted by Id.
10862 * @param createJointElems - if TRUE, create the elements
10863 * @return TRUE if operation has been completed successfully, FALSE otherwise
10865 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10866 bool createJointElems)
10868 MESSAGE("----------------------------------------------");
10869 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10870 MESSAGE("----------------------------------------------");
10872 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10873 meshDS->BuildDownWardConnectivity(true);
10875 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10877 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10878 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10879 // build the list of nodes shared by 2 or more domains, with their domain indexes
10881 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10882 std::map<int,int>celldom; // cell vtkId --> domain
10883 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10884 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10885 faceDomains.clear();
10887 cellDomains.clear();
10888 nodeDomains.clear();
10889 std::map<int,int> emptyMap;
10890 std::set<int> emptySet;
10893 for (int idom = 0; idom < theElems.size(); idom++)
10896 // --- build a map (face to duplicate --> volume to modify)
10897 // with all the faces shared by 2 domains (group of elements)
10898 // and corresponding volume of this domain, for each shared face.
10899 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10901 const TIDSortedElemSet& domain = theElems[idom];
10902 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10903 for (; elemItr != domain.end(); ++elemItr)
10905 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10908 int vtkId = anElem->getVtkId();
10909 int neighborsVtkIds[NBMAXNEIGHBORS];
10910 int downIds[NBMAXNEIGHBORS];
10911 unsigned char downTypes[NBMAXNEIGHBORS];
10912 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10913 for (int n = 0; n < nbNeighbors; n++)
10915 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10916 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10917 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10919 DownIdType face(downIds[n], downTypes[n]);
10920 if (!faceDomains.count(face))
10921 faceDomains[face] = emptyMap; // create an empty entry for face
10922 if (!faceDomains[face].count(idom))
10924 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10925 celldom[vtkId] = idom;
10932 //MESSAGE("Number of shared faces " << faceDomains.size());
10933 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10935 // --- explore the shared faces domain by domain,
10936 // explore the nodes of the face and see if they belong to a cell in the domain,
10937 // which has only a node or an edge on the border (not a shared face)
10939 for (int idomain = 0; idomain < theElems.size(); idomain++)
10941 const TIDSortedElemSet& domain = theElems[idomain];
10942 itface = faceDomains.begin();
10943 for (; itface != faceDomains.end(); ++itface)
10945 std::map<int, int> domvol = itface->second;
10946 if (!domvol.count(idomain))
10948 DownIdType face = itface->first;
10949 //MESSAGE(" --- face " << face.cellId);
10950 std::set<int> oldNodes;
10952 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10953 std::set<int>::iterator itn = oldNodes.begin();
10954 for (; itn != oldNodes.end(); ++itn)
10957 //MESSAGE(" node " << oldId);
10958 std::set<int> cells;
10960 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10961 for (int i=0; i<l.ncells; i++)
10963 int vtkId = l.cells[i];
10964 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10965 if (!domain.count(anElem))
10967 int vtkType = grid->GetCellType(vtkId);
10968 int downId = grid->CellIdToDownId(vtkId);
10971 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10972 continue; // not OK at this stage of the algorithm:
10973 //no cells created after BuildDownWardConnectivity
10975 DownIdType aCell(downId, vtkType);
10976 if (celldom.count(vtkId))
10978 cellDomains[aCell][idomain] = vtkId;
10979 celldom[vtkId] = idomain;
10985 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10986 // for each shared face, get the nodes
10987 // for each node, for each domain of the face, create a clone of the node
10989 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10990 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10991 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10993 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10994 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10996 for (int idomain = 0; idomain < theElems.size(); idomain++)
10998 itface = faceDomains.begin();
10999 for (; itface != faceDomains.end(); ++itface)
11001 std::map<int, int> domvol = itface->second;
11002 if (!domvol.count(idomain))
11004 DownIdType face = itface->first;
11005 //MESSAGE(" --- face " << face.cellId);
11006 std::set<int> oldNodes;
11008 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11009 bool isMultipleDetected = false;
11010 std::set<int>::iterator itn = oldNodes.begin();
11011 for (; itn != oldNodes.end(); ++itn)
11014 //MESSAGE(" node " << oldId);
11015 if (!nodeDomains.count(oldId))
11016 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11017 if (nodeDomains[oldId].empty())
11018 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11019 std::map<int, int>::iterator itdom = domvol.begin();
11020 for (; itdom != domvol.end(); ++itdom)
11022 int idom = itdom->first;
11023 //MESSAGE(" domain " << idom);
11024 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11026 if (nodeDomains[oldId].size() >= 2) // a multiple node
11028 vector<int> orderedDoms;
11029 //MESSAGE("multiple node " << oldId);
11030 isMultipleDetected =true;
11031 if (mutipleNodes.count(oldId))
11032 orderedDoms = mutipleNodes[oldId];
11035 map<int,int>::iterator it = nodeDomains[oldId].begin();
11036 for (; it != nodeDomains[oldId].end(); ++it)
11037 orderedDoms.push_back(it->first);
11039 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11040 //stringstream txt;
11041 //for (int i=0; i<orderedDoms.size(); i++)
11042 // txt << orderedDoms[i] << " ";
11043 //MESSAGE("orderedDoms " << txt.str());
11044 mutipleNodes[oldId] = orderedDoms;
11046 double *coords = grid->GetPoint(oldId);
11047 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11048 int newId = newNode->getVtkId();
11049 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11050 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11052 if (nodeDomains[oldId].size() >= 3)
11054 //MESSAGE("confirm multiple node " << oldId);
11055 isMultipleDetected =true;
11059 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11061 //MESSAGE("multiple Nodes detected on a shared face");
11062 int downId = itface->first.cellId;
11063 unsigned char cellType = itface->first.cellType;
11064 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11065 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11066 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11067 for (int ie =0; ie < nbEdges; ie++)
11070 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11071 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11073 vector<int> vn0 = mutipleNodes[nodes[0]];
11074 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11075 sort( vn0.begin(), vn0.end() );
11076 sort( vn1.begin(), vn1.end() );
11079 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11080 double *coords = grid->GetPoint(nodes[0]);
11081 gp_Pnt p0(coords[0], coords[1], coords[2]);
11082 coords = grid->GetPoint(nodes[nbNodes - 1]);
11083 gp_Pnt p1(coords[0], coords[1], coords[2]);
11085 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11086 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11087 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11088 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11089 for (int id=0; id < vn0.size(); id++)
11091 int idom = vn0[id];
11092 for (int ivol=0; ivol<nbvol; ivol++)
11094 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11095 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11096 if (theElems[idom].count(elem))
11098 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11099 domvol[idom] = svol;
11100 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11102 vtkIdType npts = 0;
11103 vtkIdType* pts = 0;
11104 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11105 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11108 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11109 angleDom[idom] = 0;
11113 gp_Pnt g(values[0], values[1], values[2]);
11114 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11115 //MESSAGE(" angle=" << angleDom[idom]);
11121 map<double, int> sortedDom; // sort domains by angle
11122 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11123 sortedDom[ia->second] = ia->first;
11124 vector<int> vnodes;
11126 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11128 vdom.push_back(ib->second);
11129 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11131 for (int ino = 0; ino < nbNodes; ino++)
11132 vnodes.push_back(nodes[ino]);
11133 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11141 // --- iterate on shared faces (volumes to modify, face to extrude)
11142 // get node id's of the face (id SMDS = id VTK)
11143 // create flat element with old and new nodes if requested
11145 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11146 // (domain1 X domain2) = domain1 + MAXINT*domain2
11148 std::map<int, std::map<long,int> > nodeQuadDomains;
11149 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11151 if (createJointElems)
11153 itface = faceDomains.begin();
11154 for (; itface != faceDomains.end(); ++itface)
11156 DownIdType face = itface->first;
11157 std::set<int> oldNodes;
11158 std::set<int>::iterator itn;
11160 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11162 std::map<int, int> domvol = itface->second;
11163 std::map<int, int>::iterator itdom = domvol.begin();
11164 int dom1 = itdom->first;
11165 int vtkVolId = itdom->second;
11167 int dom2 = itdom->first;
11168 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11170 stringstream grpname;
11173 grpname << dom1 << "_" << dom2;
11175 grpname << dom2 << "_" << dom1;
11177 string namegrp = grpname.str();
11178 if (!mapOfJunctionGroups.count(namegrp))
11179 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11180 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11182 sgrp->Add(vol->GetID());
11186 // --- create volumes on multiple domain intersection if requested
11187 // iterate on edgesMultiDomains
11189 if (createJointElems)
11191 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11192 for (; ite != edgesMultiDomains.end(); ++ite)
11194 vector<int> nodes = ite->first;
11195 vector<int> orderDom = ite->second;
11196 vector<vtkIdType> orderedNodes;
11197 if (nodes.size() == 2)
11199 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11200 for (int ino=0; ino < nodes.size(); ino++)
11201 if (orderDom.size() == 3)
11202 for (int idom = 0; idom <orderDom.size(); idom++)
11203 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11205 for (int idom = orderDom.size()-1; idom >=0; idom--)
11206 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11207 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11209 stringstream grpname;
11211 grpname << 0 << "_" << 0;
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 //MESSAGE("Quadratic multiple joints not implemented");
11223 // TODO quadratic nodes
11228 // --- list the explicit faces and edges of the mesh that need to be modified,
11229 // i.e. faces and edges built with one or more duplicated nodes.
11230 // associate these faces or edges to their corresponding domain.
11231 // only the first domain found is kept when a face or edge is shared
11233 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11234 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11235 faceOrEdgeDom.clear();
11238 for (int idomain = 0; idomain < theElems.size(); idomain++)
11240 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11241 for (; itnod != nodeDomains.end(); ++itnod)
11243 int oldId = itnod->first;
11244 //MESSAGE(" node " << oldId);
11245 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11246 for (int i = 0; i < l.ncells; i++)
11248 int vtkId = l.cells[i];
11249 int vtkType = grid->GetCellType(vtkId);
11250 int downId = grid->CellIdToDownId(vtkId);
11252 continue; // new cells: not to be modified
11253 DownIdType aCell(downId, vtkType);
11254 int volParents[1000];
11255 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11256 for (int j = 0; j < nbvol; j++)
11257 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11258 if (!feDom.count(vtkId))
11260 feDom[vtkId] = idomain;
11261 faceOrEdgeDom[aCell] = emptyMap;
11262 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11263 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11264 // << " type " << vtkType << " downId " << downId);
11270 // --- iterate on shared faces (volumes to modify, face to extrude)
11271 // get node id's of the face
11272 // replace old nodes by new nodes in volumes, and update inverse connectivity
11274 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11275 for (int m=0; m<3; m++)
11277 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11278 itface = (*amap).begin();
11279 for (; itface != (*amap).end(); ++itface)
11281 DownIdType face = itface->first;
11282 std::set<int> oldNodes;
11283 std::set<int>::iterator itn;
11285 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11286 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11287 std::map<int, int> localClonedNodeIds;
11289 std::map<int, int> domvol = itface->second;
11290 std::map<int, int>::iterator itdom = domvol.begin();
11291 for (; itdom != domvol.end(); ++itdom)
11293 int idom = itdom->first;
11294 int vtkVolId = itdom->second;
11295 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11296 localClonedNodeIds.clear();
11297 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11300 if (nodeDomains[oldId].count(idom))
11302 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11303 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11306 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11311 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11312 grid->BuildLinks();
11320 * \brief Double nodes on some external faces and create flat elements.
11321 * Flat elements are mainly used by some types of mechanic calculations.
11323 * Each group of the list must be constituted of faces.
11324 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11325 * @param theElems - list of groups of faces, where a group of faces is a set of
11326 * SMDS_MeshElements sorted by Id.
11327 * @return TRUE if operation has been completed successfully, FALSE otherwise
11329 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11331 MESSAGE("-------------------------------------------------");
11332 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11333 MESSAGE("-------------------------------------------------");
11335 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11337 // --- For each group of faces
11338 // duplicate the nodes, create a flat element based on the face
11339 // replace the nodes of the faces by their clones
11341 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11342 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11343 clonedNodes.clear();
11344 intermediateNodes.clear();
11345 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11346 mapOfJunctionGroups.clear();
11348 for (int idom = 0; idom < theElems.size(); idom++)
11350 const TIDSortedElemSet& domain = theElems[idom];
11351 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11352 for (; elemItr != domain.end(); ++elemItr)
11354 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11355 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11358 // MESSAGE("aFace=" << aFace->GetID());
11359 bool isQuad = aFace->IsQuadratic();
11360 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11362 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11364 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11365 while (nodeIt->more())
11367 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11368 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11370 ln2.push_back(node);
11372 ln0.push_back(node);
11374 const SMDS_MeshNode* clone = 0;
11375 if (!clonedNodes.count(node))
11377 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11378 clonedNodes[node] = clone;
11381 clone = clonedNodes[node];
11384 ln3.push_back(clone);
11386 ln1.push_back(clone);
11388 const SMDS_MeshNode* inter = 0;
11389 if (isQuad && (!isMedium))
11391 if (!intermediateNodes.count(node))
11393 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11394 intermediateNodes[node] = inter;
11397 inter = intermediateNodes[node];
11398 ln4.push_back(inter);
11402 // --- extrude the face
11404 vector<const SMDS_MeshNode*> ln;
11405 SMDS_MeshVolume* vol = 0;
11406 vtkIdType aType = aFace->GetVtkType();
11410 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11411 // MESSAGE("vol prism " << vol->GetID());
11412 ln.push_back(ln1[0]);
11413 ln.push_back(ln1[1]);
11414 ln.push_back(ln1[2]);
11417 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11418 // MESSAGE("vol hexa " << vol->GetID());
11419 ln.push_back(ln1[0]);
11420 ln.push_back(ln1[1]);
11421 ln.push_back(ln1[2]);
11422 ln.push_back(ln1[3]);
11424 case VTK_QUADRATIC_TRIANGLE:
11425 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11426 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11427 // MESSAGE("vol quad prism " << vol->GetID());
11428 ln.push_back(ln1[0]);
11429 ln.push_back(ln1[1]);
11430 ln.push_back(ln1[2]);
11431 ln.push_back(ln3[0]);
11432 ln.push_back(ln3[1]);
11433 ln.push_back(ln3[2]);
11435 case VTK_QUADRATIC_QUAD:
11436 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11437 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11438 // ln4[0], ln4[1], ln4[2], ln4[3]);
11439 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11440 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11441 ln4[0], ln4[1], ln4[2], ln4[3]);
11442 // MESSAGE("vol quad hexa " << vol->GetID());
11443 ln.push_back(ln1[0]);
11444 ln.push_back(ln1[1]);
11445 ln.push_back(ln1[2]);
11446 ln.push_back(ln1[3]);
11447 ln.push_back(ln3[0]);
11448 ln.push_back(ln3[1]);
11449 ln.push_back(ln3[2]);
11450 ln.push_back(ln3[3]);
11460 stringstream grpname;
11464 string namegrp = grpname.str();
11465 if (!mapOfJunctionGroups.count(namegrp))
11466 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11467 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11469 sgrp->Add(vol->GetID());
11472 // --- modify the face
11474 aFace->ChangeNodes(&ln[0], ln.size());
11480 //================================================================================
11482 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11483 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11484 * \return TRUE if operation has been completed successfully, FALSE otherwise
11486 //================================================================================
11488 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11490 // iterates on volume elements and detect all free faces on them
11491 SMESHDS_Mesh* aMesh = GetMeshDS();
11494 //bool res = false;
11495 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11496 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11499 const SMDS_MeshVolume* volume = vIt->next();
11500 SMDS_VolumeTool vTool( volume );
11501 vTool.SetExternalNormal();
11502 const bool isPoly = volume->IsPoly();
11503 const bool isQuad = volume->IsQuadratic();
11504 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11506 if (!vTool.IsFreeFace(iface))
11509 vector<const SMDS_MeshNode *> nodes;
11510 int nbFaceNodes = vTool.NbFaceNodes(iface);
11511 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11513 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11514 nodes.push_back(faceNodes[inode]);
11516 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11517 nodes.push_back(faceNodes[inode]);
11519 // add new face based on volume nodes
11520 if (aMesh->FindFace( nodes ) ) {
11522 continue; // face already exsist
11524 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11528 return ( nbFree==(nbExisted+nbCreated) );
11533 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11535 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11537 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11540 //================================================================================
11542 * \brief Creates missing boundary elements
11543 * \param elements - elements whose boundary is to be checked
11544 * \param dimension - defines type of boundary elements to create
11545 * \param group - a group to store created boundary elements in
11546 * \param targetMesh - a mesh to store created boundary elements in
11547 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11548 * \param toCopyExistingBondary - if true, not only new but also pre-existing
11549 * boundary elements will be copied into the targetMesh
11550 * \param toAddExistingBondary - if true, not only new but also pre-existing
11551 * boundary elements will be added into the new group
11552 * \param aroundElements - if true, elements will be created on boundary of given
11553 * elements else, on boundary of the whole mesh. This
11554 * option works for 2D elements only.
11555 * \return nb of added boundary elements
11557 //================================================================================
11559 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11560 Bnd_Dimension dimension,
11561 SMESH_Group* group/*=0*/,
11562 SMESH_Mesh* targetMesh/*=0*/,
11563 bool toCopyElements/*=false*/,
11564 bool toCopyExistingBondary/*=false*/,
11565 bool toAddExistingBondary/*= false*/,
11566 bool aroundElements/*= false*/)
11568 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11569 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11570 // hope that all elements are of the same type, do not check them all
11571 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11572 throw SALOME_Exception(LOCALIZED("wrong element type"));
11574 if ( aroundElements && elemType == SMDSAbs_Volume )
11575 throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11578 toCopyElements = toCopyExistingBondary = false;
11580 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11581 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11582 int nbAddedBnd = 0;
11584 // editor adding present bnd elements and optionally holding elements to add to the group
11585 SMESH_MeshEditor* presentEditor;
11586 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11587 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11589 SMDS_VolumeTool vTool;
11590 TIDSortedElemSet avoidSet;
11591 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11594 typedef vector<const SMDS_MeshNode*> TConnectivity;
11596 SMDS_ElemIteratorPtr eIt;
11597 if (elements.empty())
11598 eIt = aMesh->elementsIterator(elemType);
11600 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11602 while (eIt->more())
11604 const SMDS_MeshElement* elem = eIt->next();
11605 const int iQuad = elem->IsQuadratic();
11607 // ------------------------------------------------------------------------------------
11608 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11609 // ------------------------------------------------------------------------------------
11610 vector<const SMDS_MeshElement*> presentBndElems;
11611 vector<TConnectivity> missingBndElems;
11612 TConnectivity nodes;
11613 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11615 vTool.SetExternalNormal();
11616 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11618 if (!vTool.IsFreeFace(iface))
11620 int nbFaceNodes = vTool.NbFaceNodes(iface);
11621 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11622 if ( missType == SMDSAbs_Edge ) // boundary edges
11624 nodes.resize( 2+iQuad );
11625 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11627 for ( int j = 0; j < nodes.size(); ++j )
11629 if ( const SMDS_MeshElement* edge =
11630 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11631 presentBndElems.push_back( edge );
11633 missingBndElems.push_back( nodes );
11636 else // boundary face
11639 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11640 nodes.push_back( nn[inode] );
11642 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11643 nodes.push_back( nn[inode] );
11645 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11646 presentBndElems.push_back( f );
11648 missingBndElems.push_back( nodes );
11652 else // elem is a face ------------------------------------------
11654 avoidSet.clear(), avoidSet.insert( elem );
11655 int nbNodes = elem->NbCornerNodes();
11656 nodes.resize( 2 /*+ iQuad*/);
11657 for ( int i = 0; i < nbNodes; i++ )
11659 nodes[0] = elem->GetNode(i);
11660 nodes[1] = elem->GetNode((i+1)%nbNodes);
11661 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11662 continue; // not free link
11665 //nodes[2] = elem->GetNode( i + nbNodes );
11666 if ( const SMDS_MeshElement* edge =
11667 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11668 presentBndElems.push_back( edge );
11670 missingBndElems.push_back( nodes );
11674 // ---------------------------------
11675 // 2. Add missing boundary elements
11676 // ---------------------------------
11677 if ( targetMesh != myMesh )
11678 // instead of making a map of nodes in this mesh and targetMesh,
11679 // we create nodes with same IDs. We can renumber them later, if needed
11680 for ( int i = 0; i < missingBndElems.size(); ++i )
11682 TConnectivity& srcNodes = missingBndElems[i];
11683 TConnectivity nodes( srcNodes.size() );
11684 for ( inode = 0; inode < nodes.size(); ++inode )
11685 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11686 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11688 /*noMedium=*/true))
11690 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11694 for ( int i = 0; i < missingBndElems.size(); ++i )
11696 TConnectivity& nodes = missingBndElems[i];
11697 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11699 /*noMedium=*/true))
11701 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11705 // ----------------------------------
11706 // 3. Copy present boundary elements
11707 // ----------------------------------
11708 if ( toCopyExistingBondary )
11709 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11711 const SMDS_MeshElement* e = presentBndElems[i];
11712 TConnectivity nodes( e->NbNodes() );
11713 for ( inode = 0; inode < nodes.size(); ++inode )
11714 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11715 presentEditor->AddElement(nodes, missType, e->IsPoly());
11717 else // store present elements to add them to a group
11718 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11720 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11723 } // loop on given elements
11725 // ---------------------------------------------
11726 // 4. Fill group with boundary elements
11727 // ---------------------------------------------
11730 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11731 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11732 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11734 tgtEditor.myLastCreatedElems.Clear();
11735 tgtEditor2.myLastCreatedElems.Clear();
11737 // -----------------------
11738 // 5. Copy given elements
11739 // -----------------------
11740 if ( toCopyElements && targetMesh != myMesh )
11742 if (elements.empty())
11743 eIt = aMesh->elementsIterator(elemType);
11745 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11746 while (eIt->more())
11748 const SMDS_MeshElement* elem = eIt->next();
11749 TConnectivity nodes( elem->NbNodes() );
11750 for ( inode = 0; inode < nodes.size(); ++inode )
11751 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11752 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11754 tgtEditor.myLastCreatedElems.Clear();