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
7862 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7863 // Change nodes of polyedre
7864 const SMDS_VtkVolume* aPolyedre =
7865 dynamic_cast<const SMDS_VtkVolume*>( elem );
7867 int nbFaces = aPolyedre->NbFaces();
7869 vector<const SMDS_MeshNode *> poly_nodes;
7870 vector<int> quantities (nbFaces);
7872 for (int iface = 1; iface <= nbFaces; iface++) {
7873 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7874 quantities[iface - 1] = nbFaceNodes;
7876 for (inode = 1; inode <= nbFaceNodes; inode++) {
7877 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7879 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7880 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7881 curNode = (*nnIt).second;
7883 poly_nodes.push_back(curNode);
7886 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7890 //int elemId = elem->GetID();
7891 //MESSAGE("Change regular element or polygon " << elemId);
7892 SMDSAbs_ElementType etyp = elem->GetType();
7893 uniqueNodes.resize(nbUniqueNodes);
7894 SMDS_MeshElement* newElem = 0;
7895 if (elem->GetEntityType() == SMDSEntity_Polygon)
7896 newElem = this->AddElement(uniqueNodes, etyp, true);
7898 newElem = this->AddElement(uniqueNodes, etyp, false);
7901 myLastCreatedElems.Append(newElem);
7903 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7905 aMesh->RemoveElement(elem);
7909 // Remove invalid regular element or invalid polygon
7910 //MESSAGE("Remove invalid " << elem->GetID());
7911 rmElemIds.push_back( elem->GetID() );
7914 } // loop on elements
7916 // Remove bad elements, then equal nodes (order important)
7918 Remove( rmElemIds, false );
7919 Remove( rmNodeIds, true );
7924 // ========================================================
7925 // class : SortableElement
7926 // purpose : allow sorting elements basing on their nodes
7927 // ========================================================
7928 class SortableElement : public set <const SMDS_MeshElement*>
7932 SortableElement( const SMDS_MeshElement* theElem )
7935 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7936 while ( nodeIt->more() )
7937 this->insert( nodeIt->next() );
7940 const SMDS_MeshElement* Get() const
7943 void Set(const SMDS_MeshElement* e) const
7948 mutable const SMDS_MeshElement* myElem;
7951 //=======================================================================
7952 //function : FindEqualElements
7953 //purpose : Return list of group of elements built on the same nodes.
7954 // Search among theElements or in the whole mesh if theElements is empty
7955 //=======================================================================
7956 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7957 TListOfListOfElementsID & theGroupsOfElementsID)
7959 myLastCreatedElems.Clear();
7960 myLastCreatedNodes.Clear();
7962 typedef set<const SMDS_MeshElement*> TElemsSet;
7963 typedef map< SortableElement, int > TMapOfNodeSet;
7964 typedef list<int> TGroupOfElems;
7967 if ( theElements.empty() )
7968 { // get all elements in the mesh
7969 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7970 while ( eIt->more() )
7971 elems.insert( elems.end(), eIt->next());
7974 elems = theElements;
7976 vector< TGroupOfElems > arrayOfGroups;
7977 TGroupOfElems groupOfElems;
7978 TMapOfNodeSet mapOfNodeSet;
7980 TElemsSet::iterator elemIt = elems.begin();
7981 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7982 const SMDS_MeshElement* curElem = *elemIt;
7983 SortableElement SE(curElem);
7986 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7987 if( !(pp.second) ) {
7988 TMapOfNodeSet::iterator& itSE = pp.first;
7989 ind = (*itSE).second;
7990 arrayOfGroups[ind].push_back(curElem->GetID());
7993 groupOfElems.clear();
7994 groupOfElems.push_back(curElem->GetID());
7995 arrayOfGroups.push_back(groupOfElems);
8000 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
8001 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
8002 groupOfElems = *groupIt;
8003 if ( groupOfElems.size() > 1 ) {
8004 groupOfElems.sort();
8005 theGroupsOfElementsID.push_back(groupOfElems);
8010 //=======================================================================
8011 //function : MergeElements
8012 //purpose : In each given group, substitute all elements by the first one.
8013 //=======================================================================
8015 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8017 myLastCreatedElems.Clear();
8018 myLastCreatedNodes.Clear();
8020 typedef list<int> TListOfIDs;
8021 TListOfIDs rmElemIds; // IDs of elems to remove
8023 SMESHDS_Mesh* aMesh = GetMeshDS();
8025 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8026 while ( groupsIt != theGroupsOfElementsID.end() ) {
8027 TListOfIDs& aGroupOfElemID = *groupsIt;
8028 aGroupOfElemID.sort();
8029 int elemIDToKeep = aGroupOfElemID.front();
8030 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8031 aGroupOfElemID.pop_front();
8032 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8033 while ( idIt != aGroupOfElemID.end() ) {
8034 int elemIDToRemove = *idIt;
8035 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8036 // add the kept element in groups of removed one (PAL15188)
8037 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8038 rmElemIds.push_back( elemIDToRemove );
8044 Remove( rmElemIds, false );
8047 //=======================================================================
8048 //function : MergeEqualElements
8049 //purpose : Remove all but one of elements built on the same nodes.
8050 //=======================================================================
8052 void SMESH_MeshEditor::MergeEqualElements()
8054 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8055 to merge equal elements in the whole mesh */
8056 TListOfListOfElementsID aGroupsOfElementsID;
8057 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8058 MergeElements(aGroupsOfElementsID);
8061 //=======================================================================
8062 //function : FindFaceInSet
8063 //purpose : Return a face having linked nodes n1 and n2 and which is
8064 // - not in avoidSet,
8065 // - in elemSet provided that !elemSet.empty()
8066 // i1 and i2 optionally returns indices of n1 and n2
8067 //=======================================================================
8069 const SMDS_MeshElement*
8070 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8071 const SMDS_MeshNode* n2,
8072 const TIDSortedElemSet& elemSet,
8073 const TIDSortedElemSet& avoidSet,
8079 const SMDS_MeshElement* face = 0;
8081 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8082 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8083 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8085 //MESSAGE("in while ( invElemIt->more() && !face )");
8086 const SMDS_MeshElement* elem = invElemIt->next();
8087 if (avoidSet.count( elem ))
8089 if ( !elemSet.empty() && !elemSet.count( elem ))
8092 i1 = elem->GetNodeIndex( n1 );
8093 // find a n2 linked to n1
8094 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8095 for ( int di = -1; di < 2 && !face; di += 2 )
8097 i2 = (i1+di+nbN) % nbN;
8098 if ( elem->GetNode( i2 ) == n2 )
8101 if ( !face && elem->IsQuadratic())
8103 // analysis for quadratic elements using all nodes
8104 const SMDS_VtkFace* F =
8105 dynamic_cast<const SMDS_VtkFace*>(elem);
8106 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8107 // use special nodes iterator
8108 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8109 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8110 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8112 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8113 if ( n1 == prevN && n2 == n )
8117 else if ( n2 == prevN && n1 == n )
8119 face = elem; swap( i1, i2 );
8125 if ( n1ind ) *n1ind = i1;
8126 if ( n2ind ) *n2ind = i2;
8130 //=======================================================================
8131 //function : findAdjacentFace
8133 //=======================================================================
8135 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8136 const SMDS_MeshNode* n2,
8137 const SMDS_MeshElement* elem)
8139 TIDSortedElemSet elemSet, avoidSet;
8141 avoidSet.insert ( elem );
8142 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8145 //=======================================================================
8146 //function : FindFreeBorder
8148 //=======================================================================
8150 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8152 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8153 const SMDS_MeshNode* theSecondNode,
8154 const SMDS_MeshNode* theLastNode,
8155 list< const SMDS_MeshNode* > & theNodes,
8156 list< const SMDS_MeshElement* >& theFaces)
8158 if ( !theFirstNode || !theSecondNode )
8160 // find border face between theFirstNode and theSecondNode
8161 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8165 theFaces.push_back( curElem );
8166 theNodes.push_back( theFirstNode );
8167 theNodes.push_back( theSecondNode );
8169 //vector<const SMDS_MeshNode*> nodes;
8170 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8171 TIDSortedElemSet foundElems;
8172 bool needTheLast = ( theLastNode != 0 );
8174 while ( nStart != theLastNode ) {
8175 if ( nStart == theFirstNode )
8176 return !needTheLast;
8178 // find all free border faces sharing form nStart
8180 list< const SMDS_MeshElement* > curElemList;
8181 list< const SMDS_MeshNode* > nStartList;
8182 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8183 while ( invElemIt->more() ) {
8184 const SMDS_MeshElement* e = invElemIt->next();
8185 if ( e == curElem || foundElems.insert( e ).second ) {
8187 int iNode = 0, nbNodes = e->NbNodes();
8188 //const SMDS_MeshNode* nodes[nbNodes+1];
8189 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8191 if(e->IsQuadratic()) {
8192 const SMDS_VtkFace* F =
8193 dynamic_cast<const SMDS_VtkFace*>(e);
8194 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8195 // use special nodes iterator
8196 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8197 while( anIter->more() ) {
8198 nodes[ iNode++ ] = cast2Node(anIter->next());
8202 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8203 while ( nIt->more() )
8204 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8206 nodes[ iNode ] = nodes[ 0 ];
8208 for ( iNode = 0; iNode < nbNodes; iNode++ )
8209 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8210 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8211 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8213 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8214 curElemList.push_back( e );
8218 // analyse the found
8220 int nbNewBorders = curElemList.size();
8221 if ( nbNewBorders == 0 ) {
8222 // no free border furthermore
8223 return !needTheLast;
8225 else if ( nbNewBorders == 1 ) {
8226 // one more element found
8228 nStart = nStartList.front();
8229 curElem = curElemList.front();
8230 theFaces.push_back( curElem );
8231 theNodes.push_back( nStart );
8234 // several continuations found
8235 list< const SMDS_MeshElement* >::iterator curElemIt;
8236 list< const SMDS_MeshNode* >::iterator nStartIt;
8237 // check if one of them reached the last node
8238 if ( needTheLast ) {
8239 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8240 curElemIt!= curElemList.end();
8241 curElemIt++, nStartIt++ )
8242 if ( *nStartIt == theLastNode ) {
8243 theFaces.push_back( *curElemIt );
8244 theNodes.push_back( *nStartIt );
8248 // find the best free border by the continuations
8249 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8250 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8251 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8252 curElemIt!= curElemList.end();
8253 curElemIt++, nStartIt++ )
8255 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8256 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8257 // find one more free border
8258 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8262 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8263 // choice: clear a worse one
8264 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8265 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8266 contNodes[ iWorse ].clear();
8267 contFaces[ iWorse ].clear();
8270 if ( contNodes[0].empty() && contNodes[1].empty() )
8273 // append the best free border
8274 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8275 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8276 theNodes.pop_back(); // remove nIgnore
8277 theNodes.pop_back(); // remove nStart
8278 theFaces.pop_back(); // remove curElem
8279 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8280 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8281 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8282 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8285 } // several continuations found
8286 } // while ( nStart != theLastNode )
8291 //=======================================================================
8292 //function : CheckFreeBorderNodes
8293 //purpose : Return true if the tree nodes are on a free border
8294 //=======================================================================
8296 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8297 const SMDS_MeshNode* theNode2,
8298 const SMDS_MeshNode* theNode3)
8300 list< const SMDS_MeshNode* > nodes;
8301 list< const SMDS_MeshElement* > faces;
8302 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8305 //=======================================================================
8306 //function : SewFreeBorder
8308 //=======================================================================
8310 SMESH_MeshEditor::Sew_Error
8311 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8312 const SMDS_MeshNode* theBordSecondNode,
8313 const SMDS_MeshNode* theBordLastNode,
8314 const SMDS_MeshNode* theSideFirstNode,
8315 const SMDS_MeshNode* theSideSecondNode,
8316 const SMDS_MeshNode* theSideThirdNode,
8317 const bool theSideIsFreeBorder,
8318 const bool toCreatePolygons,
8319 const bool toCreatePolyedrs)
8321 myLastCreatedElems.Clear();
8322 myLastCreatedNodes.Clear();
8324 MESSAGE("::SewFreeBorder()");
8325 Sew_Error aResult = SEW_OK;
8327 // ====================================
8328 // find side nodes and elements
8329 // ====================================
8331 list< const SMDS_MeshNode* > nSide[ 2 ];
8332 list< const SMDS_MeshElement* > eSide[ 2 ];
8333 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8334 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8338 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8339 nSide[0], eSide[0])) {
8340 MESSAGE(" Free Border 1 not found " );
8341 aResult = SEW_BORDER1_NOT_FOUND;
8343 if (theSideIsFreeBorder) {
8346 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8347 nSide[1], eSide[1])) {
8348 MESSAGE(" Free Border 2 not found " );
8349 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8352 if ( aResult != SEW_OK )
8355 if (!theSideIsFreeBorder) {
8359 // -------------------------------------------------------------------------
8361 // 1. If nodes to merge are not coincident, move nodes of the free border
8362 // from the coord sys defined by the direction from the first to last
8363 // nodes of the border to the correspondent sys of the side 2
8364 // 2. On the side 2, find the links most co-directed with the correspondent
8365 // links of the free border
8366 // -------------------------------------------------------------------------
8368 // 1. Since sewing may break if there are volumes to split on the side 2,
8369 // we wont move nodes but just compute new coordinates for them
8370 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8371 TNodeXYZMap nBordXYZ;
8372 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8373 list< const SMDS_MeshNode* >::iterator nBordIt;
8375 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8376 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8377 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8378 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8379 double tol2 = 1.e-8;
8380 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8381 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8382 // Need node movement.
8384 // find X and Z axes to create trsf
8385 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8387 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8389 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8392 gp_Ax3 toBordAx( Pb1, Zb, X );
8393 gp_Ax3 fromSideAx( Ps1, Zs, X );
8394 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8396 gp_Trsf toBordSys, fromSide2Sys;
8397 toBordSys.SetTransformation( toBordAx );
8398 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8399 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8402 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8403 const SMDS_MeshNode* n = *nBordIt;
8404 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8405 toBordSys.Transforms( xyz );
8406 fromSide2Sys.Transforms( xyz );
8407 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8411 // just insert nodes XYZ in the nBordXYZ map
8412 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8413 const SMDS_MeshNode* n = *nBordIt;
8414 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8418 // 2. On the side 2, find the links most co-directed with the correspondent
8419 // links of the free border
8421 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8422 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8423 sideNodes.push_back( theSideFirstNode );
8425 bool hasVolumes = false;
8426 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8427 set<long> foundSideLinkIDs, checkedLinkIDs;
8428 SMDS_VolumeTool volume;
8429 //const SMDS_MeshNode* faceNodes[ 4 ];
8431 const SMDS_MeshNode* sideNode;
8432 const SMDS_MeshElement* sideElem;
8433 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8434 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8435 nBordIt = bordNodes.begin();
8437 // border node position and border link direction to compare with
8438 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8439 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8440 // choose next side node by link direction or by closeness to
8441 // the current border node:
8442 bool searchByDir = ( *nBordIt != theBordLastNode );
8444 // find the next node on the Side 2
8446 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8448 checkedLinkIDs.clear();
8449 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8451 // loop on inverse elements of current node (prevSideNode) on the Side 2
8452 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8453 while ( invElemIt->more() )
8455 const SMDS_MeshElement* elem = invElemIt->next();
8456 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8457 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8458 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8459 bool isVolume = volume.Set( elem );
8460 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8461 if ( isVolume ) // --volume
8463 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8464 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8465 if(elem->IsQuadratic()) {
8466 const SMDS_VtkFace* F =
8467 dynamic_cast<const SMDS_VtkFace*>(elem);
8468 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8469 // use special nodes iterator
8470 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8471 while( anIter->more() ) {
8472 nodes[ iNode ] = cast2Node(anIter->next());
8473 if ( nodes[ iNode++ ] == prevSideNode )
8474 iPrevNode = iNode - 1;
8478 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8479 while ( nIt->more() ) {
8480 nodes[ iNode ] = cast2Node( nIt->next() );
8481 if ( nodes[ iNode++ ] == prevSideNode )
8482 iPrevNode = iNode - 1;
8485 // there are 2 links to check
8490 // loop on links, to be precise, on the second node of links
8491 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8492 const SMDS_MeshNode* n = nodes[ iNode ];
8494 if ( !volume.IsLinked( n, prevSideNode ))
8498 if ( iNode ) // a node before prevSideNode
8499 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8500 else // a node after prevSideNode
8501 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8503 // check if this link was already used
8504 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8505 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8506 if (!isJustChecked &&
8507 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8509 // test a link geometrically
8510 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8511 bool linkIsBetter = false;
8512 double dot = 0.0, dist = 0.0;
8513 if ( searchByDir ) { // choose most co-directed link
8514 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8515 linkIsBetter = ( dot > maxDot );
8517 else { // choose link with the node closest to bordPos
8518 dist = ( nextXYZ - bordPos ).SquareModulus();
8519 linkIsBetter = ( dist < minDist );
8521 if ( linkIsBetter ) {
8530 } // loop on inverse elements of prevSideNode
8533 MESSAGE(" Cant find path by links of the Side 2 ");
8534 return SEW_BAD_SIDE_NODES;
8536 sideNodes.push_back( sideNode );
8537 sideElems.push_back( sideElem );
8538 foundSideLinkIDs.insert ( linkID );
8539 prevSideNode = sideNode;
8541 if ( *nBordIt == theBordLastNode )
8542 searchByDir = false;
8544 // find the next border link to compare with
8545 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8546 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8547 // move to next border node if sideNode is before forward border node (bordPos)
8548 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8549 prevBordNode = *nBordIt;
8551 bordPos = nBordXYZ[ *nBordIt ];
8552 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8553 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8557 while ( sideNode != theSideSecondNode );
8559 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8560 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8561 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8563 } // end nodes search on the side 2
8565 // ============================
8566 // sew the border to the side 2
8567 // ============================
8569 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8570 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8572 TListOfListOfNodes nodeGroupsToMerge;
8573 if ( nbNodes[0] == nbNodes[1] ||
8574 ( theSideIsFreeBorder && !theSideThirdNode)) {
8576 // all nodes are to be merged
8578 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8579 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8580 nIt[0]++, nIt[1]++ )
8582 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8583 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8584 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8589 // insert new nodes into the border and the side to get equal nb of segments
8591 // get normalized parameters of nodes on the borders
8592 //double param[ 2 ][ maxNbNodes ];
8594 param[0] = new double [ maxNbNodes ];
8595 param[1] = new double [ maxNbNodes ];
8597 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8598 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8599 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8600 const SMDS_MeshNode* nPrev = *nIt;
8601 double bordLength = 0;
8602 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8603 const SMDS_MeshNode* nCur = *nIt;
8604 gp_XYZ segment (nCur->X() - nPrev->X(),
8605 nCur->Y() - nPrev->Y(),
8606 nCur->Z() - nPrev->Z());
8607 double segmentLen = segment.Modulus();
8608 bordLength += segmentLen;
8609 param[ iBord ][ iNode ] = bordLength;
8612 // normalize within [0,1]
8613 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8614 param[ iBord ][ iNode ] /= bordLength;
8618 // loop on border segments
8619 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8620 int i[ 2 ] = { 0, 0 };
8621 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8622 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8624 TElemOfNodeListMap insertMap;
8625 TElemOfNodeListMap::iterator insertMapIt;
8627 // key: elem to insert nodes into
8628 // value: 2 nodes to insert between + nodes to be inserted
8630 bool next[ 2 ] = { false, false };
8632 // find min adjacent segment length after sewing
8633 double nextParam = 10., prevParam = 0;
8634 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8635 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8636 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8637 if ( i[ iBord ] > 0 )
8638 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8640 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8641 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8642 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8644 // choose to insert or to merge nodes
8645 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8646 if ( Abs( du ) <= minSegLen * 0.2 ) {
8649 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8650 const SMDS_MeshNode* n0 = *nIt[0];
8651 const SMDS_MeshNode* n1 = *nIt[1];
8652 nodeGroupsToMerge.back().push_back( n1 );
8653 nodeGroupsToMerge.back().push_back( n0 );
8654 // position of node of the border changes due to merge
8655 param[ 0 ][ i[0] ] += du;
8656 // move n1 for the sake of elem shape evaluation during insertion.
8657 // n1 will be removed by MergeNodes() anyway
8658 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8659 next[0] = next[1] = true;
8664 int intoBord = ( du < 0 ) ? 0 : 1;
8665 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8666 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8667 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8668 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8669 if ( intoBord == 1 ) {
8670 // move node of the border to be on a link of elem of the side
8671 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8672 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8673 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8674 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8675 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8677 insertMapIt = insertMap.find( elem );
8678 bool notFound = ( insertMapIt == insertMap.end() );
8679 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8681 // insert into another link of the same element:
8682 // 1. perform insertion into the other link of the elem
8683 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8684 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8685 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8686 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8687 // 2. perform insertion into the link of adjacent faces
8689 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8691 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8695 if (toCreatePolyedrs) {
8696 // perform insertion into the links of adjacent volumes
8697 UpdateVolumes(n12, n22, nodeList);
8699 // 3. find an element appeared on n1 and n2 after the insertion
8700 insertMap.erase( elem );
8701 elem = findAdjacentFace( n1, n2, 0 );
8703 if ( notFound || otherLink ) {
8704 // add element and nodes of the side into the insertMap
8705 insertMapIt = insertMap.insert
8706 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8707 (*insertMapIt).second.push_back( n1 );
8708 (*insertMapIt).second.push_back( n2 );
8710 // add node to be inserted into elem
8711 (*insertMapIt).second.push_back( nIns );
8712 next[ 1 - intoBord ] = true;
8715 // go to the next segment
8716 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8717 if ( next[ iBord ] ) {
8718 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8720 nPrev[ iBord ] = *nIt[ iBord ];
8721 nIt[ iBord ]++; i[ iBord ]++;
8725 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8727 // perform insertion of nodes into elements
8729 for (insertMapIt = insertMap.begin();
8730 insertMapIt != insertMap.end();
8733 const SMDS_MeshElement* elem = (*insertMapIt).first;
8734 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8735 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8736 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8738 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8740 if ( !theSideIsFreeBorder ) {
8741 // look for and insert nodes into the faces adjacent to elem
8743 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8745 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8750 if (toCreatePolyedrs) {
8751 // perform insertion into the links of adjacent volumes
8752 UpdateVolumes(n1, n2, nodeList);
8758 } // end: insert new nodes
8760 MergeNodes ( nodeGroupsToMerge );
8765 //=======================================================================
8766 //function : InsertNodesIntoLink
8767 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8768 // and theBetweenNode2 and split theElement
8769 //=======================================================================
8771 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8772 const SMDS_MeshNode* theBetweenNode1,
8773 const SMDS_MeshNode* theBetweenNode2,
8774 list<const SMDS_MeshNode*>& theNodesToInsert,
8775 const bool toCreatePoly)
8777 if ( theFace->GetType() != SMDSAbs_Face ) return;
8779 // find indices of 2 link nodes and of the rest nodes
8780 int iNode = 0, il1, il2, i3, i4;
8781 il1 = il2 = i3 = i4 = -1;
8782 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8783 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8785 if(theFace->IsQuadratic()) {
8786 const SMDS_VtkFace* F =
8787 dynamic_cast<const SMDS_VtkFace*>(theFace);
8788 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8789 // use special nodes iterator
8790 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8791 while( anIter->more() ) {
8792 const SMDS_MeshNode* n = cast2Node(anIter->next());
8793 if ( n == theBetweenNode1 )
8795 else if ( n == theBetweenNode2 )
8801 nodes[ iNode++ ] = n;
8805 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8806 while ( nodeIt->more() ) {
8807 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8808 if ( n == theBetweenNode1 )
8810 else if ( n == theBetweenNode2 )
8816 nodes[ iNode++ ] = n;
8819 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8822 // arrange link nodes to go one after another regarding the face orientation
8823 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8824 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8829 aNodesToInsert.reverse();
8831 // check that not link nodes of a quadrangles are in good order
8832 int nbFaceNodes = theFace->NbNodes();
8833 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8839 if (toCreatePoly || theFace->IsPoly()) {
8842 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8844 // add nodes of face up to first node of link
8847 if(theFace->IsQuadratic()) {
8848 const SMDS_VtkFace* F =
8849 dynamic_cast<const SMDS_VtkFace*>(theFace);
8850 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8851 // use special nodes iterator
8852 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8853 while( anIter->more() && !isFLN ) {
8854 const SMDS_MeshNode* n = cast2Node(anIter->next());
8855 poly_nodes[iNode++] = n;
8856 if (n == nodes[il1]) {
8860 // add nodes to insert
8861 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8862 for (; nIt != aNodesToInsert.end(); nIt++) {
8863 poly_nodes[iNode++] = *nIt;
8865 // add nodes of face starting from last node of link
8866 while ( anIter->more() ) {
8867 poly_nodes[iNode++] = cast2Node(anIter->next());
8871 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8872 while ( nodeIt->more() && !isFLN ) {
8873 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8874 poly_nodes[iNode++] = n;
8875 if (n == nodes[il1]) {
8879 // add nodes to insert
8880 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8881 for (; nIt != aNodesToInsert.end(); nIt++) {
8882 poly_nodes[iNode++] = *nIt;
8884 // add nodes of face starting from last node of link
8885 while ( nodeIt->more() ) {
8886 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8887 poly_nodes[iNode++] = n;
8891 // edit or replace the face
8892 SMESHDS_Mesh *aMesh = GetMeshDS();
8894 if (theFace->IsPoly()) {
8895 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8898 int aShapeId = FindShape( theFace );
8900 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8901 myLastCreatedElems.Append(newElem);
8902 if ( aShapeId && newElem )
8903 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8905 aMesh->RemoveElement(theFace);
8910 SMESHDS_Mesh *aMesh = GetMeshDS();
8911 if( !theFace->IsQuadratic() ) {
8913 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8914 int nbLinkNodes = 2 + aNodesToInsert.size();
8915 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8916 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8917 linkNodes[ 0 ] = nodes[ il1 ];
8918 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8919 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8920 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8921 linkNodes[ iNode++ ] = *nIt;
8923 // decide how to split a quadrangle: compare possible variants
8924 // and choose which of splits to be a quadrangle
8925 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8926 if ( nbFaceNodes == 3 ) {
8927 iBestQuad = nbSplits;
8930 else if ( nbFaceNodes == 4 ) {
8931 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8932 double aBestRate = DBL_MAX;
8933 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8935 double aBadRate = 0;
8936 // evaluate elements quality
8937 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8938 if ( iSplit == iQuad ) {
8939 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8943 aBadRate += getBadRate( &quad, aCrit );
8946 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8948 nodes[ iSplit < iQuad ? i4 : i3 ]);
8949 aBadRate += getBadRate( &tria, aCrit );
8953 if ( aBadRate < aBestRate ) {
8955 aBestRate = aBadRate;
8960 // create new elements
8961 int aShapeId = FindShape( theFace );
8964 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8965 SMDS_MeshElement* newElem = 0;
8966 if ( iSplit == iBestQuad )
8967 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8972 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8974 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8975 myLastCreatedElems.Append(newElem);
8976 if ( aShapeId && newElem )
8977 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8980 // change nodes of theFace
8981 const SMDS_MeshNode* newNodes[ 4 ];
8982 newNodes[ 0 ] = linkNodes[ i1 ];
8983 newNodes[ 1 ] = linkNodes[ i2 ];
8984 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8985 newNodes[ 3 ] = nodes[ i4 ];
8986 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8987 const SMDS_MeshElement* newElem = 0;
8988 if (iSplit == iBestQuad)
8989 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8991 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8992 myLastCreatedElems.Append(newElem);
8993 if ( aShapeId && newElem )
8994 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8995 } // end if(!theFace->IsQuadratic())
8996 else { // theFace is quadratic
8997 // we have to split theFace on simple triangles and one simple quadrangle
8999 int nbshift = tmp*2;
9000 // shift nodes in nodes[] by nbshift
9002 for(i=0; i<nbshift; i++) {
9003 const SMDS_MeshNode* n = nodes[0];
9004 for(j=0; j<nbFaceNodes-1; j++) {
9005 nodes[j] = nodes[j+1];
9007 nodes[nbFaceNodes-1] = n;
9009 il1 = il1 - nbshift;
9010 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9011 // n0 n1 n2 n0 n1 n2
9012 // +-----+-----+ +-----+-----+
9021 // create new elements
9022 int aShapeId = FindShape( theFace );
9025 if(nbFaceNodes==6) { // quadratic triangle
9026 SMDS_MeshElement* newElem =
9027 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9028 myLastCreatedElems.Append(newElem);
9029 if ( aShapeId && newElem )
9030 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031 if(theFace->IsMediumNode(nodes[il1])) {
9032 // create quadrangle
9033 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9034 myLastCreatedElems.Append(newElem);
9035 if ( aShapeId && newElem )
9036 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9042 // create quadrangle
9043 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9044 myLastCreatedElems.Append(newElem);
9045 if ( aShapeId && newElem )
9046 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9052 else { // nbFaceNodes==8 - quadratic quadrangle
9053 SMDS_MeshElement* newElem =
9054 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9055 myLastCreatedElems.Append(newElem);
9056 if ( aShapeId && newElem )
9057 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9058 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9059 myLastCreatedElems.Append(newElem);
9060 if ( aShapeId && newElem )
9061 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9062 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9063 myLastCreatedElems.Append(newElem);
9064 if ( aShapeId && newElem )
9065 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9066 if(theFace->IsMediumNode(nodes[il1])) {
9067 // create quadrangle
9068 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9069 myLastCreatedElems.Append(newElem);
9070 if ( aShapeId && newElem )
9071 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9077 // create quadrangle
9078 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9079 myLastCreatedElems.Append(newElem);
9080 if ( aShapeId && newElem )
9081 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9087 // create needed triangles using n1,n2,n3 and inserted nodes
9088 int nbn = 2 + aNodesToInsert.size();
9089 //const SMDS_MeshNode* aNodes[nbn];
9090 vector<const SMDS_MeshNode*> aNodes(nbn);
9091 aNodes[0] = nodes[n1];
9092 aNodes[nbn-1] = nodes[n2];
9093 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9094 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9095 aNodes[iNode++] = *nIt;
9097 for(i=1; i<nbn; i++) {
9098 SMDS_MeshElement* newElem =
9099 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9100 myLastCreatedElems.Append(newElem);
9101 if ( aShapeId && newElem )
9102 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9106 aMesh->RemoveElement(theFace);
9109 //=======================================================================
9110 //function : UpdateVolumes
9112 //=======================================================================
9113 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9114 const SMDS_MeshNode* theBetweenNode2,
9115 list<const SMDS_MeshNode*>& theNodesToInsert)
9117 myLastCreatedElems.Clear();
9118 myLastCreatedNodes.Clear();
9120 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9121 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9122 const SMDS_MeshElement* elem = invElemIt->next();
9124 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9125 SMDS_VolumeTool aVolume (elem);
9126 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9129 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9130 int iface, nbFaces = aVolume.NbFaces();
9131 vector<const SMDS_MeshNode *> poly_nodes;
9132 vector<int> quantities (nbFaces);
9134 for (iface = 0; iface < nbFaces; iface++) {
9135 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9136 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9137 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9139 for (int inode = 0; inode < nbFaceNodes; inode++) {
9140 poly_nodes.push_back(faceNodes[inode]);
9142 if (nbInserted == 0) {
9143 if (faceNodes[inode] == theBetweenNode1) {
9144 if (faceNodes[inode + 1] == theBetweenNode2) {
9145 nbInserted = theNodesToInsert.size();
9147 // add nodes to insert
9148 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9149 for (; nIt != theNodesToInsert.end(); nIt++) {
9150 poly_nodes.push_back(*nIt);
9154 else if (faceNodes[inode] == theBetweenNode2) {
9155 if (faceNodes[inode + 1] == theBetweenNode1) {
9156 nbInserted = theNodesToInsert.size();
9158 // add nodes to insert in reversed order
9159 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9161 for (; nIt != theNodesToInsert.begin(); nIt--) {
9162 poly_nodes.push_back(*nIt);
9164 poly_nodes.push_back(*nIt);
9171 quantities[iface] = nbFaceNodes + nbInserted;
9174 // Replace or update the volume
9175 SMESHDS_Mesh *aMesh = GetMeshDS();
9177 if (elem->IsPoly()) {
9178 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9182 int aShapeId = FindShape( elem );
9184 SMDS_MeshElement* newElem =
9185 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9186 myLastCreatedElems.Append(newElem);
9187 if (aShapeId && newElem)
9188 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9190 aMesh->RemoveElement(elem);
9195 //=======================================================================
9197 * \brief Convert elements contained in a submesh to quadratic
9198 * \return int - nb of checked elements
9200 //=======================================================================
9202 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9203 SMESH_MesherHelper& theHelper,
9204 const bool theForce3d)
9207 if( !theSm ) return nbElem;
9209 vector<int> nbNodeInFaces;
9210 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9211 while(ElemItr->more())
9214 const SMDS_MeshElement* elem = ElemItr->next();
9215 if( !elem || elem->IsQuadratic() ) continue;
9217 int id = elem->GetID();
9218 int nbNodes = elem->NbNodes();
9219 SMDSAbs_ElementType aType = elem->GetType();
9221 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9222 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9223 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9225 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9227 const SMDS_MeshElement* NewElem = 0;
9233 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9241 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9244 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9247 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9252 case SMDSAbs_Volume :
9257 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9260 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9263 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9266 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9267 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9270 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9277 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9279 theSm->AddElement( NewElem );
9281 // if (!GetMeshDS()->isCompacted())
9282 // GetMeshDS()->compactMesh();
9286 //=======================================================================
9287 //function : ConvertToQuadratic
9289 //=======================================================================
9290 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9292 SMESHDS_Mesh* meshDS = GetMeshDS();
9294 SMESH_MesherHelper aHelper(*myMesh);
9295 aHelper.SetIsQuadratic( true );
9297 int nbCheckedElems = 0;
9298 if ( myMesh->HasShapeToMesh() )
9300 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9302 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9303 while ( smIt->more() ) {
9304 SMESH_subMesh* sm = smIt->next();
9305 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9306 aHelper.SetSubShape( sm->GetSubShape() );
9307 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9312 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9313 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9315 SMESHDS_SubMesh *smDS = 0;
9316 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9317 while(aEdgeItr->more())
9319 const SMDS_MeshEdge* edge = aEdgeItr->next();
9320 if(edge && !edge->IsQuadratic())
9322 int id = edge->GetID();
9323 //MESSAGE("edge->GetID() " << id);
9324 const SMDS_MeshNode* n1 = edge->GetNode(0);
9325 const SMDS_MeshNode* n2 = edge->GetNode(1);
9327 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9329 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9330 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9333 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9334 while(aFaceItr->more())
9336 const SMDS_MeshFace* face = aFaceItr->next();
9337 if(!face || face->IsQuadratic() ) continue;
9339 int id = face->GetID();
9340 int nbNodes = face->NbNodes();
9341 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9343 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9345 SMDS_MeshFace * NewFace = 0;
9349 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9352 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9355 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9357 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9359 vector<int> nbNodeInFaces;
9360 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9361 while(aVolumeItr->more())
9363 const SMDS_MeshVolume* volume = aVolumeItr->next();
9364 if(!volume || volume->IsQuadratic() ) continue;
9366 int id = volume->GetID();
9367 int nbNodes = volume->NbNodes();
9368 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9369 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9370 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9372 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9374 SMDS_MeshVolume * NewVolume = 0;
9378 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9379 nodes[3], id, theForce3d );
9382 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9383 nodes[3], nodes[4], id, theForce3d);
9386 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9387 nodes[3], nodes[4], nodes[5], id, theForce3d);
9390 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9391 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9394 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9396 ReplaceElemInGroups(volume, NewVolume, meshDS);
9400 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9401 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9402 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9403 aHelper.FixQuadraticElements();
9407 //================================================================================
9409 * \brief Makes given elements quadratic
9410 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9411 * \param theElements - elements to make quadratic
9413 //================================================================================
9415 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9416 TIDSortedElemSet& theElements)
9418 if ( theElements.empty() ) return;
9420 // we believe that all theElements are of the same type
9421 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9423 // get all nodes shared by theElements
9424 TIDSortedNodeSet allNodes;
9425 TIDSortedElemSet::iterator eIt = theElements.begin();
9426 for ( ; eIt != theElements.end(); ++eIt )
9427 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9429 // complete theElements with elements of lower dim whose all nodes are in allNodes
9431 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9432 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9433 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9434 for ( ; nIt != allNodes.end(); ++nIt )
9436 const SMDS_MeshNode* n = *nIt;
9437 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9438 while ( invIt->more() )
9440 const SMDS_MeshElement* e = invIt->next();
9441 if ( e->IsQuadratic() )
9443 quadAdjacentElems[ e->GetType() ].insert( e );
9446 if ( e->GetType() >= elemType )
9448 continue; // same type of more complex linear element
9451 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9452 continue; // e is already checked
9456 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9457 while ( nodeIt->more() && allIn )
9458 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9460 theElements.insert(e );
9464 SMESH_MesherHelper helper(*myMesh);
9465 helper.SetIsQuadratic( true );
9467 // add links of quadratic adjacent elements to the helper
9469 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9470 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9471 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9473 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9475 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9476 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9477 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9479 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9481 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9482 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9483 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9485 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9488 // make quadratic elements instead of linear ones
9490 SMESHDS_Mesh* meshDS = GetMeshDS();
9491 SMESHDS_SubMesh* smDS = 0;
9492 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9494 const SMDS_MeshElement* elem = *eIt;
9495 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9498 int id = elem->GetID();
9499 SMDSAbs_ElementType type = elem->GetType();
9500 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9502 if ( !smDS || !smDS->Contains( elem ))
9503 smDS = meshDS->MeshElements( elem->getshapeId() );
9504 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9506 SMDS_MeshElement * newElem = 0;
9507 switch( nodes.size() )
9509 case 4: // cases for most multiple element types go first (for optimization)
9510 if ( type == SMDSAbs_Volume )
9511 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9513 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9516 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9517 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9520 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9523 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9526 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9527 nodes[4], id, theForce3d);
9530 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9531 nodes[4], nodes[5], id, theForce3d);
9535 ReplaceElemInGroups( elem, newElem, meshDS);
9536 if( newElem && smDS )
9537 smDS->AddElement( newElem );
9540 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9541 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9542 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9543 helper.FixQuadraticElements();
9547 //=======================================================================
9549 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9550 * \return int - nb of checked elements
9552 //=======================================================================
9554 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9555 SMDS_ElemIteratorPtr theItr,
9556 const int theShapeID)
9559 SMESHDS_Mesh* meshDS = GetMeshDS();
9561 while( theItr->more() )
9563 const SMDS_MeshElement* elem = theItr->next();
9565 if( elem && elem->IsQuadratic())
9567 int id = elem->GetID();
9568 int nbCornerNodes = elem->NbCornerNodes();
9569 SMDSAbs_ElementType aType = elem->GetType();
9571 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9573 //remove a quadratic element
9574 if ( !theSm || !theSm->Contains( elem ))
9575 theSm = meshDS->MeshElements( elem->getshapeId() );
9576 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9578 // remove medium nodes
9579 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9580 if ( nodes[i]->NbInverseElements() == 0 )
9581 meshDS->RemoveFreeNode( nodes[i], theSm );
9583 // add a linear element
9584 nodes.resize( nbCornerNodes );
9585 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9586 ReplaceElemInGroups(elem, newElem, meshDS);
9587 if( theSm && newElem )
9588 theSm->AddElement( newElem );
9594 //=======================================================================
9595 //function : ConvertFromQuadratic
9597 //=======================================================================
9599 bool SMESH_MeshEditor::ConvertFromQuadratic()
9601 int nbCheckedElems = 0;
9602 if ( myMesh->HasShapeToMesh() )
9604 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9606 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9607 while ( smIt->more() ) {
9608 SMESH_subMesh* sm = smIt->next();
9609 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9610 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9616 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9617 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9619 SMESHDS_SubMesh *aSM = 0;
9620 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9628 //================================================================================
9630 * \brief Return true if all medium nodes of the element are in the node set
9632 //================================================================================
9634 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9636 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9637 if ( !nodeSet.count( elem->GetNode(i) ))
9643 //================================================================================
9645 * \brief Makes given elements linear
9647 //================================================================================
9649 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9651 if ( theElements.empty() ) return;
9653 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9654 set<int> mediumNodeIDs;
9655 TIDSortedElemSet::iterator eIt = theElements.begin();
9656 for ( ; eIt != theElements.end(); ++eIt )
9658 const SMDS_MeshElement* e = *eIt;
9659 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9660 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9663 // replace given elements by linear ones
9664 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9665 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9666 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9668 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9669 // except those elements sharing medium nodes of quadratic element whose medium nodes
9670 // are not all in mediumNodeIDs
9672 // get remaining medium nodes
9673 TIDSortedNodeSet mediumNodes;
9674 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9675 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9676 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9677 mediumNodes.insert( mediumNodes.end(), n );
9679 // find more quadratic elements to convert
9680 TIDSortedElemSet moreElemsToConvert;
9681 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9682 for ( ; nIt != mediumNodes.end(); ++nIt )
9684 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9685 while ( invIt->more() )
9687 const SMDS_MeshElement* e = invIt->next();
9688 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9690 // find a more complex element including e and
9691 // whose medium nodes are not in mediumNodes
9692 bool complexFound = false;
9693 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9695 SMDS_ElemIteratorPtr invIt2 =
9696 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9697 while ( invIt2->more() )
9699 const SMDS_MeshElement* eComplex = invIt2->next();
9700 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9702 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9703 if ( nbCommonNodes == e->NbNodes())
9705 complexFound = true;
9706 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9712 if ( !complexFound )
9713 moreElemsToConvert.insert( e );
9717 elemIt = SMDS_ElemIteratorPtr
9718 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9719 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9722 //=======================================================================
9723 //function : SewSideElements
9725 //=======================================================================
9727 SMESH_MeshEditor::Sew_Error
9728 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9729 TIDSortedElemSet& theSide2,
9730 const SMDS_MeshNode* theFirstNode1,
9731 const SMDS_MeshNode* theFirstNode2,
9732 const SMDS_MeshNode* theSecondNode1,
9733 const SMDS_MeshNode* theSecondNode2)
9735 myLastCreatedElems.Clear();
9736 myLastCreatedNodes.Clear();
9738 MESSAGE ("::::SewSideElements()");
9739 if ( theSide1.size() != theSide2.size() )
9740 return SEW_DIFF_NB_OF_ELEMENTS;
9742 Sew_Error aResult = SEW_OK;
9744 // 1. Build set of faces representing each side
9745 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9746 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9748 // =======================================================================
9749 // 1. Build set of faces representing each side:
9750 // =======================================================================
9751 // a. build set of nodes belonging to faces
9752 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9753 // c. create temporary faces representing side of volumes if correspondent
9754 // face does not exist
9756 SMESHDS_Mesh* aMesh = GetMeshDS();
9757 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9758 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9759 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9760 set<const SMDS_MeshElement*> volSet1, volSet2;
9761 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9762 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9763 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9764 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9765 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9766 int iSide, iFace, iNode;
9768 list<const SMDS_MeshElement* > tempFaceList;
9769 for ( iSide = 0; iSide < 2; iSide++ ) {
9770 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9771 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9772 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9773 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9774 set<const SMDS_MeshElement*>::iterator vIt;
9775 TIDSortedElemSet::iterator eIt;
9776 set<const SMDS_MeshNode*>::iterator nIt;
9778 // check that given nodes belong to given elements
9779 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9780 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9781 int firstIndex = -1, secondIndex = -1;
9782 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9783 const SMDS_MeshElement* elem = *eIt;
9784 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9785 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9786 if ( firstIndex > -1 && secondIndex > -1 ) break;
9788 if ( firstIndex < 0 || secondIndex < 0 ) {
9789 // we can simply return until temporary faces created
9790 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9793 // -----------------------------------------------------------
9794 // 1a. Collect nodes of existing faces
9795 // and build set of face nodes in order to detect missing
9796 // faces corresponding to sides of volumes
9797 // -----------------------------------------------------------
9799 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9801 // loop on the given element of a side
9802 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9803 //const SMDS_MeshElement* elem = *eIt;
9804 const SMDS_MeshElement* elem = *eIt;
9805 if ( elem->GetType() == SMDSAbs_Face ) {
9806 faceSet->insert( elem );
9807 set <const SMDS_MeshNode*> faceNodeSet;
9808 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9809 while ( nodeIt->more() ) {
9810 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9811 nodeSet->insert( n );
9812 faceNodeSet.insert( n );
9814 setOfFaceNodeSet.insert( faceNodeSet );
9816 else if ( elem->GetType() == SMDSAbs_Volume )
9817 volSet->insert( elem );
9819 // ------------------------------------------------------------------------------
9820 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9821 // ------------------------------------------------------------------------------
9823 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9824 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9825 while ( fIt->more() ) { // loop on faces sharing a node
9826 const SMDS_MeshElement* f = fIt->next();
9827 if ( faceSet->find( f ) == faceSet->end() ) {
9828 // check if all nodes are in nodeSet and
9829 // complete setOfFaceNodeSet if they are
9830 set <const SMDS_MeshNode*> faceNodeSet;
9831 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9832 bool allInSet = true;
9833 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9834 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9835 if ( nodeSet->find( n ) == nodeSet->end() )
9838 faceNodeSet.insert( n );
9841 faceSet->insert( f );
9842 setOfFaceNodeSet.insert( faceNodeSet );
9848 // -------------------------------------------------------------------------
9849 // 1c. Create temporary faces representing sides of volumes if correspondent
9850 // face does not exist
9851 // -------------------------------------------------------------------------
9853 if ( !volSet->empty() ) {
9854 //int nodeSetSize = nodeSet->size();
9856 // loop on given volumes
9857 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9858 SMDS_VolumeTool vol (*vIt);
9859 // loop on volume faces: find free faces
9860 // --------------------------------------
9861 list<const SMDS_MeshElement* > freeFaceList;
9862 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9863 if ( !vol.IsFreeFace( iFace ))
9865 // check if there is already a face with same nodes in a face set
9866 const SMDS_MeshElement* aFreeFace = 0;
9867 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9868 int nbNodes = vol.NbFaceNodes( iFace );
9869 set <const SMDS_MeshNode*> faceNodeSet;
9870 vol.GetFaceNodes( iFace, faceNodeSet );
9871 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9873 // no such a face is given but it still can exist, check it
9874 if ( nbNodes == 3 ) {
9875 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9877 else if ( nbNodes == 4 ) {
9878 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9881 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9882 aFreeFace = aMesh->FindFace(poly_nodes);
9886 // create a temporary face
9887 if ( nbNodes == 3 ) {
9888 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9889 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9891 else if ( nbNodes == 4 ) {
9892 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9893 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9896 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9897 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9898 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9902 freeFaceList.push_back( aFreeFace );
9903 tempFaceList.push_back( aFreeFace );
9906 } // loop on faces of a volume
9908 // choose one of several free faces
9909 // --------------------------------------
9910 if ( freeFaceList.size() > 1 ) {
9911 // choose a face having max nb of nodes shared by other elems of a side
9912 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9913 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9914 while ( fIt != freeFaceList.end() ) { // loop on free faces
9915 int nbSharedNodes = 0;
9916 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9917 while ( nodeIt->more() ) { // loop on free face nodes
9918 const SMDS_MeshNode* n =
9919 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9920 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9921 while ( invElemIt->more() ) {
9922 const SMDS_MeshElement* e = invElemIt->next();
9923 if ( faceSet->find( e ) != faceSet->end() )
9925 if ( elemSet->find( e ) != elemSet->end() )
9929 if ( nbSharedNodes >= maxNbNodes ) {
9930 maxNbNodes = nbSharedNodes;
9934 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9936 if ( freeFaceList.size() > 1 )
9938 // could not choose one face, use another way
9939 // choose a face most close to the bary center of the opposite side
9940 gp_XYZ aBC( 0., 0., 0. );
9941 set <const SMDS_MeshNode*> addedNodes;
9942 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9943 eIt = elemSet2->begin();
9944 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9945 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9946 while ( nodeIt->more() ) { // loop on free face nodes
9947 const SMDS_MeshNode* n =
9948 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9949 if ( addedNodes.insert( n ).second )
9950 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9953 aBC /= addedNodes.size();
9954 double minDist = DBL_MAX;
9955 fIt = freeFaceList.begin();
9956 while ( fIt != freeFaceList.end() ) { // loop on free faces
9958 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9959 while ( nodeIt->more() ) { // loop on free face nodes
9960 const SMDS_MeshNode* n =
9961 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9962 gp_XYZ p( n->X(),n->Y(),n->Z() );
9963 dist += ( aBC - p ).SquareModulus();
9965 if ( dist < minDist ) {
9967 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9970 fIt = freeFaceList.erase( fIt++ );
9973 } // choose one of several free faces of a volume
9975 if ( freeFaceList.size() == 1 ) {
9976 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9977 faceSet->insert( aFreeFace );
9978 // complete a node set with nodes of a found free face
9979 // for ( iNode = 0; iNode < ; iNode++ )
9980 // nodeSet->insert( fNodes[ iNode ] );
9983 } // loop on volumes of a side
9985 // // complete a set of faces if new nodes in a nodeSet appeared
9986 // // ----------------------------------------------------------
9987 // if ( nodeSetSize != nodeSet->size() ) {
9988 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9989 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9990 // while ( fIt->more() ) { // loop on faces sharing a node
9991 // const SMDS_MeshElement* f = fIt->next();
9992 // if ( faceSet->find( f ) == faceSet->end() ) {
9993 // // check if all nodes are in nodeSet and
9994 // // complete setOfFaceNodeSet if they are
9995 // set <const SMDS_MeshNode*> faceNodeSet;
9996 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9997 // bool allInSet = true;
9998 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9999 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
10000 // if ( nodeSet->find( n ) == nodeSet->end() )
10001 // allInSet = false;
10003 // faceNodeSet.insert( n );
10005 // if ( allInSet ) {
10006 // faceSet->insert( f );
10007 // setOfFaceNodeSet.insert( faceNodeSet );
10013 } // Create temporary faces, if there are volumes given
10016 if ( faceSet1.size() != faceSet2.size() ) {
10017 // delete temporary faces: they are in reverseElements of actual nodes
10018 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10019 // while ( tmpFaceIt->more() )
10020 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10021 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10022 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10023 // aMesh->RemoveElement(*tmpFaceIt);
10024 MESSAGE("Diff nb of faces");
10025 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10028 // ============================================================
10029 // 2. Find nodes to merge:
10030 // bind a node to remove to a node to put instead
10031 // ============================================================
10033 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10034 if ( theFirstNode1 != theFirstNode2 )
10035 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10036 if ( theSecondNode1 != theSecondNode2 )
10037 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10039 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10040 set< long > linkIdSet; // links to process
10041 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10043 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10044 list< NLink > linkList[2];
10045 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10046 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10047 // loop on links in linkList; find faces by links and append links
10048 // of the found faces to linkList
10049 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10050 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10051 NLink link[] = { *linkIt[0], *linkIt[1] };
10052 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10053 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10056 // by links, find faces in the face sets,
10057 // and find indices of link nodes in the found faces;
10058 // in a face set, there is only one or no face sharing a link
10059 // ---------------------------------------------------------------
10061 const SMDS_MeshElement* face[] = { 0, 0 };
10062 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10063 vector<const SMDS_MeshNode*> fnodes1(9);
10064 vector<const SMDS_MeshNode*> fnodes2(9);
10065 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10066 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10067 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10068 int iLinkNode[2][2];
10069 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10070 const SMDS_MeshNode* n1 = link[iSide].first;
10071 const SMDS_MeshNode* n2 = link[iSide].second;
10072 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10073 set< const SMDS_MeshElement* > fMap;
10074 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10075 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10076 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10077 while ( fIt->more() ) { // loop on faces sharing a node
10078 const SMDS_MeshElement* f = fIt->next();
10079 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10080 ! fMap.insert( f ).second ) // f encounters twice
10082 if ( face[ iSide ] ) {
10083 MESSAGE( "2 faces per link " );
10084 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10088 faceSet->erase( f );
10089 // get face nodes and find ones of a link
10094 fnodes1.resize(f->NbNodes()+1);
10095 notLinkNodes1.resize(f->NbNodes()-2);
10098 fnodes2.resize(f->NbNodes()+1);
10099 notLinkNodes2.resize(f->NbNodes()-2);
10102 if(!f->IsQuadratic()) {
10103 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10104 while ( nIt->more() ) {
10105 const SMDS_MeshNode* n =
10106 static_cast<const SMDS_MeshNode*>( nIt->next() );
10108 iLinkNode[ iSide ][ 0 ] = iNode;
10110 else if ( n == n2 ) {
10111 iLinkNode[ iSide ][ 1 ] = iNode;
10113 //else if ( notLinkNodes[ iSide ][ 0 ] )
10114 // notLinkNodes[ iSide ][ 1 ] = n;
10116 // notLinkNodes[ iSide ][ 0 ] = n;
10120 notLinkNodes1[nbl] = n;
10121 //notLinkNodes1.push_back(n);
10123 notLinkNodes2[nbl] = n;
10124 //notLinkNodes2.push_back(n);
10126 //faceNodes[ iSide ][ iNode++ ] = n;
10128 fnodes1[iNode++] = n;
10131 fnodes2[iNode++] = n;
10135 else { // f->IsQuadratic()
10136 const SMDS_VtkFace* F =
10137 dynamic_cast<const SMDS_VtkFace*>(f);
10138 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10139 // use special nodes iterator
10140 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10141 while ( anIter->more() ) {
10142 const SMDS_MeshNode* n =
10143 static_cast<const SMDS_MeshNode*>( anIter->next() );
10145 iLinkNode[ iSide ][ 0 ] = iNode;
10147 else if ( n == n2 ) {
10148 iLinkNode[ iSide ][ 1 ] = iNode;
10153 notLinkNodes1[nbl] = n;
10156 notLinkNodes2[nbl] = n;
10160 fnodes1[iNode++] = n;
10163 fnodes2[iNode++] = n;
10167 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10169 fnodes1[iNode] = fnodes1[0];
10172 fnodes2[iNode] = fnodes1[0];
10179 // check similarity of elements of the sides
10180 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10181 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10182 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10183 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10186 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10188 break; // do not return because it s necessary to remove tmp faces
10191 // set nodes to merge
10192 // -------------------
10194 if ( face[0] && face[1] ) {
10195 int nbNodes = face[0]->NbNodes();
10196 if ( nbNodes != face[1]->NbNodes() ) {
10197 MESSAGE("Diff nb of face nodes");
10198 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10199 break; // do not return because it s necessary to remove tmp faces
10201 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10202 if ( nbNodes == 3 ) {
10203 //nReplaceMap.insert( TNodeNodeMap::value_type
10204 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10205 nReplaceMap.insert( TNodeNodeMap::value_type
10206 ( notLinkNodes1[0], notLinkNodes2[0] ));
10209 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10210 // analyse link orientation in faces
10211 int i1 = iLinkNode[ iSide ][ 0 ];
10212 int i2 = iLinkNode[ iSide ][ 1 ];
10213 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10214 // if notLinkNodes are the first and the last ones, then
10215 // their order does not correspond to the link orientation
10216 if (( i1 == 1 && i2 == 2 ) ||
10217 ( i1 == 2 && i2 == 1 ))
10218 reverse[ iSide ] = !reverse[ iSide ];
10220 if ( reverse[0] == reverse[1] ) {
10221 //nReplaceMap.insert( TNodeNodeMap::value_type
10222 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10223 //nReplaceMap.insert( TNodeNodeMap::value_type
10224 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10225 for(int nn=0; nn<nbNodes-2; nn++) {
10226 nReplaceMap.insert( TNodeNodeMap::value_type
10227 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10231 //nReplaceMap.insert( TNodeNodeMap::value_type
10232 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10233 //nReplaceMap.insert( TNodeNodeMap::value_type
10234 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10235 for(int nn=0; nn<nbNodes-2; nn++) {
10236 nReplaceMap.insert( TNodeNodeMap::value_type
10237 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10242 // add other links of the faces to linkList
10243 // -----------------------------------------
10245 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10246 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10247 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10248 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10249 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10250 if ( !iter_isnew.second ) { // already in a set: no need to process
10251 linkIdSet.erase( iter_isnew.first );
10253 else // new in set == encountered for the first time: add
10255 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10256 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10257 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10258 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10259 linkList[0].push_back ( NLink( n1, n2 ));
10260 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10264 } // loop on link lists
10266 if ( aResult == SEW_OK &&
10267 ( linkIt[0] != linkList[0].end() ||
10268 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10269 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10270 " " << (faceSetPtr[1]->empty()));
10271 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10274 // ====================================================================
10275 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10276 // ====================================================================
10278 // delete temporary faces: they are in reverseElements of actual nodes
10279 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10280 // while ( tmpFaceIt->more() )
10281 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10282 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10283 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10284 // aMesh->RemoveElement(*tmpFaceIt);
10286 if ( aResult != SEW_OK)
10289 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10290 // loop on nodes replacement map
10291 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10292 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10293 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10294 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10295 nodeIDsToRemove.push_back( nToRemove->GetID() );
10296 // loop on elements sharing nToRemove
10297 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10298 while ( invElemIt->more() ) {
10299 const SMDS_MeshElement* e = invElemIt->next();
10300 // get a new suite of nodes: make replacement
10301 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10302 vector< const SMDS_MeshNode*> nodes( nbNodes );
10303 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10304 while ( nIt->more() ) {
10305 const SMDS_MeshNode* n =
10306 static_cast<const SMDS_MeshNode*>( nIt->next() );
10307 nnIt = nReplaceMap.find( n );
10308 if ( nnIt != nReplaceMap.end() ) {
10310 n = (*nnIt).second;
10314 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10315 // elemIDsToRemove.push_back( e->GetID() );
10319 SMDSAbs_ElementType etyp = e->GetType();
10320 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10323 myLastCreatedElems.Append(newElem);
10324 AddToSameGroups(newElem, e, aMesh);
10325 int aShapeId = e->getshapeId();
10328 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10331 aMesh->RemoveElement(e);
10336 Remove( nodeIDsToRemove, true );
10341 //================================================================================
10343 * \brief Find corresponding nodes in two sets of faces
10344 * \param theSide1 - first face set
10345 * \param theSide2 - second first face
10346 * \param theFirstNode1 - a boundary node of set 1
10347 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10348 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10349 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10350 * \param nReplaceMap - output map of corresponding nodes
10351 * \return bool - is a success or not
10353 //================================================================================
10356 //#define DEBUG_MATCHING_NODES
10359 SMESH_MeshEditor::Sew_Error
10360 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10361 set<const SMDS_MeshElement*>& theSide2,
10362 const SMDS_MeshNode* theFirstNode1,
10363 const SMDS_MeshNode* theFirstNode2,
10364 const SMDS_MeshNode* theSecondNode1,
10365 const SMDS_MeshNode* theSecondNode2,
10366 TNodeNodeMap & nReplaceMap)
10368 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10370 nReplaceMap.clear();
10371 if ( theFirstNode1 != theFirstNode2 )
10372 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10373 if ( theSecondNode1 != theSecondNode2 )
10374 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10376 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10377 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10379 list< NLink > linkList[2];
10380 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10381 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10383 // loop on links in linkList; find faces by links and append links
10384 // of the found faces to linkList
10385 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10386 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10387 NLink link[] = { *linkIt[0], *linkIt[1] };
10388 if ( linkSet.find( link[0] ) == linkSet.end() )
10391 // by links, find faces in the face sets,
10392 // and find indices of link nodes in the found faces;
10393 // in a face set, there is only one or no face sharing a link
10394 // ---------------------------------------------------------------
10396 const SMDS_MeshElement* face[] = { 0, 0 };
10397 list<const SMDS_MeshNode*> notLinkNodes[2];
10398 //bool reverse[] = { false, false }; // order of notLinkNodes
10400 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10402 const SMDS_MeshNode* n1 = link[iSide].first;
10403 const SMDS_MeshNode* n2 = link[iSide].second;
10404 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10405 set< const SMDS_MeshElement* > facesOfNode1;
10406 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10408 // during a loop of the first node, we find all faces around n1,
10409 // during a loop of the second node, we find one face sharing both n1 and n2
10410 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10411 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10412 while ( fIt->more() ) { // loop on faces sharing a node
10413 const SMDS_MeshElement* f = fIt->next();
10414 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10415 ! facesOfNode1.insert( f ).second ) // f encounters twice
10417 if ( face[ iSide ] ) {
10418 MESSAGE( "2 faces per link " );
10419 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10422 faceSet->erase( f );
10424 // get not link nodes
10425 int nbN = f->NbNodes();
10426 if ( f->IsQuadratic() )
10428 nbNodes[ iSide ] = nbN;
10429 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10430 int i1 = f->GetNodeIndex( n1 );
10431 int i2 = f->GetNodeIndex( n2 );
10432 int iEnd = nbN, iBeg = -1, iDelta = 1;
10433 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10435 std::swap( iEnd, iBeg ); iDelta = -1;
10440 if ( i == iEnd ) i = iBeg + iDelta;
10441 if ( i == i1 ) break;
10442 nodes.push_back ( f->GetNode( i ) );
10448 // check similarity of elements of the sides
10449 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10450 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10451 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10452 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10455 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10459 // set nodes to merge
10460 // -------------------
10462 if ( face[0] && face[1] ) {
10463 if ( nbNodes[0] != nbNodes[1] ) {
10464 MESSAGE("Diff nb of face nodes");
10465 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10467 #ifdef DEBUG_MATCHING_NODES
10468 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10469 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10470 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10472 int nbN = nbNodes[0];
10474 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10475 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10476 for ( int i = 0 ; i < nbN - 2; ++i ) {
10477 #ifdef DEBUG_MATCHING_NODES
10478 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10480 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10484 // add other links of the face 1 to linkList
10485 // -----------------------------------------
10487 const SMDS_MeshElement* f0 = face[0];
10488 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10489 for ( int i = 0; i < nbN; i++ )
10491 const SMDS_MeshNode* n2 = f0->GetNode( i );
10492 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10493 linkSet.insert( SMESH_TLink( n1, n2 ));
10494 if ( !iter_isnew.second ) { // already in a set: no need to process
10495 linkSet.erase( iter_isnew.first );
10497 else // new in set == encountered for the first time: add
10499 #ifdef DEBUG_MATCHING_NODES
10500 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10501 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10503 linkList[0].push_back ( NLink( n1, n2 ));
10504 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10509 } // loop on link lists
10514 //================================================================================
10516 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10517 \param theElems - the list of elements (edges or faces) to be replicated
10518 The nodes for duplication could be found from these elements
10519 \param theNodesNot - list of nodes to NOT replicate
10520 \param theAffectedElems - the list of elements (cells and edges) to which the
10521 replicated nodes should be associated to.
10522 \return TRUE if operation has been completed successfully, FALSE otherwise
10524 //================================================================================
10526 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10527 const TIDSortedElemSet& theNodesNot,
10528 const TIDSortedElemSet& theAffectedElems )
10530 myLastCreatedElems.Clear();
10531 myLastCreatedNodes.Clear();
10533 if ( theElems.size() == 0 )
10536 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10541 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10542 // duplicate elements and nodes
10543 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10544 // replce nodes by duplications
10545 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10549 //================================================================================
10551 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10552 \param theMeshDS - mesh instance
10553 \param theElems - the elements replicated or modified (nodes should be changed)
10554 \param theNodesNot - nodes to NOT replicate
10555 \param theNodeNodeMap - relation of old node to new created node
10556 \param theIsDoubleElem - flag os to replicate element or modify
10557 \return TRUE if operation has been completed successfully, FALSE otherwise
10559 //================================================================================
10561 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10562 const TIDSortedElemSet& theElems,
10563 const TIDSortedElemSet& theNodesNot,
10564 std::map< const SMDS_MeshNode*,
10565 const SMDS_MeshNode* >& theNodeNodeMap,
10566 const bool theIsDoubleElem )
10568 MESSAGE("doubleNodes");
10569 // iterate on through element and duplicate them (by nodes duplication)
10571 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10572 for ( ; elemItr != theElems.end(); ++elemItr )
10574 const SMDS_MeshElement* anElem = *elemItr;
10578 bool isDuplicate = false;
10579 // duplicate nodes to duplicate element
10580 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10581 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10583 while ( anIter->more() )
10586 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10587 SMDS_MeshNode* aNewNode = aCurrNode;
10588 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10589 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10590 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10593 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10594 theNodeNodeMap[ aCurrNode ] = aNewNode;
10595 myLastCreatedNodes.Append( aNewNode );
10597 isDuplicate |= (aCurrNode != aNewNode);
10598 newNodes[ ind++ ] = aNewNode;
10600 if ( !isDuplicate )
10603 if ( theIsDoubleElem )
10604 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10607 MESSAGE("ChangeElementNodes");
10608 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10615 //================================================================================
10617 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10618 \param theNodes - identifiers of nodes to be doubled
10619 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10620 nodes. If list of element identifiers is empty then nodes are doubled but
10621 they not assigned to elements
10622 \return TRUE if operation has been completed successfully, FALSE otherwise
10624 //================================================================================
10626 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10627 const std::list< int >& theListOfModifiedElems )
10629 MESSAGE("DoubleNodes");
10630 myLastCreatedElems.Clear();
10631 myLastCreatedNodes.Clear();
10633 if ( theListOfNodes.size() == 0 )
10636 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10640 // iterate through nodes and duplicate them
10642 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10644 std::list< int >::const_iterator aNodeIter;
10645 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10647 int aCurr = *aNodeIter;
10648 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10654 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10657 anOldNodeToNewNode[ aNode ] = aNewNode;
10658 myLastCreatedNodes.Append( aNewNode );
10662 // Create map of new nodes for modified elements
10664 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10666 std::list< int >::const_iterator anElemIter;
10667 for ( anElemIter = theListOfModifiedElems.begin();
10668 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10670 int aCurr = *anElemIter;
10671 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10675 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10677 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10679 while ( anIter->more() )
10681 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10682 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10684 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10685 aNodeArr[ ind++ ] = aNewNode;
10688 aNodeArr[ ind++ ] = aCurrNode;
10690 anElemToNodes[ anElem ] = aNodeArr;
10693 // Change nodes of elements
10695 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10696 anElemToNodesIter = anElemToNodes.begin();
10697 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10699 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10700 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10703 MESSAGE("ChangeElementNodes");
10704 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10713 //================================================================================
10715 \brief Check if element located inside shape
10716 \return TRUE if IN or ON shape, FALSE otherwise
10718 //================================================================================
10720 template<class Classifier>
10721 bool isInside(const SMDS_MeshElement* theElem,
10722 Classifier& theClassifier,
10723 const double theTol)
10725 gp_XYZ centerXYZ (0, 0, 0);
10726 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10727 while (aNodeItr->more())
10728 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10730 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10731 theClassifier.Perform(aPnt, theTol);
10732 TopAbs_State aState = theClassifier.State();
10733 return (aState == TopAbs_IN || aState == TopAbs_ON );
10736 //================================================================================
10738 * \brief Classifier of the 3D point on the TopoDS_Face
10739 * with interaface suitable for isInside()
10741 //================================================================================
10743 struct _FaceClassifier
10745 Extrema_ExtPS _extremum;
10746 BRepAdaptor_Surface _surface;
10747 TopAbs_State _state;
10749 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10751 _extremum.Initialize( _surface,
10752 _surface.FirstUParameter(), _surface.LastUParameter(),
10753 _surface.FirstVParameter(), _surface.LastVParameter(),
10754 _surface.Tolerance(), _surface.Tolerance() );
10756 void Perform(const gp_Pnt& aPnt, double theTol)
10758 _state = TopAbs_OUT;
10759 _extremum.Perform(aPnt);
10760 if ( _extremum.IsDone() )
10761 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10762 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10764 TopAbs_State State() const
10771 //================================================================================
10773 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10774 \param theElems - group of of elements (edges or faces) to be replicated
10775 \param theNodesNot - group of nodes not to replicate
10776 \param theShape - shape to detect affected elements (element which geometric center
10777 located on or inside shape).
10778 The replicated nodes should be associated to affected elements.
10779 \return TRUE if operation has been completed successfully, FALSE otherwise
10781 //================================================================================
10783 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10784 const TIDSortedElemSet& theNodesNot,
10785 const TopoDS_Shape& theShape )
10787 if ( theShape.IsNull() )
10790 const double aTol = Precision::Confusion();
10791 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10792 auto_ptr<_FaceClassifier> aFaceClassifier;
10793 if ( theShape.ShapeType() == TopAbs_SOLID )
10795 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10796 bsc3d->PerformInfinitePoint(aTol);
10798 else if (theShape.ShapeType() == TopAbs_FACE )
10800 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10803 // iterates on indicated elements and get elements by back references from their nodes
10804 TIDSortedElemSet anAffected;
10805 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10806 for ( ; elemItr != theElems.end(); ++elemItr )
10808 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10812 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10813 while ( nodeItr->more() )
10815 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10816 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10818 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10819 while ( backElemItr->more() )
10821 const SMDS_MeshElement* curElem = backElemItr->next();
10822 if ( curElem && theElems.find(curElem) == theElems.end() &&
10824 isInside( curElem, *bsc3d, aTol ) :
10825 isInside( curElem, *aFaceClassifier, aTol )))
10826 anAffected.insert( curElem );
10830 return DoubleNodes( theElems, theNodesNot, anAffected );
10834 * \brief compute an oriented angle between two planes defined by four points.
10835 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10836 * @param p0 base of the rotation axe
10837 * @param p1 extremity of the rotation axe
10838 * @param g1 belongs to the first plane
10839 * @param g2 belongs to the second plane
10841 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10843 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10844 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10845 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10846 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10847 gp_Vec vref(p0, p1);
10850 gp_Vec n1 = vref.Crossed(v1);
10851 gp_Vec n2 = vref.Crossed(v2);
10852 return n2.AngleWithRef(n1, vref);
10856 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10857 * The list of groups must describe a partition of the mesh volumes.
10858 * The nodes of the internal faces at the boundaries of the groups are doubled.
10859 * In option, the internal faces are replaced by flat elements.
10860 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10861 * The flat elements are stored in groups of volumes.
10862 * @param theElems - list of groups of volumes, where a group of volume is a set of
10863 * SMDS_MeshElements sorted by Id.
10864 * @param createJointElems - if TRUE, create the elements
10865 * @return TRUE if operation has been completed successfully, FALSE otherwise
10867 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10868 bool createJointElems)
10870 MESSAGE("----------------------------------------------");
10871 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10872 MESSAGE("----------------------------------------------");
10874 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10875 meshDS->BuildDownWardConnectivity(true);
10877 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10879 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10880 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10881 // build the list of nodes shared by 2 or more domains, with their domain indexes
10883 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10884 std::map<int,int>celldom; // cell vtkId --> domain
10885 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10886 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10887 faceDomains.clear();
10889 cellDomains.clear();
10890 nodeDomains.clear();
10891 std::map<int,int> emptyMap;
10892 std::set<int> emptySet;
10895 for (int idom = 0; idom < theElems.size(); idom++)
10898 // --- build a map (face to duplicate --> volume to modify)
10899 // with all the faces shared by 2 domains (group of elements)
10900 // and corresponding volume of this domain, for each shared face.
10901 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10903 const TIDSortedElemSet& domain = theElems[idom];
10904 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10905 for (; elemItr != domain.end(); ++elemItr)
10907 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10910 int vtkId = anElem->getVtkId();
10911 int neighborsVtkIds[NBMAXNEIGHBORS];
10912 int downIds[NBMAXNEIGHBORS];
10913 unsigned char downTypes[NBMAXNEIGHBORS];
10914 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10915 for (int n = 0; n < nbNeighbors; n++)
10917 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10918 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10919 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10921 DownIdType face(downIds[n], downTypes[n]);
10922 if (!faceDomains.count(face))
10923 faceDomains[face] = emptyMap; // create an empty entry for face
10924 if (!faceDomains[face].count(idom))
10926 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10927 celldom[vtkId] = idom;
10934 //MESSAGE("Number of shared faces " << faceDomains.size());
10935 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10937 // --- explore the shared faces domain by domain,
10938 // explore the nodes of the face and see if they belong to a cell in the domain,
10939 // which has only a node or an edge on the border (not a shared face)
10941 for (int idomain = 0; idomain < theElems.size(); idomain++)
10943 const TIDSortedElemSet& domain = theElems[idomain];
10944 itface = faceDomains.begin();
10945 for (; itface != faceDomains.end(); ++itface)
10947 std::map<int, int> domvol = itface->second;
10948 if (!domvol.count(idomain))
10950 DownIdType face = itface->first;
10951 //MESSAGE(" --- face " << face.cellId);
10952 std::set<int> oldNodes;
10954 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10955 std::set<int>::iterator itn = oldNodes.begin();
10956 for (; itn != oldNodes.end(); ++itn)
10959 //MESSAGE(" node " << oldId);
10960 std::set<int> cells;
10962 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10963 for (int i=0; i<l.ncells; i++)
10965 int vtkId = l.cells[i];
10966 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10967 if (!domain.count(anElem))
10969 int vtkType = grid->GetCellType(vtkId);
10970 int downId = grid->CellIdToDownId(vtkId);
10971 DownIdType aCell(downId, vtkType);
10972 if (celldom.count(vtkId))
10974 cellDomains[aCell][idomain] = vtkId;
10975 celldom[vtkId] = idomain;
10981 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10982 // for each shared face, get the nodes
10983 // for each node, for each domain of the face, create a clone of the node
10985 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10986 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10987 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10989 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10990 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10992 for (int idomain = 0; idomain < theElems.size(); idomain++)
10994 itface = faceDomains.begin();
10995 for (; itface != faceDomains.end(); ++itface)
10997 std::map<int, int> domvol = itface->second;
10998 if (!domvol.count(idomain))
11000 DownIdType face = itface->first;
11001 //MESSAGE(" --- face " << face.cellId);
11002 std::set<int> oldNodes;
11004 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11005 bool isMultipleDetected = false;
11006 std::set<int>::iterator itn = oldNodes.begin();
11007 for (; itn != oldNodes.end(); ++itn)
11010 //MESSAGE(" node " << oldId);
11011 if (!nodeDomains.count(oldId))
11012 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11013 if (nodeDomains[oldId].empty())
11014 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11015 std::map<int, int>::iterator itdom = domvol.begin();
11016 for (; itdom != domvol.end(); ++itdom)
11018 int idom = itdom->first;
11019 //MESSAGE(" domain " << idom);
11020 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11022 if (nodeDomains[oldId].size() >= 2) // a multiple node
11024 vector<int> orderedDoms;
11025 //MESSAGE("multiple node " << oldId);
11026 isMultipleDetected =true;
11027 if (mutipleNodes.count(oldId))
11028 orderedDoms = mutipleNodes[oldId];
11031 map<int,int>::iterator it = nodeDomains[oldId].begin();
11032 for (; it != nodeDomains[oldId].end(); ++it)
11033 orderedDoms.push_back(it->first);
11035 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11036 //stringstream txt;
11037 //for (int i=0; i<orderedDoms.size(); i++)
11038 // txt << orderedDoms[i] << " ";
11039 //MESSAGE("orderedDoms " << txt.str());
11040 mutipleNodes[oldId] = orderedDoms;
11042 double *coords = grid->GetPoint(oldId);
11043 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11044 int newId = newNode->getVtkId();
11045 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11046 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11050 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11052 //MESSAGE("multiple Nodes detected on a shared face");
11053 int downId = itface->first.cellId;
11054 unsigned char cellType = itface->first.cellType;
11055 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11056 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11057 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11058 for (int ie =0; ie < nbEdges; ie++)
11061 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11062 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11064 vector<int> vn0 = mutipleNodes[nodes[0]];
11065 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11066 sort( vn0.begin(), vn0.end() );
11067 sort( vn1.begin(), vn1.end() );
11070 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11071 double *coords = grid->GetPoint(nodes[0]);
11072 gp_Pnt p0(coords[0], coords[1], coords[2]);
11073 coords = grid->GetPoint(nodes[nbNodes - 1]);
11074 gp_Pnt p1(coords[0], coords[1], coords[2]);
11076 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11077 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11078 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11079 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11080 for (int id=0; id < vn0.size(); id++)
11082 int idom = vn0[id];
11083 for (int ivol=0; ivol<nbvol; ivol++)
11085 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11086 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11087 if (theElems[idom].count(elem))
11089 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11090 domvol[idom] = svol;
11091 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11093 vtkIdType npts = 0;
11094 vtkIdType* pts = 0;
11095 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11096 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11099 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11100 angleDom[idom] = 0;
11104 gp_Pnt g(values[0], values[1], values[2]);
11105 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11106 //MESSAGE(" angle=" << angleDom[idom]);
11112 map<double, int> sortedDom; // sort domains by angle
11113 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11114 sortedDom[ia->second] = ia->first;
11115 vector<int> vnodes;
11117 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11119 vdom.push_back(ib->second);
11120 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11122 for (int ino = 0; ino < nbNodes; ino++)
11123 vnodes.push_back(nodes[ino]);
11124 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11132 // --- iterate on shared faces (volumes to modify, face to extrude)
11133 // get node id's of the face (id SMDS = id VTK)
11134 // create flat element with old and new nodes if requested
11136 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11137 // (domain1 X domain2) = domain1 + MAXINT*domain2
11139 std::map<int, std::map<long,int> > nodeQuadDomains;
11140 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11142 if (createJointElems)
11144 itface = faceDomains.begin();
11145 for (; itface != faceDomains.end(); ++itface)
11147 DownIdType face = itface->first;
11148 std::set<int> oldNodes;
11149 std::set<int>::iterator itn;
11151 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11153 std::map<int, int> domvol = itface->second;
11154 std::map<int, int>::iterator itdom = domvol.begin();
11155 int dom1 = itdom->first;
11156 int vtkVolId = itdom->second;
11158 int dom2 = itdom->first;
11159 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11161 stringstream grpname;
11164 grpname << dom1 << "_" << dom2;
11166 grpname << dom2 << "_" << dom1;
11168 string namegrp = grpname.str();
11169 if (!mapOfJunctionGroups.count(namegrp))
11170 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11171 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11173 sgrp->Add(vol->GetID());
11177 // --- create volumes on multiple domain intersection if requested
11178 // iterate on edgesMultiDomains
11180 if (createJointElems)
11182 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11183 for (; ite != edgesMultiDomains.end(); ++ite)
11185 vector<int> nodes = ite->first;
11186 vector<int> orderDom = ite->second;
11187 vector<vtkIdType> orderedNodes;
11188 if (nodes.size() == 2)
11190 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11191 for (int ino=0; ino < nodes.size(); ino++)
11192 if (orderDom.size() == 3)
11193 for (int idom = 0; idom <orderDom.size(); idom++)
11194 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11196 for (int idom = orderDom.size()-1; idom >=0; idom--)
11197 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11198 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11200 stringstream grpname;
11202 grpname << 0 << "_" << 0;
11204 string namegrp = grpname.str();
11205 if (!mapOfJunctionGroups.count(namegrp))
11206 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11207 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11209 sgrp->Add(vol->GetID());
11213 // TODO quadratic nodes
11218 // --- list the explicit faces and edges of the mesh that need to be modified,
11219 // i.e. faces and edges built with one or more duplicated nodes.
11220 // associate these faces or edges to their corresponding domain.
11221 // only the first domain found is kept when a face or edge is shared
11223 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11224 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11225 faceOrEdgeDom.clear();
11228 for (int idomain = 0; idomain < theElems.size(); idomain++)
11230 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11231 for (; itnod != nodeDomains.end(); ++itnod)
11233 int oldId = itnod->first;
11234 //MESSAGE(" node " << oldId);
11235 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11236 for (int i = 0; i < l.ncells; i++)
11238 int vtkId = l.cells[i];
11239 int vtkType = grid->GetCellType(vtkId);
11240 int downId = grid->CellIdToDownId(vtkId);
11241 DownIdType aCell(downId, vtkType);
11242 int volParents[1000];
11243 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11244 for (int j = 0; j < nbvol; j++)
11245 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11246 if (!feDom.count(vtkId))
11248 feDom[vtkId] = idomain;
11249 faceOrEdgeDom[aCell] = emptyMap;
11250 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11251 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11252 // << " type " << vtkType << " downId " << downId);
11258 // --- iterate on shared faces (volumes to modify, face to extrude)
11259 // get node id's of the face
11260 // replace old nodes by new nodes in volumes, and update inverse connectivity
11262 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11263 for (int m=0; m<3; m++)
11265 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11266 itface = (*amap).begin();
11267 for (; itface != (*amap).end(); ++itface)
11269 DownIdType face = itface->first;
11270 std::set<int> oldNodes;
11271 std::set<int>::iterator itn;
11273 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11274 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11275 std::map<int, int> localClonedNodeIds;
11277 std::map<int, int> domvol = itface->second;
11278 std::map<int, int>::iterator itdom = domvol.begin();
11279 for (; itdom != domvol.end(); ++itdom)
11281 int idom = itdom->first;
11282 int vtkVolId = itdom->second;
11283 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11284 localClonedNodeIds.clear();
11285 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11288 if (nodeDomains[oldId].count(idom))
11290 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11291 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11294 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11299 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11300 grid->BuildLinks();
11308 * \brief Double nodes on some external faces and create flat elements.
11309 * Flat elements are mainly used by some types of mechanic calculations.
11311 * Each group of the list must be constituted of faces.
11312 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11313 * @param theElems - list of groups of faces, where a group of faces is a set of
11314 * SMDS_MeshElements sorted by Id.
11315 * @return TRUE if operation has been completed successfully, FALSE otherwise
11317 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11319 MESSAGE("-------------------------------------------------");
11320 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11321 MESSAGE("-------------------------------------------------");
11323 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11325 // --- For each group of faces
11326 // duplicate the nodes, create a flat element based on the face
11327 // replace the nodes of the faces by their clones
11329 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11330 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11331 clonedNodes.clear();
11332 intermediateNodes.clear();
11333 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11334 mapOfJunctionGroups.clear();
11336 for (int idom = 0; idom < theElems.size(); idom++)
11338 const TIDSortedElemSet& domain = theElems[idom];
11339 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11340 for (; elemItr != domain.end(); ++elemItr)
11342 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11343 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11346 // MESSAGE("aFace=" << aFace->GetID());
11347 bool isQuad = aFace->IsQuadratic();
11348 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11350 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11352 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11353 while (nodeIt->more())
11355 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11356 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11358 ln2.push_back(node);
11360 ln0.push_back(node);
11362 const SMDS_MeshNode* clone = 0;
11363 if (!clonedNodes.count(node))
11365 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11366 clonedNodes[node] = clone;
11369 clone = clonedNodes[node];
11372 ln3.push_back(clone);
11374 ln1.push_back(clone);
11376 const SMDS_MeshNode* inter = 0;
11377 if (isQuad && (!isMedium))
11379 if (!intermediateNodes.count(node))
11381 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11382 intermediateNodes[node] = inter;
11385 inter = intermediateNodes[node];
11386 ln4.push_back(inter);
11390 // --- extrude the face
11392 vector<const SMDS_MeshNode*> ln;
11393 SMDS_MeshVolume* vol = 0;
11394 vtkIdType aType = aFace->GetVtkType();
11398 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11399 // MESSAGE("vol prism " << vol->GetID());
11400 ln.push_back(ln1[0]);
11401 ln.push_back(ln1[1]);
11402 ln.push_back(ln1[2]);
11405 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11406 // MESSAGE("vol hexa " << vol->GetID());
11407 ln.push_back(ln1[0]);
11408 ln.push_back(ln1[1]);
11409 ln.push_back(ln1[2]);
11410 ln.push_back(ln1[3]);
11412 case VTK_QUADRATIC_TRIANGLE:
11413 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11414 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11415 // MESSAGE("vol quad prism " << vol->GetID());
11416 ln.push_back(ln1[0]);
11417 ln.push_back(ln1[1]);
11418 ln.push_back(ln1[2]);
11419 ln.push_back(ln3[0]);
11420 ln.push_back(ln3[1]);
11421 ln.push_back(ln3[2]);
11423 case VTK_QUADRATIC_QUAD:
11424 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11425 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11426 // ln4[0], ln4[1], ln4[2], ln4[3]);
11427 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11428 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11429 ln4[0], ln4[1], ln4[2], ln4[3]);
11430 // MESSAGE("vol quad hexa " << vol->GetID());
11431 ln.push_back(ln1[0]);
11432 ln.push_back(ln1[1]);
11433 ln.push_back(ln1[2]);
11434 ln.push_back(ln1[3]);
11435 ln.push_back(ln3[0]);
11436 ln.push_back(ln3[1]);
11437 ln.push_back(ln3[2]);
11438 ln.push_back(ln3[3]);
11448 stringstream grpname;
11452 string namegrp = grpname.str();
11453 if (!mapOfJunctionGroups.count(namegrp))
11454 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11455 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11457 sgrp->Add(vol->GetID());
11460 // --- modify the face
11462 aFace->ChangeNodes(&ln[0], ln.size());
11468 //================================================================================
11470 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11471 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11472 * \return TRUE if operation has been completed successfully, FALSE otherwise
11474 //================================================================================
11476 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11478 // iterates on volume elements and detect all free faces on them
11479 SMESHDS_Mesh* aMesh = GetMeshDS();
11482 //bool res = false;
11483 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11484 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11487 const SMDS_MeshVolume* volume = vIt->next();
11488 SMDS_VolumeTool vTool( volume );
11489 vTool.SetExternalNormal();
11490 const bool isPoly = volume->IsPoly();
11491 const bool isQuad = volume->IsQuadratic();
11492 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11494 if (!vTool.IsFreeFace(iface))
11497 vector<const SMDS_MeshNode *> nodes;
11498 int nbFaceNodes = vTool.NbFaceNodes(iface);
11499 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11501 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11502 nodes.push_back(faceNodes[inode]);
11504 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11505 nodes.push_back(faceNodes[inode]);
11507 // add new face based on volume nodes
11508 if (aMesh->FindFace( nodes ) ) {
11510 continue; // face already exsist
11512 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11516 return ( nbFree==(nbExisted+nbCreated) );
11521 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11523 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11525 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11528 //================================================================================
11530 * \brief Creates missing boundary elements
11531 * \param elements - elements whose boundary is to be checked
11532 * \param dimension - defines type of boundary elements to create
11533 * \param group - a group to store created boundary elements in
11534 * \param targetMesh - a mesh to store created boundary elements in
11535 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11536 * \param toCopyExistingBondary - if true, not only new but also pre-existing
11537 * boundary elements will be copied into the targetMesh
11538 * \param toAddExistingBondary - if true, not only new but also pre-existing
11539 * boundary elements will be added into the new group
11540 * \param aroundElements - if true, elements will be created on boundary of given
11541 * elements else, on boundary of the whole mesh. This
11542 * option works for 2D elements only.
11543 * \return nb of added boundary elements
11545 //================================================================================
11547 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11548 Bnd_Dimension dimension,
11549 SMESH_Group* group/*=0*/,
11550 SMESH_Mesh* targetMesh/*=0*/,
11551 bool toCopyElements/*=false*/,
11552 bool toCopyExistingBondary/*=false*/,
11553 bool toAddExistingBondary/*= false*/,
11554 bool aroundElements/*= false*/)
11556 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11557 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11558 // hope that all elements are of the same type, do not check them all
11559 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11560 throw SALOME_Exception(LOCALIZED("wrong element type"));
11562 if ( aroundElements && elemType == SMDSAbs_Volume )
11563 throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11566 toCopyElements = toCopyExistingBondary = false;
11568 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11569 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11570 int nbAddedBnd = 0;
11572 // editor adding present bnd elements and optionally holding elements to add to the group
11573 SMESH_MeshEditor* presentEditor;
11574 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11575 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11577 SMDS_VolumeTool vTool;
11578 TIDSortedElemSet avoidSet;
11579 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11582 typedef vector<const SMDS_MeshNode*> TConnectivity;
11584 SMDS_ElemIteratorPtr eIt;
11585 if (elements.empty())
11586 eIt = aMesh->elementsIterator(elemType);
11588 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11590 while (eIt->more())
11592 const SMDS_MeshElement* elem = eIt->next();
11593 const int iQuad = elem->IsQuadratic();
11595 // ------------------------------------------------------------------------------------
11596 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11597 // ------------------------------------------------------------------------------------
11598 vector<const SMDS_MeshElement*> presentBndElems;
11599 vector<TConnectivity> missingBndElems;
11600 TConnectivity nodes;
11601 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11603 vTool.SetExternalNormal();
11604 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11606 if (!vTool.IsFreeFace(iface))
11608 int nbFaceNodes = vTool.NbFaceNodes(iface);
11609 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11610 if ( missType == SMDSAbs_Edge ) // boundary edges
11612 nodes.resize( 2+iQuad );
11613 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11615 for ( int j = 0; j < nodes.size(); ++j )
11617 if ( const SMDS_MeshElement* edge =
11618 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11619 presentBndElems.push_back( edge );
11621 missingBndElems.push_back( nodes );
11624 else // boundary face
11627 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11628 nodes.push_back( nn[inode] );
11630 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11631 nodes.push_back( nn[inode] );
11633 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11634 presentBndElems.push_back( f );
11636 missingBndElems.push_back( nodes );
11640 else // elem is a face ------------------------------------------
11642 avoidSet.clear(), avoidSet.insert( elem );
11643 int nbNodes = elem->NbCornerNodes();
11644 nodes.resize( 2 /*+ iQuad*/);
11645 for ( int i = 0; i < nbNodes; i++ )
11647 nodes[0] = elem->GetNode(i);
11648 nodes[1] = elem->GetNode((i+1)%nbNodes);
11649 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11650 continue; // not free link
11653 //nodes[2] = elem->GetNode( i + nbNodes );
11654 if ( const SMDS_MeshElement* edge =
11655 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11656 presentBndElems.push_back( edge );
11658 missingBndElems.push_back( nodes );
11662 // ---------------------------------
11663 // 2. Add missing boundary elements
11664 // ---------------------------------
11665 if ( targetMesh != myMesh )
11666 // instead of making a map of nodes in this mesh and targetMesh,
11667 // we create nodes with same IDs. We can renumber them later, if needed
11668 for ( int i = 0; i < missingBndElems.size(); ++i )
11670 TConnectivity& srcNodes = missingBndElems[i];
11671 TConnectivity nodes( srcNodes.size() );
11672 for ( inode = 0; inode < nodes.size(); ++inode )
11673 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11674 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11676 /*noMedium=*/true))
11678 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11682 for ( int i = 0; i < missingBndElems.size(); ++i )
11684 TConnectivity& nodes = missingBndElems[i];
11685 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11687 /*noMedium=*/true))
11689 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11693 // ----------------------------------
11694 // 3. Copy present boundary elements
11695 // ----------------------------------
11696 if ( toCopyExistingBondary )
11697 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11699 const SMDS_MeshElement* e = presentBndElems[i];
11700 TConnectivity nodes( e->NbNodes() );
11701 for ( inode = 0; inode < nodes.size(); ++inode )
11702 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11703 presentEditor->AddElement(nodes, missType, e->IsPoly());
11705 else // store present elements to add them to a group
11706 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11708 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11711 } // loop on given elements
11713 // ---------------------------------------------
11714 // 4. Fill group with boundary elements
11715 // ---------------------------------------------
11718 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11719 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11720 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11722 tgtEditor.myLastCreatedElems.Clear();
11723 tgtEditor2.myLastCreatedElems.Clear();
11725 // -----------------------
11726 // 5. Copy given elements
11727 // -----------------------
11728 if ( toCopyElements && targetMesh != myMesh )
11730 if (elements.empty())
11731 eIt = aMesh->elementsIterator(elemType);
11733 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11734 while (eIt->more())
11736 const SMDS_MeshElement* elem = eIt->next();
11737 TConnectivity nodes( elem->NbNodes() );
11738 for ( inode = 0; inode < nodes.size(); ++inode )
11739 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11740 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11742 tgtEditor.myLastCreatedElems.Clear();