1 // Copyright (C) 2007-2011 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
100 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
103 using namespace SMESH::Controls;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
106 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
108 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
110 //=======================================================================
111 //function : SMESH_MeshEditor
113 //=======================================================================
115 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
116 :myMesh( theMesh ) // theMesh may be NULL
120 //=======================================================================
124 //=======================================================================
127 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
128 const SMDSAbs_ElementType type,
132 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
133 SMDS_MeshElement* e = 0;
134 int nbnode = node.size();
135 SMESHDS_Mesh* mesh = GetMeshDS();
140 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
141 else e = mesh->AddFace (node[0], node[1], node[2] );
143 else if (nbnode == 4) {
144 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
145 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
147 else if (nbnode == 6) {
148 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
149 node[4], node[5], ID);
150 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
153 else if (nbnode == 8) {
154 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
155 node[4], node[5], node[6], node[7], ID);
156 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
157 node[4], node[5], node[6], node[7] );
160 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
161 else e = mesh->AddPolygonalFace (node );
168 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
169 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
171 else if (nbnode == 5) {
172 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
174 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
177 else if (nbnode == 6) {
178 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
179 node[4], node[5], ID);
180 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
183 else if (nbnode == 8) {
184 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
185 node[4], node[5], node[6], node[7], ID);
186 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
187 node[4], node[5], node[6], node[7] );
189 else if (nbnode == 10) {
190 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
191 node[4], node[5], node[6], node[7],
192 node[8], node[9], ID);
193 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
194 node[4], node[5], node[6], node[7],
197 else if (nbnode == 13) {
198 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
199 node[4], node[5], node[6], node[7],
200 node[8], node[9], node[10],node[11],
202 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
203 node[4], node[5], node[6], node[7],
204 node[8], node[9], node[10],node[11],
207 else if (nbnode == 15) {
208 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
209 node[4], node[5], node[6], node[7],
210 node[8], node[9], node[10],node[11],
211 node[12],node[13],node[14],ID);
212 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
213 node[4], node[5], node[6], node[7],
214 node[8], node[9], node[10],node[11],
215 node[12],node[13],node[14] );
217 else if (nbnode == 20) {
218 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
219 node[4], node[5], node[6], node[7],
220 node[8], node[9], node[10],node[11],
221 node[12],node[13],node[14],node[15],
222 node[16],node[17],node[18],node[19],ID);
223 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
224 node[4], node[5], node[6], node[7],
225 node[8], node[9], node[10],node[11],
226 node[12],node[13],node[14],node[15],
227 node[16],node[17],node[18],node[19] );
234 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
235 else e = mesh->AddEdge (node[0], node[1] );
237 else if ( nbnode == 3 ) {
238 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
239 else e = mesh->AddEdge (node[0], node[1], node[2] );
243 case SMDSAbs_0DElement:
245 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
246 else e = mesh->Add0DElement (node[0] );
251 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
252 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
257 if ( e ) myLastCreatedElems.Append( e );
261 //=======================================================================
265 //=======================================================================
267 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
268 const SMDSAbs_ElementType type,
272 vector<const SMDS_MeshNode*> nodes;
273 nodes.reserve( nodeIDs.size() );
274 vector<int>::const_iterator id = nodeIDs.begin();
275 while ( id != nodeIDs.end() ) {
276 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
277 nodes.push_back( node );
281 return AddElement( nodes, type, isPoly, ID );
284 //=======================================================================
286 //purpose : Remove a node or an element.
287 // Modify a compute state of sub-meshes which become empty
288 //=======================================================================
290 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
293 myLastCreatedElems.Clear();
294 myLastCreatedNodes.Clear();
296 SMESHDS_Mesh* aMesh = GetMeshDS();
297 set< SMESH_subMesh *> smmap;
300 list<int>::const_iterator it = theIDs.begin();
301 for ( ; it != theIDs.end(); it++ ) {
302 const SMDS_MeshElement * elem;
304 elem = aMesh->FindNode( *it );
306 elem = aMesh->FindElement( *it );
310 // Notify VERTEX sub-meshes about modification
312 const SMDS_MeshNode* node = cast2Node( elem );
313 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
314 if ( int aShapeID = node->getshapeId() )
315 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
318 // Find sub-meshes to notify about modification
319 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
320 // while ( nodeIt->more() ) {
321 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
322 // const SMDS_PositionPtr& aPosition = node->GetPosition();
323 // if ( aPosition.get() ) {
324 // if ( int aShapeID = aPosition->GetShapeId() ) {
325 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
326 // smmap.insert( sm );
333 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
335 aMesh->RemoveElement( elem );
339 // Notify sub-meshes about modification
340 if ( !smmap.empty() ) {
341 set< SMESH_subMesh *>::iterator smIt;
342 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
343 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
346 // // Check if the whole mesh becomes empty
347 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
348 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
353 //=======================================================================
354 //function : FindShape
355 //purpose : Return an index of the shape theElem is on
356 // or zero if a shape not found
357 //=======================================================================
359 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
361 myLastCreatedElems.Clear();
362 myLastCreatedNodes.Clear();
364 SMESHDS_Mesh * aMesh = GetMeshDS();
365 if ( aMesh->ShapeToMesh().IsNull() )
368 int aShapeID = theElem->getshapeId();
372 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
373 if ( sm->Contains( theElem ))
376 if ( theElem->GetType() == SMDSAbs_Node ) {
377 MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
380 MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
383 TopoDS_Shape aShape; // the shape a node of theElem is on
384 if ( theElem->GetType() != SMDSAbs_Node )
386 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
387 while ( nodeIt->more() ) {
388 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
389 if ((aShapeID = node->getshapeId()) > 0) {
390 if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
391 if ( sm->Contains( theElem ))
393 if ( aShape.IsNull() )
394 aShape = aMesh->IndexToShape( aShapeID );
400 // None of nodes is on a proper shape,
401 // find the shape among ancestors of aShape on which a node is
402 if ( !aShape.IsNull() ) {
403 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
404 for ( ; ancIt.More(); ancIt.Next() ) {
405 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
406 if ( sm && sm->Contains( theElem ))
407 return aMesh->ShapeToIndex( ancIt.Value() );
412 const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
413 map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
414 for ( ; id_sm != id2sm.end(); ++id_sm )
415 if ( id_sm->second->Contains( theElem ))
419 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
423 //=======================================================================
424 //function : IsMedium
426 //=======================================================================
428 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
429 const SMDSAbs_ElementType typeToCheck)
431 bool isMedium = false;
432 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
433 while (it->more() && !isMedium ) {
434 const SMDS_MeshElement* elem = it->next();
435 isMedium = elem->IsMediumNode(node);
440 //=======================================================================
441 //function : ShiftNodesQuadTria
443 // Shift nodes in the array corresponded to quadratic triangle
444 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
445 //=======================================================================
446 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
448 const SMDS_MeshNode* nd1 = aNodes[0];
449 aNodes[0] = aNodes[1];
450 aNodes[1] = aNodes[2];
452 const SMDS_MeshNode* nd2 = aNodes[3];
453 aNodes[3] = aNodes[4];
454 aNodes[4] = aNodes[5];
458 //=======================================================================
459 //function : GetNodesFromTwoTria
461 // Shift nodes in the array corresponded to quadratic triangle
462 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
463 //=======================================================================
464 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
465 const SMDS_MeshElement * theTria2,
466 const SMDS_MeshNode* N1[],
467 const SMDS_MeshNode* N2[])
469 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
472 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
475 if(it->more()) return false;
476 it = theTria2->nodesIterator();
479 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
482 if(it->more()) return false;
484 int sames[3] = {-1,-1,-1};
496 if(nbsames!=2) return false;
498 ShiftNodesQuadTria(N1);
500 ShiftNodesQuadTria(N1);
503 i = sames[0] + sames[1] + sames[2];
505 ShiftNodesQuadTria(N2);
507 // now we receive following N1 and N2 (using numeration as above image)
508 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
509 // i.e. first nodes from both arrays determ new diagonal
513 //=======================================================================
514 //function : InverseDiag
515 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
516 // but having other common link.
517 // Return False if args are improper
518 //=======================================================================
520 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
521 const SMDS_MeshElement * theTria2 )
523 MESSAGE("InverseDiag");
524 myLastCreatedElems.Clear();
525 myLastCreatedNodes.Clear();
527 if (!theTria1 || !theTria2)
530 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
531 if (!F1) return false;
532 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
533 if (!F2) return false;
534 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
535 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
537 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
538 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
542 // put nodes in array and find out indices of the same ones
543 const SMDS_MeshNode* aNodes [6];
544 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
546 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
547 while ( it->more() ) {
548 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
550 if ( i > 2 ) // theTria2
551 // find same node of theTria1
552 for ( int j = 0; j < 3; j++ )
553 if ( aNodes[ i ] == aNodes[ j ]) {
562 return false; // theTria1 is not a triangle
563 it = theTria2->nodesIterator();
565 if ( i == 6 && it->more() )
566 return false; // theTria2 is not a triangle
569 // find indices of 1,2 and of A,B in theTria1
570 int iA = 0, iB = 0, i1 = 0, i2 = 0;
571 for ( i = 0; i < 6; i++ ) {
572 if ( sameInd [ i ] == 0 ) {
581 // nodes 1 and 2 should not be the same
582 if ( aNodes[ i1 ] == aNodes[ i2 ] )
586 aNodes[ iA ] = aNodes[ i2 ];
588 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
590 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
591 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
595 } // end if(F1 && F2)
597 // check case of quadratic faces
598 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
600 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
604 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
605 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
613 const SMDS_MeshNode* N1 [6];
614 const SMDS_MeshNode* N2 [6];
615 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
617 // now we receive following N1 and N2 (using numeration as above image)
618 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
619 // i.e. first nodes from both arrays determ new diagonal
621 const SMDS_MeshNode* N1new [6];
622 const SMDS_MeshNode* N2new [6];
635 // replaces nodes in faces
636 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
637 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
642 //=======================================================================
643 //function : findTriangles
644 //purpose : find triangles sharing theNode1-theNode2 link
645 //=======================================================================
647 static bool findTriangles(const SMDS_MeshNode * theNode1,
648 const SMDS_MeshNode * theNode2,
649 const SMDS_MeshElement*& theTria1,
650 const SMDS_MeshElement*& theTria2)
652 if ( !theNode1 || !theNode2 ) return false;
654 theTria1 = theTria2 = 0;
656 set< const SMDS_MeshElement* > emap;
657 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
659 const SMDS_MeshElement* elem = it->next();
660 if ( elem->NbNodes() == 3 )
663 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
665 const SMDS_MeshElement* elem = it->next();
666 if ( emap.find( elem ) != emap.end() ) {
668 // theTria1 must be element with minimum ID
669 if( theTria1->GetID() < elem->GetID() ) {
683 return ( theTria1 && theTria2 );
686 //=======================================================================
687 //function : InverseDiag
688 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
689 // with ones built on the same 4 nodes but having other common link.
690 // Return false if proper faces not found
691 //=======================================================================
693 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
694 const SMDS_MeshNode * theNode2)
696 myLastCreatedElems.Clear();
697 myLastCreatedNodes.Clear();
699 MESSAGE( "::InverseDiag()" );
701 const SMDS_MeshElement *tr1, *tr2;
702 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
705 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
706 if (!F1) return false;
707 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
708 if (!F2) return false;
709 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
710 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
712 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
713 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
717 // put nodes in array
718 // and find indices of 1,2 and of A in tr1 and of B in tr2
719 int i, iA1 = 0, i1 = 0;
720 const SMDS_MeshNode* aNodes1 [3];
721 SMDS_ElemIteratorPtr it;
722 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
723 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
724 if ( aNodes1[ i ] == theNode1 )
725 iA1 = i; // node A in tr1
726 else if ( aNodes1[ i ] != theNode2 )
730 const SMDS_MeshNode* aNodes2 [3];
731 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
732 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
733 if ( aNodes2[ i ] == theNode2 )
734 iB2 = i; // node B in tr2
735 else if ( aNodes2[ i ] != theNode1 )
739 // nodes 1 and 2 should not be the same
740 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
744 aNodes1[ iA1 ] = aNodes2[ i2 ];
746 aNodes2[ iB2 ] = aNodes1[ i1 ];
748 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
749 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
754 // check case of quadratic faces
755 return InverseDiag(tr1,tr2);
758 //=======================================================================
759 //function : getQuadrangleNodes
760 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
761 // fusion of triangles tr1 and tr2 having shared link on
762 // theNode1 and theNode2
763 //=======================================================================
765 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
766 const SMDS_MeshNode * theNode1,
767 const SMDS_MeshNode * theNode2,
768 const SMDS_MeshElement * tr1,
769 const SMDS_MeshElement * tr2 )
771 if( tr1->NbNodes() != tr2->NbNodes() )
773 // find the 4-th node to insert into tr1
774 const SMDS_MeshNode* n4 = 0;
775 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
777 while ( !n4 && i<3 ) {
778 const SMDS_MeshNode * n = cast2Node( it->next() );
780 bool isDiag = ( n == theNode1 || n == theNode2 );
784 // Make an array of nodes to be in a quadrangle
785 int iNode = 0, iFirstDiag = -1;
786 it = tr1->nodesIterator();
789 const SMDS_MeshNode * n = cast2Node( it->next() );
791 bool isDiag = ( n == theNode1 || n == theNode2 );
793 if ( iFirstDiag < 0 )
795 else if ( iNode - iFirstDiag == 1 )
796 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
798 else if ( n == n4 ) {
799 return false; // tr1 and tr2 should not have all the same nodes
801 theQuadNodes[ iNode++ ] = n;
803 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
804 theQuadNodes[ iNode ] = n4;
809 //=======================================================================
810 //function : DeleteDiag
811 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
812 // with a quadrangle built on the same 4 nodes.
813 // Return false if proper faces not found
814 //=======================================================================
816 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
817 const SMDS_MeshNode * theNode2)
819 myLastCreatedElems.Clear();
820 myLastCreatedNodes.Clear();
822 MESSAGE( "::DeleteDiag()" );
824 const SMDS_MeshElement *tr1, *tr2;
825 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
828 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
829 if (!F1) return false;
830 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
831 if (!F2) return false;
832 SMESHDS_Mesh * aMesh = GetMeshDS();
834 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
835 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
837 const SMDS_MeshNode* aNodes [ 4 ];
838 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
841 const SMDS_MeshElement* newElem = 0;
842 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
843 myLastCreatedElems.Append(newElem);
844 AddToSameGroups( newElem, tr1, aMesh );
845 int aShapeId = tr1->getshapeId();
848 aMesh->SetMeshElementOnShape( newElem, aShapeId );
850 aMesh->RemoveElement( tr1 );
851 aMesh->RemoveElement( tr2 );
856 // check case of quadratic faces
857 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
859 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
863 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
864 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
872 const SMDS_MeshNode* N1 [6];
873 const SMDS_MeshNode* N2 [6];
874 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
876 // now we receive following N1 and N2 (using numeration as above image)
877 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
878 // i.e. first nodes from both arrays determ new diagonal
880 const SMDS_MeshNode* aNodes[8];
890 const SMDS_MeshElement* newElem = 0;
891 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
892 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
893 myLastCreatedElems.Append(newElem);
894 AddToSameGroups( newElem, tr1, aMesh );
895 int aShapeId = tr1->getshapeId();
898 aMesh->SetMeshElementOnShape( newElem, aShapeId );
900 aMesh->RemoveElement( tr1 );
901 aMesh->RemoveElement( tr2 );
903 // remove middle node (9)
904 GetMeshDS()->RemoveNode( N1[4] );
909 //=======================================================================
910 //function : Reorient
911 //purpose : Reverse theElement orientation
912 //=======================================================================
914 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
917 myLastCreatedElems.Clear();
918 myLastCreatedNodes.Clear();
922 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
923 if ( !it || !it->more() )
926 switch ( theElem->GetType() ) {
930 if(!theElem->IsQuadratic()) {
931 int i = theElem->NbNodes();
932 vector<const SMDS_MeshNode*> aNodes( i );
934 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
935 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
938 // quadratic elements
939 if(theElem->GetType()==SMDSAbs_Edge) {
940 vector<const SMDS_MeshNode*> aNodes(3);
941 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
942 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
943 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
944 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
947 int nbn = theElem->NbNodes();
948 vector<const SMDS_MeshNode*> aNodes(nbn);
949 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
951 for(; i<nbn/2; i++) {
952 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
954 for(i=0; i<nbn/2; i++) {
955 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
957 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
961 case SMDSAbs_Volume: {
962 if (theElem->IsPoly()) {
963 // TODO reorient vtk polyhedron
964 MESSAGE("reorient vtk polyhedron ?");
965 const SMDS_VtkVolume* aPolyedre =
966 dynamic_cast<const SMDS_VtkVolume*>( theElem );
968 MESSAGE("Warning: bad volumic element");
972 int nbFaces = aPolyedre->NbFaces();
973 vector<const SMDS_MeshNode *> poly_nodes;
974 vector<int> quantities (nbFaces);
976 // reverse each face of the polyedre
977 for (int iface = 1; iface <= nbFaces; iface++) {
978 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
979 quantities[iface - 1] = nbFaceNodes;
981 for (inode = nbFaceNodes; inode >= 1; inode--) {
982 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
983 poly_nodes.push_back(curNode);
987 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
991 SMDS_VolumeTool vTool;
992 if ( !vTool.Set( theElem ))
995 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
996 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
1005 //=======================================================================
1006 //function : getBadRate
1008 //=======================================================================
1010 static double getBadRate (const SMDS_MeshElement* theElem,
1011 SMESH::Controls::NumericalFunctorPtr& theCrit)
1013 SMESH::Controls::TSequenceOfXYZ P;
1014 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1016 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1017 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1020 //=======================================================================
1021 //function : QuadToTri
1022 //purpose : Cut quadrangles into triangles.
1023 // theCrit is used to select a diagonal to cut
1024 //=======================================================================
1026 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1027 SMESH::Controls::NumericalFunctorPtr theCrit)
1029 myLastCreatedElems.Clear();
1030 myLastCreatedNodes.Clear();
1032 MESSAGE( "::QuadToTri()" );
1034 if ( !theCrit.get() )
1037 SMESHDS_Mesh * aMesh = GetMeshDS();
1039 Handle(Geom_Surface) surface;
1040 SMESH_MesherHelper helper( *GetMesh() );
1042 TIDSortedElemSet::iterator itElem;
1043 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1044 const SMDS_MeshElement* elem = *itElem;
1045 if ( !elem || elem->GetType() != SMDSAbs_Face )
1047 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1050 // retrieve element nodes
1051 const SMDS_MeshNode* aNodes [8];
1052 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1054 while ( itN->more() )
1055 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1057 // compare two sets of possible triangles
1058 double aBadRate1, aBadRate2; // to what extent a set is bad
1059 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1060 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1061 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1063 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1064 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1065 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1067 int aShapeId = FindShape( elem );
1068 const SMDS_MeshElement* newElem1 = 0;
1069 const SMDS_MeshElement* newElem2 = 0;
1071 if( !elem->IsQuadratic() ) {
1073 // split liner quadrangle
1074 if ( aBadRate1 <= aBadRate2 ) {
1075 // tr1 + tr2 is better
1076 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1077 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1080 // tr3 + tr4 is better
1081 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1082 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1087 // split quadratic quadrangle
1089 // get surface elem is on
1090 if ( aShapeId != helper.GetSubShapeID() ) {
1094 shape = aMesh->IndexToShape( aShapeId );
1095 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1096 TopoDS_Face face = TopoDS::Face( shape );
1097 surface = BRep_Tool::Surface( face );
1098 if ( !surface.IsNull() )
1099 helper.SetSubShape( shape );
1103 const SMDS_MeshNode* aNodes [8];
1104 const SMDS_MeshNode* inFaceNode = 0;
1105 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1107 while ( itN->more() ) {
1108 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1109 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1110 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1112 inFaceNode = aNodes[ i-1 ];
1115 // find middle point for (0,1,2,3)
1116 // and create a node in this point;
1118 if ( surface.IsNull() ) {
1120 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1124 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1127 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1129 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1131 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1132 myLastCreatedNodes.Append(newN);
1134 // create a new element
1135 if ( aBadRate1 <= aBadRate2 ) {
1136 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1137 aNodes[6], aNodes[7], newN );
1138 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1139 newN, aNodes[4], aNodes[5] );
1142 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1143 aNodes[7], aNodes[4], newN );
1144 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1145 newN, aNodes[5], aNodes[6] );
1149 // care of a new element
1151 myLastCreatedElems.Append(newElem1);
1152 myLastCreatedElems.Append(newElem2);
1153 AddToSameGroups( newElem1, elem, aMesh );
1154 AddToSameGroups( newElem2, elem, aMesh );
1156 // put a new triangle on the same shape
1159 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1160 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1162 aMesh->RemoveElement( elem );
1167 //=======================================================================
1168 //function : BestSplit
1169 //purpose : Find better diagonal for cutting.
1170 //=======================================================================
1172 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1173 SMESH::Controls::NumericalFunctorPtr theCrit)
1175 myLastCreatedElems.Clear();
1176 myLastCreatedNodes.Clear();
1181 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1184 if( theQuad->NbNodes()==4 ||
1185 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1187 // retrieve element nodes
1188 const SMDS_MeshNode* aNodes [4];
1189 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1191 //while (itN->more())
1193 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1195 // compare two sets of possible triangles
1196 double aBadRate1, aBadRate2; // to what extent a set is bad
1197 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1198 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1199 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1201 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1202 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1203 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1205 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1206 return 1; // diagonal 1-3
1208 return 2; // diagonal 2-4
1215 // Methods of splitting volumes into tetra
1217 const int theHexTo5_1[5*4+1] =
1219 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1221 const int theHexTo5_2[5*4+1] =
1223 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1225 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1227 const int theHexTo6_1[6*4+1] =
1229 1, 5, 6, 0, 0, 1, 2, 6, 0, 4, 5, 6, 0, 4, 6, 7, 0, 2, 3, 6, 0, 3, 7, 6, -1
1231 const int theHexTo6_2[6*4+1] =
1233 2, 6, 7, 1, 1, 2, 3, 7, 1, 5, 6, 7, 1, 5, 7, 4, 1, 3, 0, 7, 1, 0, 4, 7, -1
1235 const int theHexTo6_3[6*4+1] =
1237 3, 7, 4, 2, 2, 3, 0, 4, 2, 6, 7, 4, 2, 6, 4, 5, 2, 0, 1, 4, 2, 1, 5, 4, -1
1239 const int theHexTo6_4[6*4+1] =
1241 0, 4, 5, 3, 3, 0, 1, 5, 3, 7, 4, 5, 3, 7, 5, 6, 3, 1, 2, 5, 3, 2, 6, 5, -1
1243 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1245 const int thePyraTo2_1[2*4+1] =
1247 0, 1, 2, 4, 0, 2, 3, 4, -1
1249 const int thePyraTo2_2[2*4+1] =
1251 1, 2, 3, 4, 1, 3, 0, 4, -1
1253 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1255 const int thePentaTo3_1[3*4+1] =
1257 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1259 const int thePentaTo3_2[3*4+1] =
1261 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1263 const int thePentaTo3_3[3*4+1] =
1265 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1267 const int thePentaTo3_4[3*4+1] =
1269 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1271 const int thePentaTo3_5[3*4+1] =
1273 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1275 const int thePentaTo3_6[3*4+1] =
1277 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1279 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1280 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1282 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1285 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1286 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1287 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1292 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1293 bool _baryNode; //!< additional node is to be created at cell barycenter
1294 bool _ownConn; //!< to delete _connectivity in destructor
1295 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1297 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1298 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1299 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1300 bool hasFacet( const TTriangleFacet& facet ) const
1302 const int* tetConn = _connectivity;
1303 for ( ; tetConn[0] >= 0; tetConn += 4 )
1304 if (( facet.contains( tetConn[0] ) +
1305 facet.contains( tetConn[1] ) +
1306 facet.contains( tetConn[2] ) +
1307 facet.contains( tetConn[3] )) == 3 )
1313 //=======================================================================
1315 * \brief return TSplitMethod for the given element
1317 //=======================================================================
1319 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1321 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1323 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1324 // an edge and a face barycenter; tertaherdons are based on triangles and
1325 // a volume barycenter
1326 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1328 // Find out how adjacent volumes are split
1330 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1331 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1332 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1334 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1335 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1336 if ( nbNodes < 4 ) continue;
1338 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1339 const int* nInd = vol.GetFaceNodesIndices( iF );
1342 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1343 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1344 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1345 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1349 int iCom = 0; // common node of triangle faces to split into
1350 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1352 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1353 nInd[ iQ * ( (iCom+1)%nbNodes )],
1354 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1355 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1356 nInd[ iQ * ( (iCom+2)%nbNodes )],
1357 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1358 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1360 triaSplits.push_back( t012 );
1361 triaSplits.push_back( t023 );
1366 if ( !triaSplits.empty() )
1367 hasAdjacentSplits = true;
1370 // Among variants of split method select one compliant with adjacent volumes
1372 TSplitMethod method;
1373 if ( !vol.Element()->IsPoly() && !is24TetMode )
1375 int nbVariants = 2, nbTet = 0;
1376 const int** connVariants = 0;
1377 switch ( vol.Element()->GetEntityType() )
1379 case SMDSEntity_Hexa:
1380 case SMDSEntity_Quad_Hexa:
1381 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1382 connVariants = theHexTo5, nbTet = 5;
1384 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1386 case SMDSEntity_Pyramid:
1387 case SMDSEntity_Quad_Pyramid:
1388 connVariants = thePyraTo2; nbTet = 2;
1390 case SMDSEntity_Penta:
1391 case SMDSEntity_Quad_Penta:
1392 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1397 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1399 // check method compliancy with adjacent tetras,
1400 // all found splits must be among facets of tetras described by this method
1401 method = TSplitMethod( nbTet, connVariants[variant] );
1402 if ( hasAdjacentSplits && method._nbTetra > 0 )
1404 bool facetCreated = true;
1405 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1407 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1408 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1409 facetCreated = method.hasFacet( *facet );
1411 if ( !facetCreated )
1412 method = TSplitMethod(0); // incompatible method
1416 if ( method._nbTetra < 1 )
1418 // No standard method is applicable, use a generic solution:
1419 // each facet of a volume is split into triangles and
1420 // each of triangles and a volume barycenter form a tetrahedron.
1422 int* connectivity = new int[ maxTetConnSize + 1 ];
1423 method._connectivity = connectivity;
1424 method._ownConn = true;
1425 method._baryNode = true;
1428 int baryCenInd = vol.NbNodes();
1429 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1431 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1432 const int* nInd = vol.GetFaceNodesIndices( iF );
1433 // find common node of triangle facets of tetra to create
1434 int iCommon = 0; // index in linear numeration
1435 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1436 if ( !triaSplits.empty() )
1439 const TTriangleFacet* facet = &triaSplits.front();
1440 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1441 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1442 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1445 else if ( nbNodes > 3 && !is24TetMode )
1447 // find the best method of splitting into triangles by aspect ratio
1448 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1449 map< double, int > badness2iCommon;
1450 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1451 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1452 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1453 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1455 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1456 nodes[ iQ*((iLast-1)%nbNodes)],
1457 nodes[ iQ*((iLast )%nbNodes)]);
1458 double badness = getBadRate( &tria, aspectRatio );
1459 badness2iCommon.insert( make_pair( badness, iCommon ));
1461 // use iCommon with lowest badness
1462 iCommon = badness2iCommon.begin()->second;
1464 if ( iCommon >= nbNodes )
1465 iCommon = 0; // something wrong
1467 // fill connectivity of tetrahedra based on a current face
1468 int nbTet = nbNodes - 2;
1469 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1471 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1472 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1474 for ( int i = 0; i < nbTet; ++i )
1476 int i1 = i, i2 = (i+1) % nbNodes;
1477 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1478 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1479 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1480 connectivity[ connSize++ ] = faceBaryCenInd;
1481 connectivity[ connSize++ ] = baryCenInd;
1486 for ( int i = 0; i < nbTet; ++i )
1488 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1489 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1490 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1491 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1492 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1493 connectivity[ connSize++ ] = baryCenInd;
1496 method._nbTetra += nbTet;
1498 connectivity[ connSize++ ] = -1;
1502 //================================================================================
1504 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1506 //================================================================================
1508 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1510 // find the tetrahedron including the three nodes of facet
1511 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1512 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1513 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1514 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1515 while ( volIt1->more() )
1517 const SMDS_MeshElement* v = volIt1->next();
1518 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1520 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1521 while ( volIt2->more() )
1522 if ( v != volIt2->next() )
1524 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1525 while ( volIt3->more() )
1526 if ( v == volIt3->next() )
1532 //=======================================================================
1534 * \brief A key of a face of volume
1536 //=======================================================================
1538 struct TVolumeFaceKey: pair< int, pair< int, int> >
1540 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1542 TIDSortedNodeSet sortedNodes;
1543 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1544 int nbNodes = vol.NbFaceNodes( iF );
1545 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1546 for ( int i = 0; i < nbNodes; i += iQ )
1547 sortedNodes.insert( fNodes[i] );
1548 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1549 first = (*(n++))->GetID();
1550 second.first = (*(n++))->GetID();
1551 second.second = (*(n++))->GetID();
1556 //=======================================================================
1557 //function : SplitVolumesIntoTetra
1558 //purpose : Split volumic elements into tetrahedra.
1559 //=======================================================================
1561 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1562 const int theMethodFlags)
1564 // std-like iterator on coordinates of nodes of mesh element
1565 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1566 NXyzIterator xyzEnd;
1568 SMDS_VolumeTool volTool;
1569 SMESH_MesherHelper helper( *GetMesh());
1571 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1572 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1574 SMESH_SequenceOfElemPtr newNodes, newElems;
1576 // map face of volume to it's baricenrtic node
1577 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1580 TIDSortedElemSet::const_iterator elem = theElems.begin();
1581 for ( ; elem != theElems.end(); ++elem )
1583 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1584 if ( geomType <= SMDSEntity_Quad_Tetra )
1585 continue; // tetra or face or ...
1587 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1589 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1590 if ( splitMethod._nbTetra < 1 ) continue;
1592 // find submesh to add new tetras to
1593 if ( !subMesh || !subMesh->Contains( *elem ))
1595 int shapeID = FindShape( *elem );
1596 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1597 subMesh = GetMeshDS()->MeshElements( shapeID );
1600 if ( (*elem)->IsQuadratic() )
1603 // add quadratic links to the helper
1604 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1606 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1607 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1608 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1610 helper.SetIsQuadratic( true );
1615 helper.SetIsQuadratic( false );
1617 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1618 if ( splitMethod._baryNode )
1620 // make a node at barycenter
1621 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1622 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1623 nodes.push_back( gcNode );
1624 newNodes.Append( gcNode );
1626 if ( !splitMethod._faceBaryNode.empty() )
1628 // make or find baricentric nodes of faces
1629 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1630 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1632 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1633 volFace2BaryNode.insert
1634 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1637 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1638 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1640 nodes.push_back( iF_n->second = f_n->second );
1645 helper.SetElementsOnShape( true );
1646 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1647 const int* tetConn = splitMethod._connectivity;
1648 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1649 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1650 nodes[ tetConn[1] ],
1651 nodes[ tetConn[2] ],
1652 nodes[ tetConn[3] ]));
1654 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1656 // Split faces on sides of the split volume
1658 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1659 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1661 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1662 if ( nbNodes < 4 ) continue;
1664 // find an existing face
1665 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1666 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1667 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1670 helper.SetElementsOnShape( false );
1671 vector< const SMDS_MeshElement* > triangles;
1673 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1674 if ( iF_n != splitMethod._faceBaryNode.end() )
1676 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1678 const SMDS_MeshNode* n1 = fNodes[iN];
1679 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1680 const SMDS_MeshNode *n3 = iF_n->second;
1681 if ( !volTool.IsFaceExternal( iF ))
1683 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1688 // among possible triangles create ones discribed by split method
1689 const int* nInd = volTool.GetFaceNodesIndices( iF );
1690 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1691 int iCom = 0; // common node of triangle faces to split into
1692 list< TTriangleFacet > facets;
1693 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1695 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1696 nInd[ iQ * ( (iCom+1)%nbNodes )],
1697 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1698 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1699 nInd[ iQ * ( (iCom+2)%nbNodes )],
1700 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1701 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1703 facets.push_back( t012 );
1704 facets.push_back( t023 );
1705 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1706 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1707 nInd[ iQ * ((iLast-1)%nbNodes )],
1708 nInd[ iQ * ((iLast )%nbNodes )]));
1712 list< TTriangleFacet >::iterator facet = facets.begin();
1713 for ( ; facet != facets.end(); ++facet )
1715 if ( !volTool.IsFaceExternal( iF ))
1716 swap( facet->_n2, facet->_n3 );
1717 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1718 volNodes[ facet->_n2 ],
1719 volNodes[ facet->_n3 ]));
1722 // find submesh to add new triangles in
1723 if ( !fSubMesh || !fSubMesh->Contains( face ))
1725 int shapeID = FindShape( face );
1726 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1728 for ( int i = 0; i < triangles.size(); ++i )
1730 if ( !triangles[i] ) continue;
1732 fSubMesh->AddElement( triangles[i]);
1733 newElems.Append( triangles[i] );
1735 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1736 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1739 } // loop on volume faces to split them into triangles
1741 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1743 } // loop on volumes to split
1745 myLastCreatedNodes = newNodes;
1746 myLastCreatedElems = newElems;
1749 //=======================================================================
1750 //function : AddToSameGroups
1751 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1752 //=======================================================================
1754 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1755 const SMDS_MeshElement* elemInGroups,
1756 SMESHDS_Mesh * aMesh)
1758 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1759 if (!groups.empty()) {
1760 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1761 for ( ; grIt != groups.end(); grIt++ ) {
1762 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1763 if ( group && group->Contains( elemInGroups ))
1764 group->SMDSGroup().Add( elemToAdd );
1770 //=======================================================================
1771 //function : RemoveElemFromGroups
1772 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1773 //=======================================================================
1774 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1775 SMESHDS_Mesh * aMesh)
1777 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1778 if (!groups.empty())
1780 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1781 for (; GrIt != groups.end(); GrIt++)
1783 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1784 if (!grp || grp->IsEmpty()) continue;
1785 grp->SMDSGroup().Remove(removeelem);
1790 //================================================================================
1792 * \brief Replace elemToRm by elemToAdd in the all groups
1794 //================================================================================
1796 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1797 const SMDS_MeshElement* elemToAdd,
1798 SMESHDS_Mesh * aMesh)
1800 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1801 if (!groups.empty()) {
1802 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1803 for ( ; grIt != groups.end(); grIt++ ) {
1804 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1805 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1806 group->SMDSGroup().Add( elemToAdd );
1811 //================================================================================
1813 * \brief Replace elemToRm by elemToAdd in the all groups
1815 //================================================================================
1817 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1818 const vector<const SMDS_MeshElement*>& elemToAdd,
1819 SMESHDS_Mesh * aMesh)
1821 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1822 if (!groups.empty())
1824 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1825 for ( ; grIt != groups.end(); grIt++ ) {
1826 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1827 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1828 for ( int i = 0; i < elemToAdd.size(); ++i )
1829 group->SMDSGroup().Add( elemToAdd[ i ] );
1834 //=======================================================================
1835 //function : QuadToTri
1836 //purpose : Cut quadrangles into triangles.
1837 // theCrit is used to select a diagonal to cut
1838 //=======================================================================
1840 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1841 const bool the13Diag)
1843 myLastCreatedElems.Clear();
1844 myLastCreatedNodes.Clear();
1846 MESSAGE( "::QuadToTri()" );
1848 SMESHDS_Mesh * aMesh = GetMeshDS();
1850 Handle(Geom_Surface) surface;
1851 SMESH_MesherHelper helper( *GetMesh() );
1853 TIDSortedElemSet::iterator itElem;
1854 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1855 const SMDS_MeshElement* elem = *itElem;
1856 if ( !elem || elem->GetType() != SMDSAbs_Face )
1858 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1859 if(!isquad) continue;
1861 if(elem->NbNodes()==4) {
1862 // retrieve element nodes
1863 const SMDS_MeshNode* aNodes [4];
1864 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1866 while ( itN->more() )
1867 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1869 int aShapeId = FindShape( elem );
1870 const SMDS_MeshElement* newElem1 = 0;
1871 const SMDS_MeshElement* newElem2 = 0;
1873 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1874 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1877 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1878 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1880 myLastCreatedElems.Append(newElem1);
1881 myLastCreatedElems.Append(newElem2);
1882 // put a new triangle on the same shape and add to the same groups
1885 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1886 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1888 AddToSameGroups( newElem1, elem, aMesh );
1889 AddToSameGroups( newElem2, elem, aMesh );
1890 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1891 aMesh->RemoveElement( elem );
1894 // Quadratic quadrangle
1896 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1898 // get surface elem is on
1899 int aShapeId = FindShape( elem );
1900 if ( aShapeId != helper.GetSubShapeID() ) {
1904 shape = aMesh->IndexToShape( aShapeId );
1905 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1906 TopoDS_Face face = TopoDS::Face( shape );
1907 surface = BRep_Tool::Surface( face );
1908 if ( !surface.IsNull() )
1909 helper.SetSubShape( shape );
1913 const SMDS_MeshNode* aNodes [8];
1914 const SMDS_MeshNode* inFaceNode = 0;
1915 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1917 while ( itN->more() ) {
1918 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1919 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1920 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1922 inFaceNode = aNodes[ i-1 ];
1926 // find middle point for (0,1,2,3)
1927 // and create a node in this point;
1929 if ( surface.IsNull() ) {
1931 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1935 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1938 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1940 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1942 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1943 myLastCreatedNodes.Append(newN);
1945 // create a new element
1946 const SMDS_MeshElement* newElem1 = 0;
1947 const SMDS_MeshElement* newElem2 = 0;
1949 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1950 aNodes[6], aNodes[7], newN );
1951 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1952 newN, aNodes[4], aNodes[5] );
1955 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1956 aNodes[7], aNodes[4], newN );
1957 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1958 newN, aNodes[5], aNodes[6] );
1960 myLastCreatedElems.Append(newElem1);
1961 myLastCreatedElems.Append(newElem2);
1962 // put a new triangle on the same shape and add to the same groups
1965 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1966 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1968 AddToSameGroups( newElem1, elem, aMesh );
1969 AddToSameGroups( newElem2, elem, aMesh );
1970 aMesh->RemoveElement( elem );
1977 //=======================================================================
1978 //function : getAngle
1980 //=======================================================================
1982 double getAngle(const SMDS_MeshElement * tr1,
1983 const SMDS_MeshElement * tr2,
1984 const SMDS_MeshNode * n1,
1985 const SMDS_MeshNode * n2)
1987 double angle = 2*PI; // bad angle
1990 SMESH::Controls::TSequenceOfXYZ P1, P2;
1991 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
1992 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
1995 if(!tr1->IsQuadratic())
1996 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
1998 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
1999 if ( N1.SquareMagnitude() <= gp::Resolution() )
2001 if(!tr2->IsQuadratic())
2002 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2004 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2005 if ( N2.SquareMagnitude() <= gp::Resolution() )
2008 // find the first diagonal node n1 in the triangles:
2009 // take in account a diagonal link orientation
2010 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2011 for ( int t = 0; t < 2; t++ ) {
2012 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2013 int i = 0, iDiag = -1;
2014 while ( it->more()) {
2015 const SMDS_MeshElement *n = it->next();
2016 if ( n == n1 || n == n2 ) {
2020 if ( i - iDiag == 1 )
2021 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2030 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2033 angle = N1.Angle( N2 );
2038 // =================================================
2039 // class generating a unique ID for a pair of nodes
2040 // and able to return nodes by that ID
2041 // =================================================
2045 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2046 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2049 long GetLinkID (const SMDS_MeshNode * n1,
2050 const SMDS_MeshNode * n2) const
2052 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2055 bool GetNodes (const long theLinkID,
2056 const SMDS_MeshNode* & theNode1,
2057 const SMDS_MeshNode* & theNode2) const
2059 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2060 if ( !theNode1 ) return false;
2061 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2062 if ( !theNode2 ) return false;
2068 const SMESHDS_Mesh* myMesh;
2073 //=======================================================================
2074 //function : TriToQuad
2075 //purpose : Fuse neighbour triangles into quadrangles.
2076 // theCrit is used to select a neighbour to fuse with.
2077 // theMaxAngle is a max angle between element normals at which
2078 // fusion is still performed.
2079 //=======================================================================
2081 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2082 SMESH::Controls::NumericalFunctorPtr theCrit,
2083 const double theMaxAngle)
2085 myLastCreatedElems.Clear();
2086 myLastCreatedNodes.Clear();
2088 MESSAGE( "::TriToQuad()" );
2090 if ( !theCrit.get() )
2093 SMESHDS_Mesh * aMesh = GetMeshDS();
2095 // Prepare data for algo: build
2096 // 1. map of elements with their linkIDs
2097 // 2. map of linkIDs with their elements
2099 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2100 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2101 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2102 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2104 TIDSortedElemSet::iterator itElem;
2105 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2106 const SMDS_MeshElement* elem = *itElem;
2107 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2108 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2109 if(!IsTria) continue;
2111 // retrieve element nodes
2112 const SMDS_MeshNode* aNodes [4];
2113 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2116 aNodes[ i++ ] = cast2Node( itN->next() );
2117 aNodes[ 3 ] = aNodes[ 0 ];
2120 for ( i = 0; i < 3; i++ ) {
2121 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2122 // check if elements sharing a link can be fused
2123 itLE = mapLi_listEl.find( link );
2124 if ( itLE != mapLi_listEl.end() ) {
2125 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2127 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2128 //if ( FindShape( elem ) != FindShape( elem2 ))
2129 // continue; // do not fuse triangles laying on different shapes
2130 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2131 continue; // avoid making badly shaped quads
2132 (*itLE).second.push_back( elem );
2135 mapLi_listEl[ link ].push_back( elem );
2137 mapEl_setLi [ elem ].insert( link );
2140 // Clean the maps from the links shared by a sole element, ie
2141 // links to which only one element is bound in mapLi_listEl
2143 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2144 int nbElems = (*itLE).second.size();
2145 if ( nbElems < 2 ) {
2146 const SMDS_MeshElement* elem = (*itLE).second.front();
2147 SMESH_TLink link = (*itLE).first;
2148 mapEl_setLi[ elem ].erase( link );
2149 if ( mapEl_setLi[ elem ].empty() )
2150 mapEl_setLi.erase( elem );
2154 // Algo: fuse triangles into quadrangles
2156 while ( ! mapEl_setLi.empty() ) {
2157 // Look for the start element:
2158 // the element having the least nb of shared links
2159 const SMDS_MeshElement* startElem = 0;
2161 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2162 int nbLinks = (*itEL).second.size();
2163 if ( nbLinks < minNbLinks ) {
2164 startElem = (*itEL).first;
2165 minNbLinks = nbLinks;
2166 if ( minNbLinks == 1 )
2171 // search elements to fuse starting from startElem or links of elements
2172 // fused earlyer - startLinks
2173 list< SMESH_TLink > startLinks;
2174 while ( startElem || !startLinks.empty() ) {
2175 while ( !startElem && !startLinks.empty() ) {
2176 // Get an element to start, by a link
2177 SMESH_TLink linkId = startLinks.front();
2178 startLinks.pop_front();
2179 itLE = mapLi_listEl.find( linkId );
2180 if ( itLE != mapLi_listEl.end() ) {
2181 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2182 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2183 for ( ; itE != listElem.end() ; itE++ )
2184 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2186 mapLi_listEl.erase( itLE );
2191 // Get candidates to be fused
2192 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2193 const SMESH_TLink *link12, *link13;
2195 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2196 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2197 ASSERT( !setLi.empty() );
2198 set< SMESH_TLink >::iterator itLi;
2199 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2201 const SMESH_TLink & link = (*itLi);
2202 itLE = mapLi_listEl.find( link );
2203 if ( itLE == mapLi_listEl.end() )
2206 const SMDS_MeshElement* elem = (*itLE).second.front();
2208 elem = (*itLE).second.back();
2209 mapLi_listEl.erase( itLE );
2210 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2221 // add other links of elem to list of links to re-start from
2222 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2223 set< SMESH_TLink >::iterator it;
2224 for ( it = links.begin(); it != links.end(); it++ ) {
2225 const SMESH_TLink& link2 = (*it);
2226 if ( link2 != link )
2227 startLinks.push_back( link2 );
2231 // Get nodes of possible quadrangles
2232 const SMDS_MeshNode *n12 [4], *n13 [4];
2233 bool Ok12 = false, Ok13 = false;
2234 const SMDS_MeshNode *linkNode1, *linkNode2;
2236 linkNode1 = link12->first;
2237 linkNode2 = link12->second;
2238 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2242 linkNode1 = link13->first;
2243 linkNode2 = link13->second;
2244 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2248 // Choose a pair to fuse
2249 if ( Ok12 && Ok13 ) {
2250 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2251 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2252 double aBadRate12 = getBadRate( &quad12, theCrit );
2253 double aBadRate13 = getBadRate( &quad13, theCrit );
2254 if ( aBadRate13 < aBadRate12 )
2261 // and remove fused elems and removed links from the maps
2262 mapEl_setLi.erase( tr1 );
2264 mapEl_setLi.erase( tr2 );
2265 mapLi_listEl.erase( *link12 );
2266 if(tr1->NbNodes()==3) {
2267 const SMDS_MeshElement* newElem = 0;
2268 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2269 myLastCreatedElems.Append(newElem);
2270 AddToSameGroups( newElem, tr1, aMesh );
2271 int aShapeId = tr1->getshapeId();
2274 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2276 aMesh->RemoveElement( tr1 );
2277 aMesh->RemoveElement( tr2 );
2280 const SMDS_MeshNode* N1 [6];
2281 const SMDS_MeshNode* N2 [6];
2282 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2283 // now we receive following N1 and N2 (using numeration as above image)
2284 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2285 // i.e. first nodes from both arrays determ new diagonal
2286 const SMDS_MeshNode* aNodes[8];
2295 const SMDS_MeshElement* newElem = 0;
2296 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2297 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2298 myLastCreatedElems.Append(newElem);
2299 AddToSameGroups( newElem, tr1, aMesh );
2300 int aShapeId = tr1->getshapeId();
2303 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2305 aMesh->RemoveElement( tr1 );
2306 aMesh->RemoveElement( tr2 );
2307 // remove middle node (9)
2308 GetMeshDS()->RemoveNode( N1[4] );
2312 mapEl_setLi.erase( tr3 );
2313 mapLi_listEl.erase( *link13 );
2314 if(tr1->NbNodes()==3) {
2315 const SMDS_MeshElement* newElem = 0;
2316 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2317 myLastCreatedElems.Append(newElem);
2318 AddToSameGroups( newElem, tr1, aMesh );
2319 int aShapeId = tr1->getshapeId();
2322 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2324 aMesh->RemoveElement( tr1 );
2325 aMesh->RemoveElement( tr3 );
2328 const SMDS_MeshNode* N1 [6];
2329 const SMDS_MeshNode* N2 [6];
2330 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2331 // now we receive following N1 and N2 (using numeration as above image)
2332 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2333 // i.e. first nodes from both arrays determ new diagonal
2334 const SMDS_MeshNode* aNodes[8];
2343 const SMDS_MeshElement* newElem = 0;
2344 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2345 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2346 myLastCreatedElems.Append(newElem);
2347 AddToSameGroups( newElem, tr1, aMesh );
2348 int aShapeId = tr1->getshapeId();
2351 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2353 aMesh->RemoveElement( tr1 );
2354 aMesh->RemoveElement( tr3 );
2355 // remove middle node (9)
2356 GetMeshDS()->RemoveNode( N1[4] );
2360 // Next element to fuse: the rejected one
2362 startElem = Ok12 ? tr3 : tr2;
2364 } // if ( startElem )
2365 } // while ( startElem || !startLinks.empty() )
2366 } // while ( ! mapEl_setLi.empty() )
2372 /*#define DUMPSO(txt) \
2373 // cout << txt << endl;
2374 //=============================================================================
2378 //=============================================================================
2379 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2383 int tmp = idNodes[ i1 ];
2384 idNodes[ i1 ] = idNodes[ i2 ];
2385 idNodes[ i2 ] = tmp;
2386 gp_Pnt Ptmp = P[ i1 ];
2389 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2392 //=======================================================================
2393 //function : SortQuadNodes
2394 //purpose : Set 4 nodes of a quadrangle face in a good order.
2395 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2397 //=======================================================================
2399 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2404 for ( i = 0; i < 4; i++ ) {
2405 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2407 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2410 gp_Vec V1(P[0], P[1]);
2411 gp_Vec V2(P[0], P[2]);
2412 gp_Vec V3(P[0], P[3]);
2414 gp_Vec Cross1 = V1 ^ V2;
2415 gp_Vec Cross2 = V2 ^ V3;
2418 if (Cross1.Dot(Cross2) < 0)
2423 if (Cross1.Dot(Cross2) < 0)
2427 swap ( i, i + 1, idNodes, P );
2429 // for ( int ii = 0; ii < 4; ii++ ) {
2430 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2431 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2437 //=======================================================================
2438 //function : SortHexaNodes
2439 //purpose : Set 8 nodes of a hexahedron in a good order.
2440 // Return success status
2441 //=======================================================================
2443 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2448 DUMPSO( "INPUT: ========================================");
2449 for ( i = 0; i < 8; i++ ) {
2450 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2451 if ( !n ) return false;
2452 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2453 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2455 DUMPSO( "========================================");
2458 set<int> faceNodes; // ids of bottom face nodes, to be found
2459 set<int> checkedId1; // ids of tried 2-nd nodes
2460 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2461 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2462 int iMin, iLoop1 = 0;
2464 // Loop to try the 2-nd nodes
2466 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2468 // Find not checked 2-nd node
2469 for ( i = 1; i < 8; i++ )
2470 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2471 int id1 = idNodes[i];
2472 swap ( 1, i, idNodes, P );
2473 checkedId1.insert ( id1 );
2477 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2478 // ie that all but meybe one (id3 which is on the same face) nodes
2479 // lay on the same side from the triangle plane.
2481 bool manyInPlane = false; // more than 4 nodes lay in plane
2483 while ( ++iLoop2 < 6 ) {
2485 // get 1-2-3 plane coeffs
2486 Standard_Real A, B, C, D;
2487 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2488 if ( N.SquareMagnitude() > gp::Resolution() )
2490 gp_Pln pln ( P[0], N );
2491 pln.Coefficients( A, B, C, D );
2493 // find the node (iMin) closest to pln
2494 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2496 for ( i = 3; i < 8; i++ ) {
2497 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2498 if ( fabs( dist[i] ) < minDist ) {
2499 minDist = fabs( dist[i] );
2502 if ( fabs( dist[i] ) <= tol )
2503 idInPln.insert( idNodes[i] );
2506 // there should not be more than 4 nodes in bottom plane
2507 if ( idInPln.size() > 1 )
2509 DUMPSO( "### idInPln.size() = " << idInPln.size());
2510 // idInPlane does not contain the first 3 nodes
2511 if ( manyInPlane || idInPln.size() == 5)
2512 return false; // all nodes in one plane
2515 // set the 1-st node to be not in plane
2516 for ( i = 3; i < 8; i++ ) {
2517 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2518 DUMPSO( "### Reset 0-th node");
2519 swap( 0, i, idNodes, P );
2524 // reset to re-check second nodes
2525 leastDist = DBL_MAX;
2529 break; // from iLoop2;
2532 // check that the other 4 nodes are on the same side
2533 bool sameSide = true;
2534 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2535 for ( i = 3; sameSide && i < 8; i++ ) {
2537 sameSide = ( isNeg == dist[i] <= 0.);
2540 // keep best solution
2541 if ( sameSide && minDist < leastDist ) {
2542 leastDist = minDist;
2544 faceNodes.insert( idNodes[ 1 ] );
2545 faceNodes.insert( idNodes[ 2 ] );
2546 faceNodes.insert( idNodes[ iMin ] );
2547 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2548 << " leastDist = " << leastDist);
2549 if ( leastDist <= DBL_MIN )
2554 // set next 3-d node to check
2555 int iNext = 2 + iLoop2;
2557 DUMPSO( "Try 2-nd");
2558 swap ( 2, iNext, idNodes, P );
2560 } // while ( iLoop2 < 6 )
2563 if ( faceNodes.empty() ) return false;
2565 // Put the faceNodes in proper places
2566 for ( i = 4; i < 8; i++ ) {
2567 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2568 // find a place to put
2570 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2572 DUMPSO( "Set faceNodes");
2573 swap ( iTo, i, idNodes, P );
2578 // Set nodes of the found bottom face in good order
2579 DUMPSO( " Found bottom face: ");
2580 i = SortQuadNodes( theMesh, idNodes );
2582 gp_Pnt Ptmp = P[ i ];
2587 // for ( int ii = 0; ii < 4; ii++ ) {
2588 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2589 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2592 // Gravity center of the top and bottom faces
2593 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2594 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2596 // Get direction from the bottom to the top face
2597 gp_Vec upDir ( aGCb, aGCt );
2598 Standard_Real upDirSize = upDir.Magnitude();
2599 if ( upDirSize <= gp::Resolution() ) return false;
2602 // Assure that the bottom face normal points up
2603 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2604 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2605 if ( Nb.Dot( upDir ) < 0 ) {
2606 DUMPSO( "Reverse bottom face");
2607 swap( 1, 3, idNodes, P );
2610 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2611 Standard_Real minDist = DBL_MAX;
2612 for ( i = 4; i < 8; i++ ) {
2613 // projection of P[i] to the plane defined by P[0] and upDir
2614 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2615 Standard_Real sqDist = P[0].SquareDistance( Pp );
2616 if ( sqDist < minDist ) {
2621 DUMPSO( "Set 4-th");
2622 swap ( 4, iMin, idNodes, P );
2624 // Set nodes of the top face in good order
2625 DUMPSO( "Sort top face");
2626 i = SortQuadNodes( theMesh, &idNodes[4] );
2629 gp_Pnt Ptmp = P[ i ];
2634 // Assure that direction of the top face normal is from the bottom face
2635 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2636 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2637 if ( Nt.Dot( upDir ) < 0 ) {
2638 DUMPSO( "Reverse top face");
2639 swap( 5, 7, idNodes, P );
2642 // DUMPSO( "OUTPUT: ========================================");
2643 // for ( i = 0; i < 8; i++ ) {
2644 // float *p = ugrid->GetPoint(idNodes[i]);
2645 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2651 //================================================================================
2653 * \brief Return nodes linked to the given one
2654 * \param theNode - the node
2655 * \param linkedNodes - the found nodes
2656 * \param type - the type of elements to check
2658 * Medium nodes are ignored
2660 //================================================================================
2662 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2663 TIDSortedElemSet & linkedNodes,
2664 SMDSAbs_ElementType type )
2666 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2667 while ( elemIt->more() )
2669 const SMDS_MeshElement* elem = elemIt->next();
2670 if(elem->GetType() == SMDSAbs_0DElement)
2673 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2674 if ( elem->GetType() == SMDSAbs_Volume )
2676 SMDS_VolumeTool vol( elem );
2677 while ( nodeIt->more() ) {
2678 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2679 if ( theNode != n && vol.IsLinked( theNode, n ))
2680 linkedNodes.insert( n );
2685 for ( int i = 0; nodeIt->more(); ++i ) {
2686 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2687 if ( n == theNode ) {
2688 int iBefore = i - 1;
2690 if ( elem->IsQuadratic() ) {
2691 int nb = elem->NbNodes() / 2;
2692 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2693 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2695 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2696 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2703 //=======================================================================
2704 //function : laplacianSmooth
2705 //purpose : pulls theNode toward the center of surrounding nodes directly
2706 // connected to that node along an element edge
2707 //=======================================================================
2709 void laplacianSmooth(const SMDS_MeshNode* theNode,
2710 const Handle(Geom_Surface)& theSurface,
2711 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2713 // find surrounding nodes
2715 TIDSortedElemSet nodeSet;
2716 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2718 // compute new coodrs
2720 double coord[] = { 0., 0., 0. };
2721 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2722 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2723 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2724 if ( theSurface.IsNull() ) { // smooth in 3D
2725 coord[0] += node->X();
2726 coord[1] += node->Y();
2727 coord[2] += node->Z();
2729 else { // smooth in 2D
2730 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2731 gp_XY* uv = theUVMap[ node ];
2732 coord[0] += uv->X();
2733 coord[1] += uv->Y();
2736 int nbNodes = nodeSet.size();
2739 coord[0] /= nbNodes;
2740 coord[1] /= nbNodes;
2742 if ( !theSurface.IsNull() ) {
2743 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2744 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2745 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2751 coord[2] /= nbNodes;
2755 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2758 //=======================================================================
2759 //function : centroidalSmooth
2760 //purpose : pulls theNode toward the element-area-weighted centroid of the
2761 // surrounding elements
2762 //=======================================================================
2764 void centroidalSmooth(const SMDS_MeshNode* theNode,
2765 const Handle(Geom_Surface)& theSurface,
2766 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2768 gp_XYZ aNewXYZ(0.,0.,0.);
2769 SMESH::Controls::Area anAreaFunc;
2770 double totalArea = 0.;
2775 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2776 while ( elemIt->more() )
2778 const SMDS_MeshElement* elem = elemIt->next();
2781 gp_XYZ elemCenter(0.,0.,0.);
2782 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2783 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2784 int nn = elem->NbNodes();
2785 if(elem->IsQuadratic()) nn = nn/2;
2787 //while ( itN->more() ) {
2789 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2791 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2792 aNodePoints.push_back( aP );
2793 if ( !theSurface.IsNull() ) { // smooth in 2D
2794 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2795 gp_XY* uv = theUVMap[ aNode ];
2796 aP.SetCoord( uv->X(), uv->Y(), 0. );
2800 double elemArea = anAreaFunc.GetValue( aNodePoints );
2801 totalArea += elemArea;
2803 aNewXYZ += elemCenter * elemArea;
2805 aNewXYZ /= totalArea;
2806 if ( !theSurface.IsNull() ) {
2807 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2808 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2813 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2816 //=======================================================================
2817 //function : getClosestUV
2818 //purpose : return UV of closest projection
2819 //=======================================================================
2821 static bool getClosestUV (Extrema_GenExtPS& projector,
2822 const gp_Pnt& point,
2825 projector.Perform( point );
2826 if ( projector.IsDone() ) {
2827 double u, v, minVal = DBL_MAX;
2828 for ( int i = projector.NbExt(); i > 0; i-- )
2829 if ( projector.Value( i ) < minVal ) {
2830 minVal = projector.Value( i );
2831 projector.Point( i ).Parameter( u, v );
2833 result.SetCoord( u, v );
2839 //=======================================================================
2841 //purpose : Smooth theElements during theNbIterations or until a worst
2842 // element has aspect ratio <= theTgtAspectRatio.
2843 // Aspect Ratio varies in range [1.0, inf].
2844 // If theElements is empty, the whole mesh is smoothed.
2845 // theFixedNodes contains additionally fixed nodes. Nodes built
2846 // on edges and boundary nodes are always fixed.
2847 //=======================================================================
2849 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2850 set<const SMDS_MeshNode*> & theFixedNodes,
2851 const SmoothMethod theSmoothMethod,
2852 const int theNbIterations,
2853 double theTgtAspectRatio,
2856 myLastCreatedElems.Clear();
2857 myLastCreatedNodes.Clear();
2859 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2861 if ( theTgtAspectRatio < 1.0 )
2862 theTgtAspectRatio = 1.0;
2864 const double disttol = 1.e-16;
2866 SMESH::Controls::AspectRatio aQualityFunc;
2868 SMESHDS_Mesh* aMesh = GetMeshDS();
2870 if ( theElems.empty() ) {
2871 // add all faces to theElems
2872 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2873 while ( fIt->more() ) {
2874 const SMDS_MeshElement* face = fIt->next();
2875 theElems.insert( face );
2878 // get all face ids theElems are on
2879 set< int > faceIdSet;
2880 TIDSortedElemSet::iterator itElem;
2882 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2883 int fId = FindShape( *itElem );
2884 // check that corresponding submesh exists and a shape is face
2886 faceIdSet.find( fId ) == faceIdSet.end() &&
2887 aMesh->MeshElements( fId )) {
2888 TopoDS_Shape F = aMesh->IndexToShape( fId );
2889 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2890 faceIdSet.insert( fId );
2893 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2895 // ===============================================
2896 // smooth elements on each TopoDS_Face separately
2897 // ===============================================
2899 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2900 for ( ; fId != faceIdSet.rend(); ++fId ) {
2901 // get face surface and submesh
2902 Handle(Geom_Surface) surface;
2903 SMESHDS_SubMesh* faceSubMesh = 0;
2905 double fToler2 = 0, f,l;
2906 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2907 bool isUPeriodic = false, isVPeriodic = false;
2909 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2910 surface = BRep_Tool::Surface( face );
2911 faceSubMesh = aMesh->MeshElements( *fId );
2912 fToler2 = BRep_Tool::Tolerance( face );
2913 fToler2 *= fToler2 * 10.;
2914 isUPeriodic = surface->IsUPeriodic();
2917 isVPeriodic = surface->IsVPeriodic();
2920 surface->Bounds( u1, u2, v1, v2 );
2922 // ---------------------------------------------------------
2923 // for elements on a face, find movable and fixed nodes and
2924 // compute UV for them
2925 // ---------------------------------------------------------
2926 bool checkBoundaryNodes = false;
2927 bool isQuadratic = false;
2928 set<const SMDS_MeshNode*> setMovableNodes;
2929 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2930 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2931 list< const SMDS_MeshElement* > elemsOnFace;
2933 Extrema_GenExtPS projector;
2934 GeomAdaptor_Surface surfAdaptor;
2935 if ( !surface.IsNull() ) {
2936 surfAdaptor.Load( surface );
2937 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2939 int nbElemOnFace = 0;
2940 itElem = theElems.begin();
2941 // loop on not yet smoothed elements: look for elems on a face
2942 while ( itElem != theElems.end() ) {
2943 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2944 break; // all elements found
2946 const SMDS_MeshElement* elem = *itElem;
2947 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2948 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2952 elemsOnFace.push_back( elem );
2953 theElems.erase( itElem++ );
2957 isQuadratic = elem->IsQuadratic();
2959 // get movable nodes of elem
2960 const SMDS_MeshNode* node;
2961 SMDS_TypeOfPosition posType;
2962 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2963 int nn = 0, nbn = elem->NbNodes();
2964 if(elem->IsQuadratic())
2966 while ( nn++ < nbn ) {
2967 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2968 const SMDS_PositionPtr& pos = node->GetPosition();
2969 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2970 if (posType != SMDS_TOP_EDGE &&
2971 posType != SMDS_TOP_VERTEX &&
2972 theFixedNodes.find( node ) == theFixedNodes.end())
2974 // check if all faces around the node are on faceSubMesh
2975 // because a node on edge may be bound to face
2976 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2978 if ( faceSubMesh ) {
2979 while ( eIt->more() && all ) {
2980 const SMDS_MeshElement* e = eIt->next();
2981 all = faceSubMesh->Contains( e );
2985 setMovableNodes.insert( node );
2987 checkBoundaryNodes = true;
2989 if ( posType == SMDS_TOP_3DSPACE )
2990 checkBoundaryNodes = true;
2993 if ( surface.IsNull() )
2996 // get nodes to check UV
2997 list< const SMDS_MeshNode* > uvCheckNodes;
2998 itN = elem->nodesIterator();
2999 nn = 0; nbn = elem->NbNodes();
3000 if(elem->IsQuadratic())
3002 while ( nn++ < nbn ) {
3003 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3004 if ( uvMap.find( node ) == uvMap.end() )
3005 uvCheckNodes.push_back( node );
3006 // add nodes of elems sharing node
3007 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3008 // while ( eIt->more() ) {
3009 // const SMDS_MeshElement* e = eIt->next();
3010 // if ( e != elem ) {
3011 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3012 // while ( nIt->more() ) {
3013 // const SMDS_MeshNode* n =
3014 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3015 // if ( uvMap.find( n ) == uvMap.end() )
3016 // uvCheckNodes.push_back( n );
3022 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3023 for ( ; n != uvCheckNodes.end(); ++n ) {
3026 const SMDS_PositionPtr& pos = node->GetPosition();
3027 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3029 switch ( posType ) {
3030 case SMDS_TOP_FACE: {
3031 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3032 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3035 case SMDS_TOP_EDGE: {
3036 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3037 Handle(Geom2d_Curve) pcurve;
3038 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3039 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3040 if ( !pcurve.IsNull() ) {
3041 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3042 uv = pcurve->Value( u ).XY();
3046 case SMDS_TOP_VERTEX: {
3047 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3048 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3049 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3054 // check existing UV
3055 bool project = true;
3056 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3057 double dist1 = DBL_MAX, dist2 = 0;
3058 if ( posType != SMDS_TOP_3DSPACE ) {
3059 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3060 project = dist1 > fToler2;
3062 if ( project ) { // compute new UV
3064 if ( !getClosestUV( projector, pNode, newUV )) {
3065 MESSAGE("Node Projection Failed " << node);
3069 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3071 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3073 if ( posType != SMDS_TOP_3DSPACE )
3074 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3075 if ( dist2 < dist1 )
3079 // store UV in the map
3080 listUV.push_back( uv );
3081 uvMap.insert( make_pair( node, &listUV.back() ));
3083 } // loop on not yet smoothed elements
3085 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3086 checkBoundaryNodes = true;
3088 // fix nodes on mesh boundary
3090 if ( checkBoundaryNodes ) {
3091 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3092 map< NLink, int >::iterator link_nb;
3093 // put all elements links to linkNbMap
3094 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3095 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3096 const SMDS_MeshElement* elem = (*elemIt);
3097 int nbn = elem->NbNodes();
3098 if(elem->IsQuadratic())
3100 // loop on elem links: insert them in linkNbMap
3101 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3102 for ( int iN = 0; iN < nbn; ++iN ) {
3103 curNode = elem->GetNode( iN );
3105 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3106 else link = make_pair( prevNode , curNode );
3108 link_nb = linkNbMap.find( link );
3109 if ( link_nb == linkNbMap.end() )
3110 linkNbMap.insert( make_pair ( link, 1 ));
3115 // remove nodes that are in links encountered only once from setMovableNodes
3116 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3117 if ( link_nb->second == 1 ) {
3118 setMovableNodes.erase( link_nb->first.first );
3119 setMovableNodes.erase( link_nb->first.second );
3124 // -----------------------------------------------------
3125 // for nodes on seam edge, compute one more UV ( uvMap2 );
3126 // find movable nodes linked to nodes on seam and which
3127 // are to be smoothed using the second UV ( uvMap2 )
3128 // -----------------------------------------------------
3130 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3131 if ( !surface.IsNull() ) {
3132 TopExp_Explorer eExp( face, TopAbs_EDGE );
3133 for ( ; eExp.More(); eExp.Next() ) {
3134 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3135 if ( !BRep_Tool::IsClosed( edge, face ))
3137 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3138 if ( !sm ) continue;
3139 // find out which parameter varies for a node on seam
3142 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3143 if ( pcurve.IsNull() ) continue;
3144 uv1 = pcurve->Value( f );
3146 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3147 if ( pcurve.IsNull() ) continue;
3148 uv2 = pcurve->Value( f );
3149 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3151 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3152 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3154 // get nodes on seam and its vertices
3155 list< const SMDS_MeshNode* > seamNodes;
3156 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3157 while ( nSeamIt->more() ) {
3158 const SMDS_MeshNode* node = nSeamIt->next();
3159 if ( !isQuadratic || !IsMedium( node ))
3160 seamNodes.push_back( node );
3162 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3163 for ( ; vExp.More(); vExp.Next() ) {
3164 sm = aMesh->MeshElements( vExp.Current() );
3166 nSeamIt = sm->GetNodes();
3167 while ( nSeamIt->more() )
3168 seamNodes.push_back( nSeamIt->next() );
3171 // loop on nodes on seam
3172 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3173 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3174 const SMDS_MeshNode* nSeam = *noSeIt;
3175 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3176 if ( n_uv == uvMap.end() )
3179 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3180 // set the second UV
3181 listUV.push_back( *n_uv->second );
3182 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3183 if ( uvMap2.empty() )
3184 uvMap2 = uvMap; // copy the uvMap contents
3185 uvMap2[ nSeam ] = &listUV.back();
3187 // collect movable nodes linked to ones on seam in nodesNearSeam
3188 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3189 while ( eIt->more() ) {
3190 const SMDS_MeshElement* e = eIt->next();
3191 int nbUseMap1 = 0, nbUseMap2 = 0;
3192 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3193 int nn = 0, nbn = e->NbNodes();
3194 if(e->IsQuadratic()) nbn = nbn/2;
3195 while ( nn++ < nbn )
3197 const SMDS_MeshNode* n =
3198 static_cast<const SMDS_MeshNode*>( nIt->next() );
3200 setMovableNodes.find( n ) == setMovableNodes.end() )
3202 // add only nodes being closer to uv2 than to uv1
3203 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3204 0.5 * ( n->Y() + nSeam->Y() ),
3205 0.5 * ( n->Z() + nSeam->Z() ));
3207 getClosestUV( projector, pMid, uv );
3208 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3209 nodesNearSeam.insert( n );
3215 // for centroidalSmooth all element nodes must
3216 // be on one side of a seam
3217 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3218 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3220 while ( nn++ < nbn ) {
3221 const SMDS_MeshNode* n =
3222 static_cast<const SMDS_MeshNode*>( nIt->next() );
3223 setMovableNodes.erase( n );
3227 } // loop on nodes on seam
3228 } // loop on edge of a face
3229 } // if ( !face.IsNull() )
3231 if ( setMovableNodes.empty() ) {
3232 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3233 continue; // goto next face
3241 double maxRatio = -1., maxDisplacement = -1.;
3242 set<const SMDS_MeshNode*>::iterator nodeToMove;
3243 for ( it = 0; it < theNbIterations; it++ ) {
3244 maxDisplacement = 0.;
3245 nodeToMove = setMovableNodes.begin();
3246 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3247 const SMDS_MeshNode* node = (*nodeToMove);
3248 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3251 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3252 if ( theSmoothMethod == LAPLACIAN )
3253 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3255 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3257 // node displacement
3258 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3259 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3260 if ( aDispl > maxDisplacement )
3261 maxDisplacement = aDispl;
3263 // no node movement => exit
3264 //if ( maxDisplacement < 1.e-16 ) {
3265 if ( maxDisplacement < disttol ) {
3266 MESSAGE("-- no node movement --");
3270 // check elements quality
3272 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3273 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3274 const SMDS_MeshElement* elem = (*elemIt);
3275 if ( !elem || elem->GetType() != SMDSAbs_Face )
3277 SMESH::Controls::TSequenceOfXYZ aPoints;
3278 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3279 double aValue = aQualityFunc.GetValue( aPoints );
3280 if ( aValue > maxRatio )
3284 if ( maxRatio <= theTgtAspectRatio ) {
3285 MESSAGE("-- quality achived --");
3288 if (it+1 == theNbIterations) {
3289 MESSAGE("-- Iteration limit exceeded --");
3291 } // smoothing iterations
3293 MESSAGE(" Face id: " << *fId <<
3294 " Nb iterstions: " << it <<
3295 " Displacement: " << maxDisplacement <<
3296 " Aspect Ratio " << maxRatio);
3298 // ---------------------------------------
3299 // new nodes positions are computed,
3300 // record movement in DS and set new UV
3301 // ---------------------------------------
3302 nodeToMove = setMovableNodes.begin();
3303 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3304 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3305 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3306 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3307 if ( node_uv != uvMap.end() ) {
3308 gp_XY* uv = node_uv->second;
3310 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3314 // move medium nodes of quadratic elements
3317 SMESH_MesherHelper helper( *GetMesh() );
3318 if ( !face.IsNull() )
3319 helper.SetSubShape( face );
3320 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3321 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3322 const SMDS_VtkFace* QF =
3323 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3324 if(QF && QF->IsQuadratic()) {
3325 vector<const SMDS_MeshNode*> Ns;
3326 Ns.reserve(QF->NbNodes()+1);
3327 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3328 while ( anIter->more() )
3329 Ns.push_back( cast2Node(anIter->next()) );
3330 Ns.push_back( Ns[0] );
3332 for(int i=0; i<QF->NbNodes(); i=i+2) {
3333 if ( !surface.IsNull() ) {
3334 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3335 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3336 gp_XY uv = ( uv1 + uv2 ) / 2.;
3337 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3338 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3341 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3342 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3343 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3345 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3346 fabs( Ns[i+1]->Y() - y ) > disttol ||
3347 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3348 // we have to move i+1 node
3349 aMesh->MoveNode( Ns[i+1], x, y, z );
3356 } // loop on face ids
3360 //=======================================================================
3361 //function : isReverse
3362 //purpose : Return true if normal of prevNodes is not co-directied with
3363 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3364 // iNotSame is where prevNodes and nextNodes are different
3365 //=======================================================================
3367 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3368 vector<const SMDS_MeshNode*> nextNodes,
3372 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3373 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3375 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3376 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3377 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3378 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3380 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3381 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3382 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3383 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3385 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3387 return (vA ^ vB) * vN < 0.0;
3390 //=======================================================================
3392 * \brief Create elements by sweeping an element
3393 * \param elem - element to sweep
3394 * \param newNodesItVec - nodes generated from each node of the element
3395 * \param newElems - generated elements
3396 * \param nbSteps - number of sweeping steps
3397 * \param srcElements - to append elem for each generated element
3399 //=======================================================================
3401 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3402 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3403 list<const SMDS_MeshElement*>& newElems,
3405 SMESH_SequenceOfElemPtr& srcElements)
3407 //MESSAGE("sweepElement " << nbSteps);
3408 SMESHDS_Mesh* aMesh = GetMeshDS();
3410 // Loop on elem nodes:
3411 // find new nodes and detect same nodes indices
3412 int nbNodes = elem->NbNodes();
3413 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3414 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3415 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3416 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3418 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3419 vector<int> sames(nbNodes);
3420 vector<bool> issimple(nbNodes);
3422 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3423 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3424 const SMDS_MeshNode* node = nnIt->first;
3425 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3426 if ( listNewNodes.empty() ) {
3430 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3432 itNN[ iNode ] = listNewNodes.begin();
3433 prevNod[ iNode ] = node;
3434 nextNod[ iNode ] = listNewNodes.front();
3435 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3436 if ( prevNod[ iNode ] != nextNod [ iNode ])
3437 iNotSameNode = iNode;
3441 sames[nbSame++] = iNode;
3446 //cerr<<" nbSame = "<<nbSame<<endl;
3447 if ( nbSame == nbNodes || nbSame > 2) {
3448 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3449 //INFOS( " Too many same nodes of element " << elem->GetID() );
3453 // if( elem->IsQuadratic() && nbSame>0 ) {
3454 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3458 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3459 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3461 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3462 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3463 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3467 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3468 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3469 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3470 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3472 // check element orientation
3474 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3475 //MESSAGE("Reversed elem " << elem );
3479 std::swap( iBeforeSame, iAfterSame );
3482 // make new elements
3483 const SMDS_MeshElement* lastElem = elem;
3484 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3486 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3487 if(issimple[iNode]) {
3488 nextNod[ iNode ] = *itNN[ iNode ];
3492 if( elem->GetType()==SMDSAbs_Node ) {
3493 // we have to use two nodes
3494 midlNod[ iNode ] = *itNN[ iNode ];
3496 nextNod[ iNode ] = *itNN[ iNode ];
3499 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3500 // we have to use each second node
3502 nextNod[ iNode ] = *itNN[ iNode ];
3506 // we have to use two nodes
3507 midlNod[ iNode ] = *itNN[ iNode ];
3509 nextNod[ iNode ] = *itNN[ iNode ];
3514 SMDS_MeshElement* aNewElem = 0;
3515 if(!elem->IsPoly()) {
3516 switch ( nbNodes ) {
3520 if ( nbSame == 0 ) {
3522 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3524 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3530 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3531 nextNod[ 1 ], nextNod[ 0 ] );
3533 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3534 nextNod[ iNotSameNode ] );
3538 case 3: { // TRIANGLE or quadratic edge
3539 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3541 if ( nbSame == 0 ) // --- pentahedron
3542 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3543 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3545 else if ( nbSame == 1 ) // --- pyramid
3546 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3547 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3548 nextNod[ iSameNode ]);
3550 else // 2 same nodes: --- tetrahedron
3551 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3552 nextNod[ iNotSameNode ]);
3554 else { // quadratic edge
3555 if(nbSame==0) { // quadratic quadrangle
3556 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3557 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3559 else if(nbSame==1) { // quadratic triangle
3561 return; // medium node on axis
3563 else if(sames[0]==0) {
3564 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3565 nextNod[2], midlNod[1], prevNod[2]);
3567 else { // sames[0]==1
3568 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3569 midlNod[0], nextNod[2], prevNod[2]);
3578 case 4: { // QUADRANGLE
3580 if ( nbSame == 0 ) // --- hexahedron
3581 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3582 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3584 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3585 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3586 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3587 nextNod[ iSameNode ]);
3588 newElems.push_back( aNewElem );
3589 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3590 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3591 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3593 else if ( nbSame == 2 ) { // pentahedron
3594 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3595 // iBeforeSame is same too
3596 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3597 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3598 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3600 // iAfterSame is same too
3601 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3602 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3603 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3607 case 6: { // quadratic triangle
3608 // create pentahedron with 15 nodes
3610 if(i0>0) { // reversed case
3611 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3612 nextNod[0], nextNod[2], nextNod[1],
3613 prevNod[5], prevNod[4], prevNod[3],
3614 nextNod[5], nextNod[4], nextNod[3],
3615 midlNod[0], midlNod[2], midlNod[1]);
3617 else { // not reversed case
3618 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3619 nextNod[0], nextNod[1], nextNod[2],
3620 prevNod[3], prevNod[4], prevNod[5],
3621 nextNod[3], nextNod[4], nextNod[5],
3622 midlNod[0], midlNod[1], midlNod[2]);
3625 else if(nbSame==1) {
3626 // 2d order pyramid of 13 nodes
3627 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3628 // int n12,int n23,int n34,int n41,
3629 // int n15,int n25,int n35,int n45, int ID);
3631 int n1,n4,n41,n15,n45;
3632 if(i0>0) { // reversed case
3633 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3634 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3640 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3641 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3646 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3647 nextNod[n4], prevNod[n4], prevNod[n5],
3648 midlNod[n1], nextNod[n41],
3649 midlNod[n4], prevNod[n41],
3650 prevNod[n15], nextNod[n15],
3651 nextNod[n45], prevNod[n45]);
3653 else if(nbSame==2) {
3654 // 2d order tetrahedron of 10 nodes
3655 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3656 // int n12,int n23,int n31,
3657 // int n14,int n24,int n34, int ID);
3658 int n1 = iNotSameNode;
3659 int n2,n3,n12,n23,n31;
3660 if(i0>0) { // reversed case
3661 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3662 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3668 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3669 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3674 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3675 prevNod[n12], prevNod[n23], prevNod[n31],
3676 midlNod[n1], nextNod[n12], nextNod[n31]);
3680 case 8: { // quadratic quadrangle
3682 // create hexahedron with 20 nodes
3683 if(i0>0) { // reversed case
3684 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3685 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3686 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3687 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3688 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3690 else { // not reversed case
3691 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3692 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3693 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3694 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3695 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3698 else if(nbSame==1) {
3699 // --- pyramid + pentahedron - can not be created since it is needed
3700 // additional middle node ot the center of face
3701 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3704 else if(nbSame==2) {
3705 // 2d order Pentahedron with 15 nodes
3706 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3707 // int n12,int n23,int n31,int n45,int n56,int n64,
3708 // int n14,int n25,int n36, int ID);
3710 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3711 // iBeforeSame is same too
3718 // iAfterSame is same too
3724 int n12,n45,n14,n25;
3725 if(i0>0) { //reversed case
3737 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3738 prevNod[n4], prevNod[n5], nextNod[n5],
3739 prevNod[n12], midlNod[n2], nextNod[n12],
3740 prevNod[n45], midlNod[n5], nextNod[n45],
3741 prevNod[n14], prevNod[n25], nextNod[n25]);
3746 // realized for extrusion only
3747 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3748 //vector<int> quantities (nbNodes + 2);
3750 //quantities[0] = nbNodes; // bottom of prism
3751 //for (int inode = 0; inode < nbNodes; inode++) {
3752 // polyedre_nodes[inode] = prevNod[inode];
3755 //quantities[1] = nbNodes; // top of prism
3756 //for (int inode = 0; inode < nbNodes; inode++) {
3757 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3760 //for (int iface = 0; iface < nbNodes; iface++) {
3761 // quantities[iface + 2] = 4;
3762 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3763 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3764 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3765 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3766 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3768 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3775 // realized for extrusion only
3776 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3777 vector<int> quantities (nbNodes + 2);
3779 quantities[0] = nbNodes; // bottom of prism
3780 for (int inode = 0; inode < nbNodes; inode++) {
3781 polyedre_nodes[inode] = prevNod[inode];
3784 quantities[1] = nbNodes; // top of prism
3785 for (int inode = 0; inode < nbNodes; inode++) {
3786 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3789 for (int iface = 0; iface < nbNodes; iface++) {
3790 quantities[iface + 2] = 4;
3791 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3792 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3793 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3794 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3795 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3797 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3801 newElems.push_back( aNewElem );
3802 myLastCreatedElems.Append(aNewElem);
3803 srcElements.Append( elem );
3804 lastElem = aNewElem;
3807 // set new prev nodes
3808 for ( iNode = 0; iNode < nbNodes; iNode++ )
3809 prevNod[ iNode ] = nextNod[ iNode ];
3814 //=======================================================================
3816 * \brief Create 1D and 2D elements around swept elements
3817 * \param mapNewNodes - source nodes and ones generated from them
3818 * \param newElemsMap - source elements and ones generated from them
3819 * \param elemNewNodesMap - nodes generated from each node of each element
3820 * \param elemSet - all swept elements
3821 * \param nbSteps - number of sweeping steps
3822 * \param srcElements - to append elem for each generated element
3824 //=======================================================================
3826 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3827 TElemOfElemListMap & newElemsMap,
3828 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3829 TIDSortedElemSet& elemSet,
3831 SMESH_SequenceOfElemPtr& srcElements)
3833 MESSAGE("makeWalls");
3834 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3835 SMESHDS_Mesh* aMesh = GetMeshDS();
3837 // Find nodes belonging to only one initial element - sweep them to get edges.
3839 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3840 for ( ; nList != mapNewNodes.end(); nList++ ) {
3841 const SMDS_MeshNode* node =
3842 static_cast<const SMDS_MeshNode*>( nList->first );
3843 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3844 int nbInitElems = 0;
3845 const SMDS_MeshElement* el = 0;
3846 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3847 while ( eIt->more() && nbInitElems < 2 ) {
3849 SMDSAbs_ElementType type = el->GetType();
3850 if ( type == SMDSAbs_Volume || type < highType ) continue;
3851 if ( type > highType ) {
3855 if ( elemSet.find(el) != elemSet.end() )
3858 if ( nbInitElems < 2 ) {
3859 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3860 if(!NotCreateEdge) {
3861 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3862 list<const SMDS_MeshElement*> newEdges;
3863 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3868 // Make a ceiling for each element ie an equal element of last new nodes.
3869 // Find free links of faces - make edges and sweep them into faces.
3871 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3872 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3873 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3874 const SMDS_MeshElement* elem = itElem->first;
3875 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3877 if(itElem->second.size()==0) continue;
3879 if ( elem->GetType() == SMDSAbs_Edge ) {
3880 // create a ceiling edge
3881 if (!elem->IsQuadratic()) {
3882 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3883 vecNewNodes[ 1 ]->second.back())) {
3884 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3885 vecNewNodes[ 1 ]->second.back()));
3886 srcElements.Append( myLastCreatedElems.Last() );
3890 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3891 vecNewNodes[ 1 ]->second.back(),
3892 vecNewNodes[ 2 ]->second.back())) {
3893 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3894 vecNewNodes[ 1 ]->second.back(),
3895 vecNewNodes[ 2 ]->second.back()));
3896 srcElements.Append( myLastCreatedElems.Last() );
3900 if ( elem->GetType() != SMDSAbs_Face )
3903 bool hasFreeLinks = false;
3905 TIDSortedElemSet avoidSet;
3906 avoidSet.insert( elem );
3908 set<const SMDS_MeshNode*> aFaceLastNodes;
3909 int iNode, nbNodes = vecNewNodes.size();
3910 if(!elem->IsQuadratic()) {
3911 // loop on the face nodes
3912 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3913 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3914 // look for free links of the face
3915 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3916 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3917 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3918 // check if a link is free
3919 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3920 hasFreeLinks = true;
3921 // make an edge and a ceiling for a new edge
3922 if ( !aMesh->FindEdge( n1, n2 )) {
3923 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3924 srcElements.Append( myLastCreatedElems.Last() );
3926 n1 = vecNewNodes[ iNode ]->second.back();
3927 n2 = vecNewNodes[ iNext ]->second.back();
3928 if ( !aMesh->FindEdge( n1, n2 )) {
3929 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3930 srcElements.Append( myLastCreatedElems.Last() );
3935 else { // elem is quadratic face
3936 int nbn = nbNodes/2;
3937 for ( iNode = 0; iNode < nbn; iNode++ ) {
3938 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3939 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3940 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3941 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3942 // check if a link is free
3943 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3944 hasFreeLinks = true;
3945 // make an edge and a ceiling for a new edge
3947 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3948 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3949 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3950 srcElements.Append( myLastCreatedElems.Last() );
3952 n1 = vecNewNodes[ iNode ]->second.back();
3953 n2 = vecNewNodes[ iNext ]->second.back();
3954 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3955 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3956 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3957 srcElements.Append( myLastCreatedElems.Last() );
3961 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3962 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3966 // sweep free links into faces
3968 if ( hasFreeLinks ) {
3969 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3970 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3972 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3973 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3974 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3975 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3977 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3978 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3980 while ( iVol++ < volNb ) v++;
3981 // find indices of free faces of a volume and their source edges
3982 list< int > freeInd;
3983 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3984 SMDS_VolumeTool vTool( *v );
3985 int iF, nbF = vTool.NbFaces();
3986 for ( iF = 0; iF < nbF; iF ++ ) {
3987 if (vTool.IsFreeFace( iF ) &&
3988 vTool.GetFaceNodes( iF, faceNodeSet ) &&
3989 initNodeSet != faceNodeSet) // except an initial face
3991 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
3993 freeInd.push_back( iF );
3994 // find source edge of a free face iF
3995 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
3996 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
3997 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
3998 initNodeSet.begin(), initNodeSet.end(),
3999 commonNodes.begin());
4000 if ( (*v)->IsQuadratic() )
4001 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4003 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4005 if ( !srcEdges.back() )
4007 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4008 << iF << " of volume #" << vTool.ID() << endl;
4013 if ( freeInd.empty() )
4016 // create faces for all steps;
4017 // if such a face has been already created by sweep of edge,
4018 // assure that its orientation is OK
4019 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4021 vTool.SetExternalNormal();
4022 list< int >::iterator ind = freeInd.begin();
4023 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4024 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4026 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4027 int nbn = vTool.NbFaceNodes( *ind );
4029 case 3: { ///// triangle
4030 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4032 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4033 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4035 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4036 aMesh->RemoveElement(f);
4040 case 4: { ///// quadrangle
4041 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4043 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4044 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4046 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4047 aMesh->RemoveElement(f);
4052 if( (*v)->IsQuadratic() ) {
4053 if(nbn==6) { /////// quadratic triangle
4054 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4055 nodes[1], nodes[3], nodes[5] );
4057 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4058 nodes[1], nodes[3], nodes[5]));
4060 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4061 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4062 tmpnodes[0] = nodes[0];
4063 tmpnodes[1] = nodes[2];
4064 tmpnodes[2] = nodes[4];
4065 tmpnodes[3] = nodes[1];
4066 tmpnodes[4] = nodes[3];
4067 tmpnodes[5] = nodes[5];
4068 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4069 nodes[1], nodes[3], nodes[5]));
4070 aMesh->RemoveElement(f);
4073 else { /////// quadratic quadrangle
4074 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4075 nodes[1], nodes[3], nodes[5], nodes[7] );
4077 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4078 nodes[1], nodes[3], nodes[5], nodes[7]));
4080 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4081 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4082 tmpnodes[0] = nodes[0];
4083 tmpnodes[1] = nodes[2];
4084 tmpnodes[2] = nodes[4];
4085 tmpnodes[3] = nodes[6];
4086 tmpnodes[4] = nodes[1];
4087 tmpnodes[5] = nodes[3];
4088 tmpnodes[6] = nodes[5];
4089 tmpnodes[7] = nodes[7];
4090 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4091 nodes[1], nodes[3], nodes[5], nodes[7]));
4092 aMesh->RemoveElement(f);
4096 else { //////// polygon
4097 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4098 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4100 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4101 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4103 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4104 MESSAGE("ChangeElementNodes");
4105 aMesh->ChangeElementNodes( f, nodes, nbn );
4109 while ( srcElements.Length() < myLastCreatedElems.Length() )
4110 srcElements.Append( *srcEdge );
4112 } // loop on free faces
4114 // go to the next volume
4116 while ( iVol++ < nbVolumesByStep ) v++;
4119 } // sweep free links into faces
4121 // Make a ceiling face with a normal external to a volume
4123 SMDS_VolumeTool lastVol( itElem->second.back() );
4125 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4127 lastVol.SetExternalNormal();
4128 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4129 int nbn = lastVol.NbFaceNodes( iF );
4132 if (!hasFreeLinks ||
4133 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4134 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4137 if (!hasFreeLinks ||
4138 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4139 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4142 if(itElem->second.back()->IsQuadratic()) {
4144 if (!hasFreeLinks ||
4145 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4146 nodes[1], nodes[3], nodes[5]) ) {
4147 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4148 nodes[1], nodes[3], nodes[5]));
4152 if (!hasFreeLinks ||
4153 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4154 nodes[1], nodes[3], nodes[5], nodes[7]) )
4155 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4156 nodes[1], nodes[3], nodes[5], nodes[7]));
4160 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4161 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4162 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4166 while ( srcElements.Length() < myLastCreatedElems.Length() )
4167 srcElements.Append( myLastCreatedElems.Last() );
4169 } // loop on swept elements
4172 //=======================================================================
4173 //function : RotationSweep
4175 //=======================================================================
4177 SMESH_MeshEditor::PGroupIDs
4178 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4179 const gp_Ax1& theAxis,
4180 const double theAngle,
4181 const int theNbSteps,
4182 const double theTol,
4183 const bool theMakeGroups,
4184 const bool theMakeWalls)
4186 myLastCreatedElems.Clear();
4187 myLastCreatedNodes.Clear();
4189 // source elements for each generated one
4190 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4192 MESSAGE( "RotationSweep()");
4194 aTrsf.SetRotation( theAxis, theAngle );
4196 aTrsf2.SetRotation( theAxis, theAngle/2. );
4198 gp_Lin aLine( theAxis );
4199 double aSqTol = theTol * theTol;
4201 SMESHDS_Mesh* aMesh = GetMeshDS();
4203 TNodeOfNodeListMap mapNewNodes;
4204 TElemOfVecOfNnlmiMap mapElemNewNodes;
4205 TElemOfElemListMap newElemsMap;
4208 TIDSortedElemSet::iterator itElem;
4209 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4210 const SMDS_MeshElement* elem = *itElem;
4211 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4213 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4214 newNodesItVec.reserve( elem->NbNodes() );
4216 // loop on elem nodes
4217 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4218 while ( itN->more() ) {
4219 // check if a node has been already sweeped
4220 const SMDS_MeshNode* node = cast2Node( itN->next() );
4222 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4224 aXYZ.Coord( coord[0], coord[1], coord[2] );
4225 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4227 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4228 if ( nIt == mapNewNodes.end() ) {
4229 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4230 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4233 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4235 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4236 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4237 const SMDS_MeshNode * newNode = node;
4238 for ( int i = 0; i < theNbSteps; i++ ) {
4240 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4242 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4243 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4244 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4245 myLastCreatedNodes.Append(newNode);
4246 srcNodes.Append( node );
4247 listNewNodes.push_back( newNode );
4248 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4249 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4252 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4254 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4255 myLastCreatedNodes.Append(newNode);
4256 srcNodes.Append( node );
4257 listNewNodes.push_back( newNode );
4260 listNewNodes.push_back( newNode );
4261 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4262 listNewNodes.push_back( newNode );
4269 // if current elem is quadratic and current node is not medium
4270 // we have to check - may be it is needed to insert additional nodes
4271 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4272 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4273 if(listNewNodes.size()==theNbSteps) {
4274 listNewNodes.clear();
4276 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4278 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4279 const SMDS_MeshNode * newNode = node;
4281 for(int i = 0; i<theNbSteps; i++) {
4282 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4283 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4284 cout<<" 3 AddNode: "<<newNode;
4285 myLastCreatedNodes.Append(newNode);
4286 listNewNodes.push_back( newNode );
4287 srcNodes.Append( node );
4288 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4289 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4290 cout<<" 4 AddNode: "<<newNode;
4291 myLastCreatedNodes.Append(newNode);
4292 srcNodes.Append( node );
4293 listNewNodes.push_back( newNode );
4297 listNewNodes.push_back( newNode );
4303 newNodesItVec.push_back( nIt );
4305 // make new elements
4306 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4310 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4312 PGroupIDs newGroupIDs;
4313 if ( theMakeGroups )
4314 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4320 //=======================================================================
4321 //function : CreateNode
4323 //=======================================================================
4324 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4327 const double tolnode,
4328 SMESH_SequenceOfNode& aNodes)
4330 myLastCreatedElems.Clear();
4331 myLastCreatedNodes.Clear();
4334 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4336 // try to search in sequence of existing nodes
4337 // if aNodes.Length()>0 we 'nave to use given sequence
4338 // else - use all nodes of mesh
4339 if(aNodes.Length()>0) {
4341 for(i=1; i<=aNodes.Length(); i++) {
4342 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4343 if(P1.Distance(P2)<tolnode)
4344 return aNodes.Value(i);
4348 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4349 while(itn->more()) {
4350 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4351 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4352 if(P1.Distance(P2)<tolnode)
4357 // create new node and return it
4358 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4359 myLastCreatedNodes.Append(NewNode);
4364 //=======================================================================
4365 //function : ExtrusionSweep
4367 //=======================================================================
4369 SMESH_MeshEditor::PGroupIDs
4370 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4371 const gp_Vec& theStep,
4372 const int theNbSteps,
4373 TElemOfElemListMap& newElemsMap,
4374 const bool theMakeGroups,
4376 const double theTolerance)
4378 ExtrusParam aParams;
4379 aParams.myDir = gp_Dir(theStep);
4380 aParams.myNodes.Clear();
4381 aParams.mySteps = new TColStd_HSequenceOfReal;
4383 for(i=1; i<=theNbSteps; i++)
4384 aParams.mySteps->Append(theStep.Magnitude());
4387 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4391 //=======================================================================
4392 //function : ExtrusionSweep
4394 //=======================================================================
4396 SMESH_MeshEditor::PGroupIDs
4397 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4398 ExtrusParam& theParams,
4399 TElemOfElemListMap& newElemsMap,
4400 const bool theMakeGroups,
4402 const double theTolerance)
4404 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4405 myLastCreatedElems.Clear();
4406 myLastCreatedNodes.Clear();
4408 // source elements for each generated one
4409 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4411 SMESHDS_Mesh* aMesh = GetMeshDS();
4413 int nbsteps = theParams.mySteps->Length();
4415 TNodeOfNodeListMap mapNewNodes;
4416 //TNodeOfNodeVecMap mapNewNodes;
4417 TElemOfVecOfNnlmiMap mapElemNewNodes;
4418 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4421 TIDSortedElemSet::iterator itElem;
4422 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4423 // check element type
4424 const SMDS_MeshElement* elem = *itElem;
4425 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4428 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4429 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4430 newNodesItVec.reserve( elem->NbNodes() );
4432 // loop on elem nodes
4433 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4434 while ( itN->more() )
4436 // check if a node has been already sweeped
4437 const SMDS_MeshNode* node = cast2Node( itN->next() );
4438 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4439 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4440 if ( nIt == mapNewNodes.end() ) {
4441 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4442 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4443 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4444 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4445 //vecNewNodes.reserve(nbsteps);
4448 double coord[] = { node->X(), node->Y(), node->Z() };
4449 //int nbsteps = theParams.mySteps->Length();
4450 for ( int i = 0; i < nbsteps; i++ ) {
4451 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4452 // create additional node
4453 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4454 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4455 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4456 if( theFlags & EXTRUSION_FLAG_SEW ) {
4457 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4458 theTolerance, theParams.myNodes);
4459 listNewNodes.push_back( newNode );
4462 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4463 myLastCreatedNodes.Append(newNode);
4464 srcNodes.Append( node );
4465 listNewNodes.push_back( newNode );
4468 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4469 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4470 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4471 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4472 if( theFlags & EXTRUSION_FLAG_SEW ) {
4473 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4474 theTolerance, theParams.myNodes);
4475 listNewNodes.push_back( newNode );
4476 //vecNewNodes[i]=newNode;
4479 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4480 myLastCreatedNodes.Append(newNode);
4481 srcNodes.Append( node );
4482 listNewNodes.push_back( newNode );
4483 //vecNewNodes[i]=newNode;
4488 // if current elem is quadratic and current node is not medium
4489 // we have to check - may be it is needed to insert additional nodes
4490 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4491 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4492 if(listNewNodes.size()==nbsteps) {
4493 listNewNodes.clear();
4494 double coord[] = { node->X(), node->Y(), node->Z() };
4495 for ( int i = 0; i < nbsteps; i++ ) {
4496 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4497 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4498 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4499 if( theFlags & EXTRUSION_FLAG_SEW ) {
4500 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4501 theTolerance, theParams.myNodes);
4502 listNewNodes.push_back( newNode );
4505 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4506 myLastCreatedNodes.Append(newNode);
4507 srcNodes.Append( node );
4508 listNewNodes.push_back( newNode );
4510 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4511 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4512 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4513 if( theFlags & EXTRUSION_FLAG_SEW ) {
4514 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4515 theTolerance, theParams.myNodes);
4516 listNewNodes.push_back( newNode );
4519 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4520 myLastCreatedNodes.Append(newNode);
4521 srcNodes.Append( node );
4522 listNewNodes.push_back( newNode );
4528 newNodesItVec.push_back( nIt );
4530 // make new elements
4531 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4534 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4535 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4537 PGroupIDs newGroupIDs;
4538 if ( theMakeGroups )
4539 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4545 //=======================================================================
4546 //class : SMESH_MeshEditor_PathPoint
4547 //purpose : auxiliary class
4548 //=======================================================================
4549 class SMESH_MeshEditor_PathPoint {
4551 SMESH_MeshEditor_PathPoint() {
4552 myPnt.SetCoord(99., 99., 99.);
4553 myTgt.SetCoord(1.,0.,0.);
4557 void SetPnt(const gp_Pnt& aP3D){
4560 void SetTangent(const gp_Dir& aTgt){
4563 void SetAngle(const double& aBeta){
4566 void SetParameter(const double& aPrm){
4569 const gp_Pnt& Pnt()const{
4572 const gp_Dir& Tangent()const{
4575 double Angle()const{
4578 double Parameter()const{
4590 //=======================================================================
4591 //function : ExtrusionAlongTrack
4593 //=======================================================================
4594 SMESH_MeshEditor::Extrusion_Error
4595 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4596 SMESH_subMesh* theTrack,
4597 const SMDS_MeshNode* theN1,
4598 const bool theHasAngles,
4599 list<double>& theAngles,
4600 const bool theLinearVariation,
4601 const bool theHasRefPoint,
4602 const gp_Pnt& theRefPoint,
4603 const bool theMakeGroups)
4605 MESSAGE("ExtrusionAlongTrack");
4606 myLastCreatedElems.Clear();
4607 myLastCreatedNodes.Clear();
4610 std::list<double> aPrms;
4611 TIDSortedElemSet::iterator itElem;
4614 TopoDS_Edge aTrackEdge;
4615 TopoDS_Vertex aV1, aV2;
4617 SMDS_ElemIteratorPtr aItE;
4618 SMDS_NodeIteratorPtr aItN;
4619 SMDSAbs_ElementType aTypeE;
4621 TNodeOfNodeListMap mapNewNodes;
4624 aNbE = theElements.size();
4627 return EXTR_NO_ELEMENTS;
4629 // 1.1 Track Pattern
4632 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4634 aItE = pSubMeshDS->GetElements();
4635 while ( aItE->more() ) {
4636 const SMDS_MeshElement* pE = aItE->next();
4637 aTypeE = pE->GetType();
4638 // Pattern must contain links only
4639 if ( aTypeE != SMDSAbs_Edge )
4640 return EXTR_PATH_NOT_EDGE;
4643 list<SMESH_MeshEditor_PathPoint> fullList;
4645 const TopoDS_Shape& aS = theTrack->GetSubShape();
4646 // Sub shape for the Pattern must be an Edge or Wire
4647 if( aS.ShapeType() == TopAbs_EDGE ) {
4648 aTrackEdge = TopoDS::Edge( aS );
4649 // the Edge must not be degenerated
4650 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4651 return EXTR_BAD_PATH_SHAPE;
4652 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4653 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4654 const SMDS_MeshNode* aN1 = aItN->next();
4655 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4656 const SMDS_MeshNode* aN2 = aItN->next();
4657 // starting node must be aN1 or aN2
4658 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4659 return EXTR_BAD_STARTING_NODE;
4660 aItN = pSubMeshDS->GetNodes();
4661 while ( aItN->more() ) {
4662 const SMDS_MeshNode* pNode = aItN->next();
4663 const SMDS_EdgePosition* pEPos =
4664 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4665 double aT = pEPos->GetUParameter();
4666 aPrms.push_back( aT );
4668 //Extrusion_Error err =
4669 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4671 else if( aS.ShapeType() == TopAbs_WIRE ) {
4672 list< SMESH_subMesh* > LSM;
4673 TopTools_SequenceOfShape Edges;
4674 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4675 while(itSM->more()) {
4676 SMESH_subMesh* SM = itSM->next();
4678 const TopoDS_Shape& aS = SM->GetSubShape();
4681 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4682 int startNid = theN1->GetID();
4683 TColStd_MapOfInteger UsedNums;
4684 int NbEdges = Edges.Length();
4686 for(; i<=NbEdges; i++) {
4688 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4689 for(; itLSM!=LSM.end(); itLSM++) {
4691 if(UsedNums.Contains(k)) continue;
4692 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4693 SMESH_subMesh* locTrack = *itLSM;
4694 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4695 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4696 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4697 const SMDS_MeshNode* aN1 = aItN->next();
4698 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4699 const SMDS_MeshNode* aN2 = aItN->next();
4700 // starting node must be aN1 or aN2
4701 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4702 // 2. Collect parameters on the track edge
4704 aItN = locMeshDS->GetNodes();
4705 while ( aItN->more() ) {
4706 const SMDS_MeshNode* pNode = aItN->next();
4707 const SMDS_EdgePosition* pEPos =
4708 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4709 double aT = pEPos->GetUParameter();
4710 aPrms.push_back( aT );
4712 list<SMESH_MeshEditor_PathPoint> LPP;
4713 //Extrusion_Error err =
4714 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4715 LLPPs.push_back(LPP);
4717 // update startN for search following egde
4718 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4719 else startNid = aN1->GetID();
4723 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4724 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4725 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4726 for(; itPP!=firstList.end(); itPP++) {
4727 fullList.push_back( *itPP );
4729 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4730 fullList.pop_back();
4732 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4733 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4734 itPP = currList.begin();
4735 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4736 gp_Dir D1 = PP1.Tangent();
4737 gp_Dir D2 = PP2.Tangent();
4738 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4739 (D1.Z()+D2.Z())/2 ) );
4740 PP1.SetTangent(Dnew);
4741 fullList.push_back(PP1);
4743 for(; itPP!=firstList.end(); itPP++) {
4744 fullList.push_back( *itPP );
4746 PP1 = fullList.back();
4747 fullList.pop_back();
4749 // if wire not closed
4750 fullList.push_back(PP1);
4754 return EXTR_BAD_PATH_SHAPE;
4757 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4758 theHasRefPoint, theRefPoint, theMakeGroups);
4762 //=======================================================================
4763 //function : ExtrusionAlongTrack
4765 //=======================================================================
4766 SMESH_MeshEditor::Extrusion_Error
4767 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4768 SMESH_Mesh* theTrack,
4769 const SMDS_MeshNode* theN1,
4770 const bool theHasAngles,
4771 list<double>& theAngles,
4772 const bool theLinearVariation,
4773 const bool theHasRefPoint,
4774 const gp_Pnt& theRefPoint,
4775 const bool theMakeGroups)
4777 myLastCreatedElems.Clear();
4778 myLastCreatedNodes.Clear();
4781 std::list<double> aPrms;
4782 TIDSortedElemSet::iterator itElem;
4785 TopoDS_Edge aTrackEdge;
4786 TopoDS_Vertex aV1, aV2;
4788 SMDS_ElemIteratorPtr aItE;
4789 SMDS_NodeIteratorPtr aItN;
4790 SMDSAbs_ElementType aTypeE;
4792 TNodeOfNodeListMap mapNewNodes;
4795 aNbE = theElements.size();
4798 return EXTR_NO_ELEMENTS;
4800 // 1.1 Track Pattern
4803 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4805 aItE = pMeshDS->elementsIterator();
4806 while ( aItE->more() ) {
4807 const SMDS_MeshElement* pE = aItE->next();
4808 aTypeE = pE->GetType();
4809 // Pattern must contain links only
4810 if ( aTypeE != SMDSAbs_Edge )
4811 return EXTR_PATH_NOT_EDGE;
4814 list<SMESH_MeshEditor_PathPoint> fullList;
4816 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4817 // Sub shape for the Pattern must be an Edge or Wire
4818 if( aS.ShapeType() == TopAbs_EDGE ) {
4819 aTrackEdge = TopoDS::Edge( aS );
4820 // the Edge must not be degenerated
4821 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4822 return EXTR_BAD_PATH_SHAPE;
4823 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4824 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4825 const SMDS_MeshNode* aN1 = aItN->next();
4826 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4827 const SMDS_MeshNode* aN2 = aItN->next();
4828 // starting node must be aN1 or aN2
4829 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4830 return EXTR_BAD_STARTING_NODE;
4831 aItN = pMeshDS->nodesIterator();
4832 while ( aItN->more() ) {
4833 const SMDS_MeshNode* pNode = aItN->next();
4834 if( pNode==aN1 || pNode==aN2 ) continue;
4835 const SMDS_EdgePosition* pEPos =
4836 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4837 double aT = pEPos->GetUParameter();
4838 aPrms.push_back( aT );
4840 //Extrusion_Error err =
4841 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4843 else if( aS.ShapeType() == TopAbs_WIRE ) {
4844 list< SMESH_subMesh* > LSM;
4845 TopTools_SequenceOfShape Edges;
4846 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4847 for(; eExp.More(); eExp.Next()) {
4848 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4849 if( BRep_Tool::Degenerated(E) ) continue;
4850 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4856 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4857 int startNid = theN1->GetID();
4858 TColStd_MapOfInteger UsedNums;
4859 int NbEdges = Edges.Length();
4861 for(; i<=NbEdges; i++) {
4863 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4864 for(; itLSM!=LSM.end(); itLSM++) {
4866 if(UsedNums.Contains(k)) continue;
4867 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4868 SMESH_subMesh* locTrack = *itLSM;
4869 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4870 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4871 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4872 const SMDS_MeshNode* aN1 = aItN->next();
4873 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4874 const SMDS_MeshNode* aN2 = aItN->next();
4875 // starting node must be aN1 or aN2
4876 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4877 // 2. Collect parameters on the track edge
4879 aItN = locMeshDS->GetNodes();
4880 while ( aItN->more() ) {
4881 const SMDS_MeshNode* pNode = aItN->next();
4882 const SMDS_EdgePosition* pEPos =
4883 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4884 double aT = pEPos->GetUParameter();
4885 aPrms.push_back( aT );
4887 list<SMESH_MeshEditor_PathPoint> LPP;
4888 //Extrusion_Error err =
4889 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4890 LLPPs.push_back(LPP);
4892 // update startN for search following egde
4893 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4894 else startNid = aN1->GetID();
4898 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4899 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4900 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4901 for(; itPP!=firstList.end(); itPP++) {
4902 fullList.push_back( *itPP );
4904 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4905 fullList.pop_back();
4907 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4908 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4909 itPP = currList.begin();
4910 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4911 gp_Dir D1 = PP1.Tangent();
4912 gp_Dir D2 = PP2.Tangent();
4913 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4914 (D1.Z()+D2.Z())/2 ) );
4915 PP1.SetTangent(Dnew);
4916 fullList.push_back(PP1);
4918 for(; itPP!=currList.end(); itPP++) {
4919 fullList.push_back( *itPP );
4921 PP1 = fullList.back();
4922 fullList.pop_back();
4924 // if wire not closed
4925 fullList.push_back(PP1);
4929 return EXTR_BAD_PATH_SHAPE;
4932 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4933 theHasRefPoint, theRefPoint, theMakeGroups);
4937 //=======================================================================
4938 //function : MakeEdgePathPoints
4939 //purpose : auxilary for ExtrusionAlongTrack
4940 //=======================================================================
4941 SMESH_MeshEditor::Extrusion_Error
4942 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4943 const TopoDS_Edge& aTrackEdge,
4945 list<SMESH_MeshEditor_PathPoint>& LPP)
4947 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4949 aTolVec2=aTolVec*aTolVec;
4951 TopoDS_Vertex aV1, aV2;
4952 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4953 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4954 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4955 // 2. Collect parameters on the track edge
4956 aPrms.push_front( aT1 );
4957 aPrms.push_back( aT2 );
4960 if( FirstIsStart ) {
4971 SMESH_MeshEditor_PathPoint aPP;
4972 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4973 std::list<double>::iterator aItD = aPrms.begin();
4974 for(; aItD != aPrms.end(); ++aItD) {
4978 aC3D->D1( aT, aP3D, aVec );
4979 aL2 = aVec.SquareMagnitude();
4980 if ( aL2 < aTolVec2 )
4981 return EXTR_CANT_GET_TANGENT;
4982 gp_Dir aTgt( aVec );
4984 aPP.SetTangent( aTgt );
4985 aPP.SetParameter( aT );
4992 //=======================================================================
4993 //function : MakeExtrElements
4994 //purpose : auxilary for ExtrusionAlongTrack
4995 //=======================================================================
4996 SMESH_MeshEditor::Extrusion_Error
4997 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
4998 list<SMESH_MeshEditor_PathPoint>& fullList,
4999 const bool theHasAngles,
5000 list<double>& theAngles,
5001 const bool theLinearVariation,
5002 const bool theHasRefPoint,
5003 const gp_Pnt& theRefPoint,
5004 const bool theMakeGroups)
5006 MESSAGE("MakeExtrElements");
5007 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5008 int aNbTP = fullList.size();
5009 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5011 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5012 LinearAngleVariation(aNbTP-1, theAngles);
5014 vector<double> aAngles( aNbTP );
5016 for(; j<aNbTP; ++j) {
5019 if ( theHasAngles ) {
5021 std::list<double>::iterator aItD = theAngles.begin();
5022 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5024 aAngles[j] = anAngle;
5027 // fill vector of path points with angles
5028 //aPPs.resize(fullList.size());
5030 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5031 for(; itPP!=fullList.end(); itPP++) {
5033 SMESH_MeshEditor_PathPoint PP = *itPP;
5034 PP.SetAngle(aAngles[j]);
5038 TNodeOfNodeListMap mapNewNodes;
5039 TElemOfVecOfNnlmiMap mapElemNewNodes;
5040 TElemOfElemListMap newElemsMap;
5041 TIDSortedElemSet::iterator itElem;
5044 SMDSAbs_ElementType aTypeE;
5045 // source elements for each generated one
5046 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5048 // 3. Center of rotation aV0
5049 gp_Pnt aV0 = theRefPoint;
5051 if ( !theHasRefPoint ) {
5053 aGC.SetCoord( 0.,0.,0. );
5055 itElem = theElements.begin();
5056 for ( ; itElem != theElements.end(); itElem++ ) {
5057 const SMDS_MeshElement* elem = *itElem;
5059 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5060 while ( itN->more() ) {
5061 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5066 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5067 list<const SMDS_MeshNode*> aLNx;
5068 mapNewNodes[node] = aLNx;
5070 gp_XYZ aXYZ( aX, aY, aZ );
5078 } // if (!theHasRefPoint) {
5079 mapNewNodes.clear();
5081 // 4. Processing the elements
5082 SMESHDS_Mesh* aMesh = GetMeshDS();
5084 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5085 // check element type
5086 const SMDS_MeshElement* elem = *itElem;
5087 aTypeE = elem->GetType();
5088 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5091 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5092 newNodesItVec.reserve( elem->NbNodes() );
5094 // loop on elem nodes
5096 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5097 while ( itN->more() )
5100 // check if a node has been already processed
5101 const SMDS_MeshNode* node =
5102 static_cast<const SMDS_MeshNode*>( itN->next() );
5103 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5104 if ( nIt == mapNewNodes.end() ) {
5105 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5106 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5109 aX = node->X(); aY = node->Y(); aZ = node->Z();
5111 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5112 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5113 gp_Ax1 anAx1, anAxT1T0;
5114 gp_Dir aDT1x, aDT0x, aDT1T0;
5119 aPN0.SetCoord(aX, aY, aZ);
5121 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5123 aDT0x= aPP0.Tangent();
5124 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5126 for ( j = 1; j < aNbTP; ++j ) {
5127 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5129 aDT1x = aPP1.Tangent();
5130 aAngle1x = aPP1.Angle();
5132 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5134 gp_Vec aV01x( aP0x, aP1x );
5135 aTrsf.SetTranslation( aV01x );
5138 aV1x = aV0x.Transformed( aTrsf );
5139 aPN1 = aPN0.Transformed( aTrsf );
5141 // rotation 1 [ T1,T0 ]
5142 aAngleT1T0=-aDT1x.Angle( aDT0x );
5143 if (fabs(aAngleT1T0) > aTolAng) {
5145 anAxT1T0.SetLocation( aV1x );
5146 anAxT1T0.SetDirection( aDT1T0 );
5147 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5149 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5153 if ( theHasAngles ) {
5154 anAx1.SetLocation( aV1x );
5155 anAx1.SetDirection( aDT1x );
5156 aTrsfRot.SetRotation( anAx1, aAngle1x );
5158 aPN1 = aPN1.Transformed( aTrsfRot );
5162 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5163 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5164 // create additional node
5165 double x = ( aPN1.X() + aPN0.X() )/2.;
5166 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5167 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5168 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5169 myLastCreatedNodes.Append(newNode);
5170 srcNodes.Append( node );
5171 listNewNodes.push_back( newNode );
5176 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5177 myLastCreatedNodes.Append(newNode);
5178 srcNodes.Append( node );
5179 listNewNodes.push_back( newNode );
5189 // if current elem is quadratic and current node is not medium
5190 // we have to check - may be it is needed to insert additional nodes
5191 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5192 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5193 if(listNewNodes.size()==aNbTP-1) {
5194 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5195 gp_XYZ P(node->X(), node->Y(), node->Z());
5196 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5198 for(i=0; i<aNbTP-1; i++) {
5199 const SMDS_MeshNode* N = *it;
5200 double x = ( N->X() + P.X() )/2.;
5201 double y = ( N->Y() + P.Y() )/2.;
5202 double z = ( N->Z() + P.Z() )/2.;
5203 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5204 srcNodes.Append( node );
5205 myLastCreatedNodes.Append(newN);
5208 P = gp_XYZ(N->X(),N->Y(),N->Z());
5210 listNewNodes.clear();
5211 for(i=0; i<2*(aNbTP-1); i++) {
5212 listNewNodes.push_back(aNodes[i]);
5218 newNodesItVec.push_back( nIt );
5220 // make new elements
5221 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5222 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5223 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5226 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5228 if ( theMakeGroups )
5229 generateGroups( srcNodes, srcElems, "extruded");
5235 //=======================================================================
5236 //function : LinearAngleVariation
5237 //purpose : auxilary for ExtrusionAlongTrack
5238 //=======================================================================
5239 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5240 list<double>& Angles)
5242 int nbAngles = Angles.size();
5243 if( nbSteps > nbAngles ) {
5244 vector<double> theAngles(nbAngles);
5245 list<double>::iterator it = Angles.begin();
5247 for(; it!=Angles.end(); it++) {
5249 theAngles[i] = (*it);
5252 double rAn2St = double( nbAngles ) / double( nbSteps );
5253 double angPrev = 0, angle;
5254 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5255 double angCur = rAn2St * ( iSt+1 );
5256 double angCurFloor = floor( angCur );
5257 double angPrevFloor = floor( angPrev );
5258 if ( angPrevFloor == angCurFloor )
5259 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5261 int iP = int( angPrevFloor );
5262 double angPrevCeil = ceil(angPrev);
5263 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5265 int iC = int( angCurFloor );
5266 if ( iC < nbAngles )
5267 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5269 iP = int( angPrevCeil );
5271 angle += theAngles[ iC ];
5273 res.push_back(angle);
5278 for(; it!=res.end(); it++)
5279 Angles.push_back( *it );
5284 //================================================================================
5286 * \brief Move or copy theElements applying theTrsf to their nodes
5287 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5288 * \param theTrsf - transformation to apply
5289 * \param theCopy - if true, create translated copies of theElems
5290 * \param theMakeGroups - if true and theCopy, create translated groups
5291 * \param theTargetMesh - mesh to copy translated elements into
5292 * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5294 //================================================================================
5296 SMESH_MeshEditor::PGroupIDs
5297 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5298 const gp_Trsf& theTrsf,
5300 const bool theMakeGroups,
5301 SMESH_Mesh* theTargetMesh)
5303 myLastCreatedElems.Clear();
5304 myLastCreatedNodes.Clear();
5306 bool needReverse = false;
5307 string groupPostfix;
5308 switch ( theTrsf.Form() ) {
5310 MESSAGE("gp_PntMirror");
5312 groupPostfix = "mirrored";
5315 MESSAGE("gp_Ax1Mirror");
5316 groupPostfix = "mirrored";
5319 MESSAGE("gp_Ax2Mirror");
5321 groupPostfix = "mirrored";
5324 MESSAGE("gp_Rotation");
5325 groupPostfix = "rotated";
5327 case gp_Translation:
5328 MESSAGE("gp_Translation");
5329 groupPostfix = "translated";
5332 MESSAGE("gp_Scale");
5333 groupPostfix = "scaled";
5335 case gp_CompoundTrsf: // different scale by axis
5336 MESSAGE("gp_CompoundTrsf");
5337 groupPostfix = "scaled";
5341 needReverse = false;
5342 groupPostfix = "transformed";
5345 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5346 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5347 SMESHDS_Mesh* aMesh = GetMeshDS();
5350 // map old node to new one
5351 TNodeNodeMap nodeMap;
5353 // elements sharing moved nodes; those of them which have all
5354 // nodes mirrored but are not in theElems are to be reversed
5355 TIDSortedElemSet inverseElemSet;
5357 // source elements for each generated one
5358 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5360 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5361 TIDSortedElemSet orphanNode;
5363 if ( theElems.empty() ) // transform the whole mesh
5366 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5367 while ( eIt->more() ) theElems.insert( eIt->next() );
5369 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5370 while ( nIt->more() )
5372 const SMDS_MeshNode* node = nIt->next();
5373 if ( node->NbInverseElements() == 0)
5374 orphanNode.insert( node );
5378 // loop on elements to transform nodes : first orphan nodes then elems
5379 TIDSortedElemSet::iterator itElem;
5380 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5381 for (int i=0; i<2; i++)
5382 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5383 const SMDS_MeshElement* elem = *itElem;
5387 // loop on elem nodes
5388 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5389 while ( itN->more() ) {
5391 const SMDS_MeshNode* node = cast2Node( itN->next() );
5392 // check if a node has been already transformed
5393 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5394 nodeMap.insert( make_pair ( node, node ));
5395 if ( !n2n_isnew.second )
5399 coord[0] = node->X();
5400 coord[1] = node->Y();
5401 coord[2] = node->Z();
5402 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5403 if ( theTargetMesh ) {
5404 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5405 n2n_isnew.first->second = newNode;
5406 myLastCreatedNodes.Append(newNode);
5407 srcNodes.Append( node );
5409 else if ( theCopy ) {
5410 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5411 n2n_isnew.first->second = newNode;
5412 myLastCreatedNodes.Append(newNode);
5413 srcNodes.Append( node );
5416 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5417 // node position on shape becomes invalid
5418 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5419 ( SMDS_SpacePosition::originSpacePosition() );
5422 // keep inverse elements
5423 if ( !theCopy && !theTargetMesh && needReverse ) {
5424 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5425 while ( invElemIt->more() ) {
5426 const SMDS_MeshElement* iel = invElemIt->next();
5427 inverseElemSet.insert( iel );
5433 // either create new elements or reverse mirrored ones
5434 if ( !theCopy && !needReverse && !theTargetMesh )
5437 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5438 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5439 theElems.insert( *invElemIt );
5441 // replicate or reverse elements
5442 // TODO revoir ordre reverse vtk
5444 REV_TETRA = 0, // = nbNodes - 4
5445 REV_PYRAMID = 1, // = nbNodes - 4
5446 REV_PENTA = 2, // = nbNodes - 4
5448 REV_HEXA = 4, // = nbNodes - 4
5452 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5453 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5454 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5455 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5456 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5457 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5460 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5462 const SMDS_MeshElement* elem = *itElem;
5463 if ( !elem || elem->GetType() == SMDSAbs_Node )
5466 int nbNodes = elem->NbNodes();
5467 int elemType = elem->GetType();
5469 if (elem->IsPoly()) {
5470 // Polygon or Polyhedral Volume
5471 switch ( elemType ) {
5474 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5476 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5477 while (itN->more()) {
5478 const SMDS_MeshNode* node =
5479 static_cast<const SMDS_MeshNode*>(itN->next());
5480 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5481 if (nodeMapIt == nodeMap.end())
5482 break; // not all nodes transformed
5484 // reverse mirrored faces and volumes
5485 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5487 poly_nodes[iNode] = (*nodeMapIt).second;
5491 if ( iNode != nbNodes )
5492 continue; // not all nodes transformed
5494 if ( theTargetMesh ) {
5495 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5496 srcElems.Append( elem );
5498 else if ( theCopy ) {
5499 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5500 srcElems.Append( elem );
5503 aMesh->ChangePolygonNodes(elem, poly_nodes);
5507 case SMDSAbs_Volume:
5509 // ATTENTION: Reversing is not yet done!!!
5510 const SMDS_VtkVolume* aPolyedre =
5511 dynamic_cast<const SMDS_VtkVolume*>( elem );
5513 MESSAGE("Warning: bad volumic element");
5517 vector<const SMDS_MeshNode*> poly_nodes;
5518 vector<int> quantities;
5520 bool allTransformed = true;
5521 int nbFaces = aPolyedre->NbFaces();
5522 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5523 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5524 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5525 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5526 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5527 if (nodeMapIt == nodeMap.end()) {
5528 allTransformed = false; // not all nodes transformed
5530 poly_nodes.push_back((*nodeMapIt).second);
5533 quantities.push_back(nbFaceNodes);
5535 if ( !allTransformed )
5536 continue; // not all nodes transformed
5538 if ( theTargetMesh ) {
5539 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5540 srcElems.Append( elem );
5542 else if ( theCopy ) {
5543 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5544 srcElems.Append( elem );
5547 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5557 int* i = index[ FORWARD ];
5558 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5559 if ( elemType == SMDSAbs_Face )
5560 i = index[ REV_FACE ];
5562 i = index[ nbNodes - 4 ];
5564 if(elem->IsQuadratic()) {
5565 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5568 if(nbNodes==3) { // quadratic edge
5569 static int anIds[] = {1,0,2};
5572 else if(nbNodes==6) { // quadratic triangle
5573 static int anIds[] = {0,2,1,5,4,3};
5576 else if(nbNodes==8) { // quadratic quadrangle
5577 static int anIds[] = {0,3,2,1,7,6,5,4};
5580 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5581 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5584 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5585 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5588 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5589 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5592 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5593 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5599 // find transformed nodes
5600 vector<const SMDS_MeshNode*> nodes(nbNodes);
5602 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5603 while ( itN->more() ) {
5604 const SMDS_MeshNode* node =
5605 static_cast<const SMDS_MeshNode*>( itN->next() );
5606 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5607 if ( nodeMapIt == nodeMap.end() )
5608 break; // not all nodes transformed
5609 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5611 if ( iNode != nbNodes )
5612 continue; // not all nodes transformed
5614 if ( theTargetMesh ) {
5615 if ( SMDS_MeshElement* copy =
5616 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5617 myLastCreatedElems.Append( copy );
5618 srcElems.Append( elem );
5621 else if ( theCopy ) {
5622 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5623 srcElems.Append( elem );
5626 // reverse element as it was reversed by transformation
5628 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5632 PGroupIDs newGroupIDs;
5634 if ( ( theMakeGroups && theCopy ) ||
5635 ( theMakeGroups && theTargetMesh ) )
5636 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5642 ////=======================================================================
5643 ////function : Scale
5645 ////=======================================================================
5647 //SMESH_MeshEditor::PGroupIDs
5648 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5649 // const gp_Pnt& thePoint,
5650 // const std::list<double>& theScaleFact,
5651 // const bool theCopy,
5652 // const bool theMakeGroups,
5653 // SMESH_Mesh* theTargetMesh)
5655 // MESSAGE("Scale");
5656 // myLastCreatedElems.Clear();
5657 // myLastCreatedNodes.Clear();
5659 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5660 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5661 // SMESHDS_Mesh* aMesh = GetMeshDS();
5663 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5664 // std::list<double>::const_iterator itS = theScaleFact.begin();
5666 // if(theScaleFact.size()==1) {
5670 // if(theScaleFact.size()==2) {
5675 // if(theScaleFact.size()>2) {
5682 // // map old node to new one
5683 // TNodeNodeMap nodeMap;
5685 // // elements sharing moved nodes; those of them which have all
5686 // // nodes mirrored but are not in theElems are to be reversed
5687 // TIDSortedElemSet inverseElemSet;
5689 // // source elements for each generated one
5690 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5692 // // loop on theElems
5693 // TIDSortedElemSet::iterator itElem;
5694 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5695 // const SMDS_MeshElement* elem = *itElem;
5699 // // loop on elem nodes
5700 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5701 // while ( itN->more() ) {
5703 // // check if a node has been already transformed
5704 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5705 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5706 // nodeMap.insert( make_pair ( node, node ));
5707 // if ( !n2n_isnew.second )
5710 // //double coord[3];
5711 // //coord[0] = node->X();
5712 // //coord[1] = node->Y();
5713 // //coord[2] = node->Z();
5714 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5715 // double dx = (node->X() - thePoint.X()) * scaleX;
5716 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5717 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5718 // if ( theTargetMesh ) {
5719 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5720 // const SMDS_MeshNode * newNode =
5721 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5722 // n2n_isnew.first->second = newNode;
5723 // myLastCreatedNodes.Append(newNode);
5724 // srcNodes.Append( node );
5726 // else if ( theCopy ) {
5727 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5728 // const SMDS_MeshNode * newNode =
5729 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5730 // n2n_isnew.first->second = newNode;
5731 // myLastCreatedNodes.Append(newNode);
5732 // srcNodes.Append( node );
5735 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5736 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5737 // // node position on shape becomes invalid
5738 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5739 // ( SMDS_SpacePosition::originSpacePosition() );
5742 // // keep inverse elements
5743 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5744 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5745 // // while ( invElemIt->more() ) {
5746 // // const SMDS_MeshElement* iel = invElemIt->next();
5747 // // inverseElemSet.insert( iel );
5753 // // either create new elements or reverse mirrored ones
5754 // //if ( !theCopy && !needReverse && !theTargetMesh )
5755 // if ( !theCopy && !theTargetMesh )
5756 // return PGroupIDs();
5758 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5759 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5760 // theElems.insert( *invElemIt );
5762 // // replicate or reverse elements
5765 // REV_TETRA = 0, // = nbNodes - 4
5766 // REV_PYRAMID = 1, // = nbNodes - 4
5767 // REV_PENTA = 2, // = nbNodes - 4
5769 // REV_HEXA = 4, // = nbNodes - 4
5772 // int index[][8] = {
5773 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5774 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5775 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5776 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5777 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5778 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5781 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5783 // const SMDS_MeshElement* elem = *itElem;
5784 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5787 // int nbNodes = elem->NbNodes();
5788 // int elemType = elem->GetType();
5790 // if (elem->IsPoly()) {
5791 // // Polygon or Polyhedral Volume
5792 // switch ( elemType ) {
5793 // case SMDSAbs_Face:
5795 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5797 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5798 // while (itN->more()) {
5799 // const SMDS_MeshNode* node =
5800 // static_cast<const SMDS_MeshNode*>(itN->next());
5801 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5802 // if (nodeMapIt == nodeMap.end())
5803 // break; // not all nodes transformed
5804 // //if (needReverse) {
5805 // // // reverse mirrored faces and volumes
5806 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5808 // poly_nodes[iNode] = (*nodeMapIt).second;
5812 // if ( iNode != nbNodes )
5813 // continue; // not all nodes transformed
5815 // if ( theTargetMesh ) {
5816 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5817 // srcElems.Append( elem );
5819 // else if ( theCopy ) {
5820 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5821 // srcElems.Append( elem );
5824 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5828 // case SMDSAbs_Volume:
5830 // // ATTENTION: Reversing is not yet done!!!
5831 // const SMDS_VtkVolume* aPolyedre =
5832 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5833 // if (!aPolyedre) {
5834 // MESSAGE("Warning: bad volumic element");
5838 // vector<const SMDS_MeshNode*> poly_nodes;
5839 // vector<int> quantities;
5841 // bool allTransformed = true;
5842 // int nbFaces = aPolyedre->NbFaces();
5843 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5844 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5845 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5846 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5847 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5848 // if (nodeMapIt == nodeMap.end()) {
5849 // allTransformed = false; // not all nodes transformed
5851 // poly_nodes.push_back((*nodeMapIt).second);
5854 // quantities.push_back(nbFaceNodes);
5856 // if ( !allTransformed )
5857 // continue; // not all nodes transformed
5859 // if ( theTargetMesh ) {
5860 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5861 // srcElems.Append( elem );
5863 // else if ( theCopy ) {
5864 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5865 // srcElems.Append( elem );
5868 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5877 // // Regular elements
5878 // int* i = index[ FORWARD ];
5879 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5880 // // if ( elemType == SMDSAbs_Face )
5881 // // i = index[ REV_FACE ];
5883 // // i = index[ nbNodes - 4 ];
5885 // if(elem->IsQuadratic()) {
5886 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5888 // //if(needReverse) {
5889 // // if(nbNodes==3) { // quadratic edge
5890 // // static int anIds[] = {1,0,2};
5893 // // else if(nbNodes==6) { // quadratic triangle
5894 // // static int anIds[] = {0,2,1,5,4,3};
5897 // // else if(nbNodes==8) { // quadratic quadrangle
5898 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5901 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5902 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5905 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5906 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5909 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5910 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5913 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5914 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5920 // // find transformed nodes
5921 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5923 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5924 // while ( itN->more() ) {
5925 // const SMDS_MeshNode* node =
5926 // static_cast<const SMDS_MeshNode*>( itN->next() );
5927 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5928 // if ( nodeMapIt == nodeMap.end() )
5929 // break; // not all nodes transformed
5930 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5932 // if ( iNode != nbNodes )
5933 // continue; // not all nodes transformed
5935 // if ( theTargetMesh ) {
5936 // if ( SMDS_MeshElement* copy =
5937 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5938 // myLastCreatedElems.Append( copy );
5939 // srcElems.Append( elem );
5942 // else if ( theCopy ) {
5943 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5944 // myLastCreatedElems.Append( copy );
5945 // srcElems.Append( elem );
5949 // // reverse element as it was reversed by transformation
5950 // if ( nbNodes > 2 )
5951 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5955 // PGroupIDs newGroupIDs;
5957 // if ( theMakeGroups && theCopy ||
5958 // theMakeGroups && theTargetMesh ) {
5959 // string groupPostfix = "scaled";
5960 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5963 // return newGroupIDs;
5967 //=======================================================================
5969 * \brief Create groups of elements made during transformation
5970 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5971 * \param elemGens - elements making corresponding myLastCreatedElems
5972 * \param postfix - to append to names of new groups
5974 //=======================================================================
5976 SMESH_MeshEditor::PGroupIDs
5977 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5978 const SMESH_SequenceOfElemPtr& elemGens,
5979 const std::string& postfix,
5980 SMESH_Mesh* targetMesh)
5982 PGroupIDs newGroupIDs( new list<int> );
5983 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
5985 // Sort existing groups by types and collect their names
5987 // to store an old group and a generated new one
5988 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
5989 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
5991 set< string > groupNames;
5993 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
5994 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
5995 while ( groupIt->more() ) {
5996 SMESH_Group * group = groupIt->next();
5997 if ( !group ) continue;
5998 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
5999 if ( !groupDS || groupDS->IsEmpty() ) continue;
6000 groupNames.insert( group->GetName() );
6001 groupDS->SetStoreName( group->GetName() );
6002 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6007 // loop on nodes and elements
6008 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6010 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6011 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6012 if ( gens.Length() != elems.Length() )
6013 throw SALOME_Exception(LOCALIZED("invalid args"));
6015 // loop on created elements
6016 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6018 const SMDS_MeshElement* sourceElem = gens( iElem );
6019 if ( !sourceElem ) {
6020 MESSAGE("generateGroups(): NULL source element");
6023 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6024 if ( groupsOldNew.empty() ) {
6025 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6026 ++iElem; // skip all elements made by sourceElem
6029 // collect all elements made by sourceElem
6030 list< const SMDS_MeshElement* > resultElems;
6031 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6032 if ( resElem != sourceElem )
6033 resultElems.push_back( resElem );
6034 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6035 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6036 if ( resElem != sourceElem )
6037 resultElems.push_back( resElem );
6038 // do not generate element groups from node ones
6039 if ( sourceElem->GetType() == SMDSAbs_Node &&
6040 elems( iElem )->GetType() != SMDSAbs_Node )
6043 // add resultElems to groups made by ones the sourceElem belongs to
6044 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6045 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6047 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6048 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6050 SMDS_MeshGroup* & newGroup = gOldNew->second;
6051 if ( !newGroup )// create a new group
6054 string name = oldGroup->GetStoreName();
6055 if ( !targetMesh ) {
6059 while ( !groupNames.insert( name ).second ) // name exists
6065 TCollection_AsciiString nbStr(nb+1);
6066 name.resize( name.rfind('_')+1 );
6067 name += nbStr.ToCString();
6074 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6076 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6077 newGroup = & groupDS->SMDSGroup();
6078 newGroupIDs->push_back( id );
6081 // fill in a new group
6082 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6083 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6084 newGroup->Add( *resElemIt );
6087 } // loop on created elements
6088 }// loop on nodes and elements
6093 //================================================================================
6095 * \brief Return list of group of nodes close to each other within theTolerance
6096 * Search among theNodes or in the whole mesh if theNodes is empty using
6097 * an Octree algorithm
6099 //================================================================================
6101 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6102 const double theTolerance,
6103 TListOfListOfNodes & theGroupsOfNodes)
6105 myLastCreatedElems.Clear();
6106 myLastCreatedNodes.Clear();
6108 if ( theNodes.empty() )
6109 { // get all nodes in the mesh
6110 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6111 while ( nIt->more() )
6112 theNodes.insert( theNodes.end(),nIt->next());
6115 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6119 //=======================================================================
6121 * \brief Implementation of search for the node closest to point
6123 //=======================================================================
6125 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6127 //---------------------------------------------------------------------
6129 * \brief Constructor
6131 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6133 myMesh = ( SMESHDS_Mesh* ) theMesh;
6135 TIDSortedNodeSet nodes;
6137 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6138 while ( nIt->more() )
6139 nodes.insert( nodes.end(), nIt->next() );
6141 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6143 // get max size of a leaf box
6144 SMESH_OctreeNode* tree = myOctreeNode;
6145 while ( !tree->isLeaf() )
6147 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6151 myHalfLeafSize = tree->maxSize() / 2.;
6154 //---------------------------------------------------------------------
6156 * \brief Move node and update myOctreeNode accordingly
6158 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6160 myOctreeNode->UpdateByMoveNode( node, toPnt );
6161 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6164 //---------------------------------------------------------------------
6166 * \brief Do it's job
6168 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6170 map<double, const SMDS_MeshNode*> dist2Nodes;
6171 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6172 if ( !dist2Nodes.empty() )
6173 return dist2Nodes.begin()->second;
6174 list<const SMDS_MeshNode*> nodes;
6175 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6177 double minSqDist = DBL_MAX;
6178 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6180 // sort leafs by their distance from thePnt
6181 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6182 TDistTreeMap treeMap;
6183 list< SMESH_OctreeNode* > treeList;
6184 list< SMESH_OctreeNode* >::iterator trIt;
6185 treeList.push_back( myOctreeNode );
6187 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6188 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6189 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6191 SMESH_OctreeNode* tree = *trIt;
6192 if ( !tree->isLeaf() ) // put children to the queue
6194 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6195 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6196 while ( cIt->more() )
6197 treeList.push_back( cIt->next() );
6199 else if ( tree->NbNodes() ) // put a tree to the treeMap
6201 const Bnd_B3d& box = tree->getBox();
6202 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6203 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6204 if ( !it_in.second ) // not unique distance to box center
6205 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6208 // find distance after which there is no sense to check tree's
6209 double sqLimit = DBL_MAX;
6210 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6211 if ( treeMap.size() > 5 ) {
6212 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6213 const Bnd_B3d& box = closestTree->getBox();
6214 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6215 sqLimit = limit * limit;
6217 // get all nodes from trees
6218 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6219 if ( sqDist_tree->first > sqLimit )
6221 SMESH_OctreeNode* tree = sqDist_tree->second;
6222 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6225 // find closest among nodes
6226 minSqDist = DBL_MAX;
6227 const SMDS_MeshNode* closestNode = 0;
6228 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6229 for ( ; nIt != nodes.end(); ++nIt ) {
6230 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6231 if ( minSqDist > sqDist ) {
6239 //---------------------------------------------------------------------
6243 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6245 //---------------------------------------------------------------------
6247 * \brief Return the node tree
6249 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6252 SMESH_OctreeNode* myOctreeNode;
6253 SMESHDS_Mesh* myMesh;
6254 double myHalfLeafSize; // max size of a leaf box
6257 //=======================================================================
6259 * \brief Return SMESH_NodeSearcher
6261 //=======================================================================
6263 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6265 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6268 // ========================================================================
6269 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6271 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6272 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6273 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6275 //=======================================================================
6277 * \brief Octal tree of bounding boxes of elements
6279 //=======================================================================
6281 class ElementBndBoxTree : public SMESH_Octree
6285 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6286 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6287 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6288 ~ElementBndBoxTree();
6291 ElementBndBoxTree() {}
6292 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6293 void buildChildrenData();
6294 Bnd_B3d* buildRootBox();
6296 //!< Bounding box of element
6297 struct ElementBox : public Bnd_B3d
6299 const SMDS_MeshElement* _element;
6300 int _refCount; // an ElementBox can be included in several tree branches
6301 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6303 vector< ElementBox* > _elements;
6306 //================================================================================
6308 * \brief ElementBndBoxTree creation
6310 //================================================================================
6312 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6313 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6315 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6316 _elements.reserve( nbElems );
6318 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6319 while ( elemIt->more() )
6320 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6322 if ( _elements.size() > MaxNbElemsInLeaf )
6328 //================================================================================
6332 //================================================================================
6334 ElementBndBoxTree::~ElementBndBoxTree()
6336 for ( int i = 0; i < _elements.size(); ++i )
6337 if ( --_elements[i]->_refCount <= 0 )
6338 delete _elements[i];
6341 //================================================================================
6343 * \brief Return the maximal box
6345 //================================================================================
6347 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6349 Bnd_B3d* box = new Bnd_B3d;
6350 for ( int i = 0; i < _elements.size(); ++i )
6351 box->Add( *_elements[i] );
6355 //================================================================================
6357 * \brief Redistrubute element boxes among children
6359 //================================================================================
6361 void ElementBndBoxTree::buildChildrenData()
6363 for ( int i = 0; i < _elements.size(); ++i )
6365 for (int j = 0; j < 8; j++)
6367 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6369 _elements[i]->_refCount++;
6370 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6373 _elements[i]->_refCount--;
6377 for (int j = 0; j < 8; j++)
6379 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6380 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6381 child->myIsLeaf = true;
6383 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6384 child->_elements.resize( child->_elements.size() ); // compact
6388 //================================================================================
6390 * \brief Return elements which can include the point
6392 //================================================================================
6394 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6395 TIDSortedElemSet& foundElems)
6397 if ( level() && getBox().IsOut( point.XYZ() ))
6402 for ( int i = 0; i < _elements.size(); ++i )
6403 if ( !_elements[i]->IsOut( point.XYZ() ))
6404 foundElems.insert( _elements[i]->_element );
6408 for (int i = 0; i < 8; i++)
6409 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6413 //================================================================================
6415 * \brief Return elements which can be intersected by the line
6417 //================================================================================
6419 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6420 TIDSortedElemSet& foundElems)
6422 if ( level() && getBox().IsOut( line ))
6427 for ( int i = 0; i < _elements.size(); ++i )
6428 if ( !_elements[i]->IsOut( line ))
6429 foundElems.insert( _elements[i]->_element );
6433 for (int i = 0; i < 8; i++)
6434 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6438 //================================================================================
6440 * \brief Construct the element box
6442 //================================================================================
6444 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6448 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6449 while ( nIt->more() )
6450 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6451 Enlarge( tolerance );
6456 //=======================================================================
6458 * \brief Implementation of search for the elements by point and
6459 * of classification of point in 2D mesh
6461 //=======================================================================
6463 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6465 SMESHDS_Mesh* _mesh;
6466 SMDS_ElemIteratorPtr _meshPartIt;
6467 ElementBndBoxTree* _ebbTree;
6468 SMESH_NodeSearcherImpl* _nodeSearcher;
6469 SMDSAbs_ElementType _elementType;
6471 bool _outerFacesFound;
6472 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6474 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6475 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6476 ~SMESH_ElementSearcherImpl()
6478 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6479 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6481 virtual int FindElementsByPoint(const gp_Pnt& point,
6482 SMDSAbs_ElementType type,
6483 vector< const SMDS_MeshElement* >& foundElements);
6484 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6486 void GetElementsNearLine( const gp_Ax1& line,
6487 SMDSAbs_ElementType type,
6488 vector< const SMDS_MeshElement* >& foundElems);
6489 double getTolerance();
6490 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6491 const double tolerance, double & param);
6492 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6493 bool isOuterBoundary(const SMDS_MeshElement* face) const
6495 return _outerFaces.empty() || _outerFaces.count(face);
6497 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6499 const SMDS_MeshElement* _face;
6501 bool _coincides; //!< the line lays in face plane
6502 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6503 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6505 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6508 TIDSortedElemSet _faces;
6509 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6510 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6514 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6516 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6517 << ", _coincides="<<i._coincides << ")";
6520 //=======================================================================
6522 * \brief define tolerance for search
6524 //=======================================================================
6526 double SMESH_ElementSearcherImpl::getTolerance()
6528 if ( _tolerance < 0 )
6530 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6533 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6535 double boxSize = _nodeSearcher->getTree()->maxSize();
6536 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6538 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6540 double boxSize = _ebbTree->maxSize();
6541 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6543 if ( _tolerance == 0 )
6545 // define tolerance by size of a most complex element
6546 int complexType = SMDSAbs_Volume;
6547 while ( complexType > SMDSAbs_All &&
6548 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6550 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6552 if ( complexType == int( SMDSAbs_Node ))
6554 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6556 if ( meshInfo.NbNodes() > 2 )
6557 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6561 SMDS_ElemIteratorPtr elemIt =
6562 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6563 const SMDS_MeshElement* elem = elemIt->next();
6564 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6565 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6567 while ( nodeIt->more() )
6569 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6570 elemSize = max( dist, elemSize );
6573 _tolerance = 1e-4 * elemSize;
6579 //================================================================================
6581 * \brief Find intersection of the line and an edge of face and return parameter on line
6583 //================================================================================
6585 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6586 const SMDS_MeshElement* face,
6593 GeomAPI_ExtremaCurveCurve anExtCC;
6594 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6596 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6597 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6599 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6600 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6601 anExtCC.Init( lineCurve, edge);
6602 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6604 Quantity_Parameter pl, pe;
6605 anExtCC.LowerDistanceParameters( pl, pe );
6607 if ( ++nbInts == 2 )
6611 if ( nbInts > 0 ) param /= nbInts;
6614 //================================================================================
6616 * \brief Find all faces belonging to the outer boundary of mesh
6618 //================================================================================
6620 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6622 if ( _outerFacesFound ) return;
6624 // Collect all outer faces by passing from one outer face to another via their links
6625 // and BTW find out if there are internal faces at all.
6627 // checked links and links where outer boundary meets internal one
6628 set< SMESH_TLink > visitedLinks, seamLinks;
6630 // links to treat with already visited faces sharing them
6631 list < TFaceLink > startLinks;
6633 // load startLinks with the first outerFace
6634 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6635 _outerFaces.insert( outerFace );
6637 TIDSortedElemSet emptySet;
6638 while ( !startLinks.empty() )
6640 const SMESH_TLink& link = startLinks.front()._link;
6641 TIDSortedElemSet& faces = startLinks.front()._faces;
6643 outerFace = *faces.begin();
6644 // find other faces sharing the link
6645 const SMDS_MeshElement* f;
6646 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6649 // select another outer face among the found
6650 const SMDS_MeshElement* outerFace2 = 0;
6651 if ( faces.size() == 2 )
6653 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6655 else if ( faces.size() > 2 )
6657 seamLinks.insert( link );
6659 // link direction within the outerFace
6660 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6661 SMESH_TNodeXYZ( link.node2()));
6662 int i1 = outerFace->GetNodeIndex( link.node1() );
6663 int i2 = outerFace->GetNodeIndex( link.node2() );
6664 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6665 if ( rev ) n1n2.Reverse();
6667 gp_XYZ ofNorm, fNorm;
6668 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6670 // direction from the link inside outerFace
6671 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6672 // sort all other faces by angle with the dirInOF
6673 map< double, const SMDS_MeshElement* > angle2Face;
6674 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6675 for ( ; face != faces.end(); ++face )
6677 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6679 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6680 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6681 if ( angle < 0 ) angle += 2*PI;
6682 angle2Face.insert( make_pair( angle, *face ));
6684 if ( !angle2Face.empty() )
6685 outerFace2 = angle2Face.begin()->second;
6688 // store the found outer face and add its links to continue seaching from
6691 _outerFaces.insert( outerFace );
6692 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6693 for ( int i = 0; i < nbNodes; ++i )
6695 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6696 if ( visitedLinks.insert( link2 ).second )
6697 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6700 startLinks.pop_front();
6702 _outerFacesFound = true;
6704 if ( !seamLinks.empty() )
6706 // There are internal boundaries touching the outher one,
6707 // find all faces of internal boundaries in order to find
6708 // faces of boundaries of holes, if any.
6713 _outerFaces.clear();
6717 //=======================================================================
6719 * \brief Find elements of given type where the given point is IN or ON.
6720 * Returns nb of found elements and elements them-selves.
6722 * 'ALL' type means elements of any type excluding nodes and 0D elements
6724 //=======================================================================
6726 int SMESH_ElementSearcherImpl::
6727 FindElementsByPoint(const gp_Pnt& point,
6728 SMDSAbs_ElementType type,
6729 vector< const SMDS_MeshElement* >& foundElements)
6731 foundElements.clear();
6733 double tolerance = getTolerance();
6735 // =================================================================================
6736 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6738 if ( !_nodeSearcher )
6739 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6741 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6742 if ( !closeNode ) return foundElements.size();
6744 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6745 return foundElements.size(); // to far from any node
6747 if ( type == SMDSAbs_Node )
6749 foundElements.push_back( closeNode );
6753 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6754 while ( elemIt->more() )
6755 foundElements.push_back( elemIt->next() );
6758 // =================================================================================
6759 else // elements more complex than 0D
6761 if ( !_ebbTree || _elementType != type )
6763 if ( _ebbTree ) delete _ebbTree;
6764 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6766 TIDSortedElemSet suspectElems;
6767 _ebbTree->getElementsNearPoint( point, suspectElems );
6768 TIDSortedElemSet::iterator elem = suspectElems.begin();
6769 for ( ; elem != suspectElems.end(); ++elem )
6770 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6771 foundElements.push_back( *elem );
6773 return foundElements.size();
6776 //================================================================================
6778 * \brief Classify the given point in the closed 2D mesh
6780 //================================================================================
6782 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6784 double tolerance = getTolerance();
6785 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6787 if ( _ebbTree ) delete _ebbTree;
6788 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6790 // Algo: analyse transition of a line starting at the point through mesh boundary;
6791 // try three lines parallel to axis of the coordinate system and perform rough
6792 // analysis. If solution is not clear perform thorough analysis.
6794 const int nbAxes = 3;
6795 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6796 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6797 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6798 multimap< int, int > nbInt2Axis; // to find the simplest case
6799 for ( int axis = 0; axis < nbAxes; ++axis )
6801 gp_Ax1 lineAxis( point, axisDir[axis]);
6802 gp_Lin line ( lineAxis );
6804 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6805 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6807 // Intersect faces with the line
6809 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6810 TIDSortedElemSet::iterator face = suspectFaces.begin();
6811 for ( ; face != suspectFaces.end(); ++face )
6815 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6816 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6818 // perform intersection
6819 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6820 if ( !intersection.IsDone() )
6822 if ( intersection.IsInQuadric() )
6824 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6826 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6828 gp_Pnt intersectionPoint = intersection.Point(1);
6829 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6830 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6833 // Analyse intersections roughly
6835 int nbInter = u2inters.size();
6839 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6840 if ( nbInter == 1 ) // not closed mesh
6841 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6843 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6846 if ( (f<0) == (l<0) )
6849 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6850 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6851 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6854 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6856 if ( _outerFacesFound ) break; // pass to thorough analysis
6858 } // three attempts - loop on CS axes
6860 // Analyse intersections thoroughly.
6861 // We make two loops maximum, on the first one we only exclude touching intersections,
6862 // on the second, if situation is still unclear, we gather and use information on
6863 // position of faces (internal or outer). If faces position is already gathered,
6864 // we make the second loop right away.
6866 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6868 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6869 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6871 int axis = nb_axis->second;
6872 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6874 gp_Ax1 lineAxis( point, axisDir[axis]);
6875 gp_Lin line ( lineAxis );
6877 // add tangent intersections to u2inters
6879 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6880 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6881 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6882 u2inters.insert(make_pair( param, *tgtInt ));
6883 tangentInters[ axis ].clear();
6885 // Count intersections before and after the point excluding touching ones.
6886 // If hasPositionInfo we count intersections of outer boundary only
6888 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6889 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6890 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6891 bool ok = ! u_int1->second._coincides;
6892 while ( ok && u_int1 != u2inters.end() )
6894 double u = u_int1->first;
6895 bool touchingInt = false;
6896 if ( ++u_int2 != u2inters.end() )
6898 // skip intersections at the same point (if the line passes through edge or node)
6900 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6906 // skip tangent intersections
6908 const SMDS_MeshElement* prevFace = u_int1->second._face;
6909 while ( ok && u_int2->second._coincides )
6911 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6917 ok = ( u_int2 != u2inters.end() );
6922 // skip intersections at the same point after tangent intersections
6925 double u2 = u_int2->first;
6927 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6933 // decide if we skipped a touching intersection
6934 if ( nbSamePnt + nbTgt > 0 )
6936 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6937 map< double, TInters >::iterator u_int = u_int1;
6938 for ( ; u_int != u_int2; ++u_int )
6940 if ( u_int->second._coincides ) continue;
6941 double dot = u_int->second._faceNorm * line.Direction();
6942 if ( dot > maxDot ) maxDot = dot;
6943 if ( dot < minDot ) minDot = dot;
6945 touchingInt = ( minDot*maxDot < 0 );
6950 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6961 u_int1 = u_int2; // to next intersection
6963 } // loop on intersections with one line
6967 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6970 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6973 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6974 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6976 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6979 if ( (f<0) == (l<0) )
6982 if ( hasPositionInfo )
6983 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
6985 } // loop on intersections of the tree lines - thorough analysis
6987 if ( !hasPositionInfo )
6989 // gather info on faces position - is face in the outer boundary or not
6990 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
6991 findOuterBoundary( u2inters.begin()->second._face );
6994 } // two attempts - with and w/o faces position info in the mesh
6996 return TopAbs_UNKNOWN;
6999 //=======================================================================
7001 * \brief Return elements possibly intersecting the line
7003 //=======================================================================
7005 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7006 SMDSAbs_ElementType type,
7007 vector< const SMDS_MeshElement* >& foundElems)
7009 if ( !_ebbTree || _elementType != type )
7011 if ( _ebbTree ) delete _ebbTree;
7012 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7014 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7015 _ebbTree->getElementsNearLine( line, suspectFaces );
7016 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7019 //=======================================================================
7021 * \brief Return SMESH_ElementSearcher
7023 //=======================================================================
7025 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7027 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7030 //=======================================================================
7032 * \brief Return SMESH_ElementSearcher
7034 //=======================================================================
7036 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7038 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7041 //=======================================================================
7043 * \brief Return true if the point is IN or ON of the element
7045 //=======================================================================
7047 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7049 if ( element->GetType() == SMDSAbs_Volume)
7051 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7054 // get ordered nodes
7056 vector< gp_XYZ > xyz;
7057 vector<const SMDS_MeshNode*> nodeList;
7059 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7060 if ( element->IsQuadratic() ) {
7061 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7062 nodeIt = f->interlacedNodesElemIterator();
7063 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7064 nodeIt = e->interlacedNodesElemIterator();
7066 while ( nodeIt->more() )
7068 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7069 xyz.push_back( SMESH_TNodeXYZ(node) );
7070 nodeList.push_back(node);
7073 int i, nbNodes = element->NbNodes();
7075 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7077 // compute face normal
7078 gp_Vec faceNorm(0,0,0);
7079 xyz.push_back( xyz.front() );
7080 nodeList.push_back( nodeList.front() );
7081 for ( i = 0; i < nbNodes; ++i )
7083 gp_Vec edge1( xyz[i+1], xyz[i]);
7084 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7085 faceNorm += edge1 ^ edge2;
7087 double normSize = faceNorm.Magnitude();
7088 if ( normSize <= tol )
7090 // degenerated face: point is out if it is out of all face edges
7091 for ( i = 0; i < nbNodes; ++i )
7093 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7094 if ( !isOut( &edge, point, tol ))
7099 faceNorm /= normSize;
7101 // check if the point lays on face plane
7102 gp_Vec n2p( xyz[0], point );
7103 if ( fabs( n2p * faceNorm ) > tol )
7104 return true; // not on face plane
7106 // check if point is out of face boundary:
7107 // define it by closest transition of a ray point->infinity through face boundary
7108 // on the face plane.
7109 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7110 // to find intersections of the ray with the boundary.
7112 gp_Vec plnNorm = ray ^ faceNorm;
7113 normSize = plnNorm.Magnitude();
7114 if ( normSize <= tol ) return false; // point coincides with the first node
7115 plnNorm /= normSize;
7116 // for each node of the face, compute its signed distance to the plane
7117 vector<double> dist( nbNodes + 1);
7118 for ( i = 0; i < nbNodes; ++i )
7120 gp_Vec n2p( xyz[i], point );
7121 dist[i] = n2p * plnNorm;
7123 dist.back() = dist.front();
7124 // find the closest intersection
7126 double rClosest, distClosest = 1e100;;
7128 for ( i = 0; i < nbNodes; ++i )
7131 if ( fabs( dist[i]) < tol )
7133 else if ( fabs( dist[i+1]) < tol )
7135 else if ( dist[i] * dist[i+1] < 0 )
7136 r = dist[i] / ( dist[i] - dist[i+1] );
7138 continue; // no intersection
7139 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7140 gp_Vec p2int ( point, pInt);
7141 if ( p2int * ray > -tol ) // right half-space
7143 double intDist = p2int.SquareMagnitude();
7144 if ( intDist < distClosest )
7149 distClosest = intDist;
7154 return true; // no intesections - out
7156 // analyse transition
7157 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7158 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7159 gp_Vec p2int ( point, pClosest );
7160 bool out = (edgeNorm * p2int) < -tol;
7161 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7164 // ray pass through a face node; analyze transition through an adjacent edge
7165 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7166 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7167 gp_Vec edgeAdjacent( p1, p2 );
7168 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7169 bool out2 = (edgeNorm2 * p2int) < -tol;
7171 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7172 return covexCorner ? (out || out2) : (out && out2);
7174 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7176 // point is out of edge if it is NOT ON any straight part of edge
7177 // (we consider quadratic edge as being composed of two straight parts)
7178 for ( i = 1; i < nbNodes; ++i )
7180 gp_Vec edge( xyz[i-1], xyz[i]);
7181 gp_Vec n1p ( xyz[i-1], point);
7182 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7185 gp_Vec n2p( xyz[i], point );
7186 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7188 return false; // point is ON this part
7192 // Node or 0D element -------------------------------------------------------------------------
7194 gp_Vec n2p ( xyz[0], point );
7195 return n2p.Magnitude() <= tol;
7200 //=======================================================================
7201 //function : SimplifyFace
7203 //=======================================================================
7204 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7205 vector<const SMDS_MeshNode *>& poly_nodes,
7206 vector<int>& quantities) const
7208 int nbNodes = faceNodes.size();
7213 set<const SMDS_MeshNode*> nodeSet;
7215 // get simple seq of nodes
7216 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7217 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7218 int iSimple = 0, nbUnique = 0;
7220 simpleNodes[iSimple++] = faceNodes[0];
7222 for (int iCur = 1; iCur < nbNodes; iCur++) {
7223 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7224 simpleNodes[iSimple++] = faceNodes[iCur];
7225 if (nodeSet.insert( faceNodes[iCur] ).second)
7229 int nbSimple = iSimple;
7230 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7240 bool foundLoop = (nbSimple > nbUnique);
7243 set<const SMDS_MeshNode*> loopSet;
7244 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7245 const SMDS_MeshNode* n = simpleNodes[iSimple];
7246 if (!loopSet.insert( n ).second) {
7250 int iC = 0, curLast = iSimple;
7251 for (; iC < curLast; iC++) {
7252 if (simpleNodes[iC] == n) break;
7254 int loopLen = curLast - iC;
7256 // create sub-element
7258 quantities.push_back(loopLen);
7259 for (; iC < curLast; iC++) {
7260 poly_nodes.push_back(simpleNodes[iC]);
7263 // shift the rest nodes (place from the first loop position)
7264 for (iC = curLast + 1; iC < nbSimple; iC++) {
7265 simpleNodes[iC - loopLen] = simpleNodes[iC];
7267 nbSimple -= loopLen;
7270 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7271 } // while (foundLoop)
7275 quantities.push_back(iSimple);
7276 for (int i = 0; i < iSimple; i++)
7277 poly_nodes.push_back(simpleNodes[i]);
7283 //=======================================================================
7284 //function : MergeNodes
7285 //purpose : In each group, the cdr of nodes are substituted by the first one
7287 //=======================================================================
7289 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7291 MESSAGE("MergeNodes");
7292 myLastCreatedElems.Clear();
7293 myLastCreatedNodes.Clear();
7295 SMESHDS_Mesh* aMesh = GetMeshDS();
7297 TNodeNodeMap nodeNodeMap; // node to replace - new node
7298 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7299 list< int > rmElemIds, rmNodeIds;
7301 // Fill nodeNodeMap and elems
7303 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7304 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7305 list<const SMDS_MeshNode*>& nodes = *grIt;
7306 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7307 const SMDS_MeshNode* nToKeep = *nIt;
7308 //MESSAGE("node to keep " << nToKeep->GetID());
7309 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7310 const SMDS_MeshNode* nToRemove = *nIt;
7311 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7312 if ( nToRemove != nToKeep ) {
7313 //MESSAGE(" node to remove " << nToRemove->GetID());
7314 rmNodeIds.push_back( nToRemove->GetID() );
7315 AddToSameGroups( nToKeep, nToRemove, aMesh );
7318 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7319 while ( invElemIt->more() ) {
7320 const SMDS_MeshElement* elem = invElemIt->next();
7325 // Change element nodes or remove an element
7327 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7328 for ( ; eIt != elems.end(); eIt++ ) {
7329 const SMDS_MeshElement* elem = *eIt;
7330 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7331 int nbNodes = elem->NbNodes();
7332 int aShapeId = FindShape( elem );
7334 set<const SMDS_MeshNode*> nodeSet;
7335 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7336 int iUnique = 0, iCur = 0, nbRepl = 0;
7337 vector<int> iRepl( nbNodes );
7339 // get new seq of nodes
7340 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7341 while ( itN->more() ) {
7342 const SMDS_MeshNode* n =
7343 static_cast<const SMDS_MeshNode*>( itN->next() );
7345 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7346 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7348 // BUG 0020185: begin
7350 bool stopRecur = false;
7351 set<const SMDS_MeshNode*> nodesRecur;
7352 nodesRecur.insert(n);
7353 while (!stopRecur) {
7354 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7355 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7356 n = (*nnIt_i).second;
7357 if (!nodesRecur.insert(n).second) {
7358 // error: recursive dependancy
7367 iRepl[ nbRepl++ ] = iCur;
7369 curNodes[ iCur ] = n;
7370 bool isUnique = nodeSet.insert( n ).second;
7372 uniqueNodes[ iUnique++ ] = n;
7376 // Analyse element topology after replacement
7379 int nbUniqueNodes = nodeSet.size();
7380 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7381 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7382 // Polygons and Polyhedral volumes
7383 if (elem->IsPoly()) {
7385 if (elem->GetType() == SMDSAbs_Face) {
7387 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7389 for (; inode < nbNodes; inode++) {
7390 face_nodes[inode] = curNodes[inode];
7393 vector<const SMDS_MeshNode *> polygons_nodes;
7394 vector<int> quantities;
7395 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7398 for (int iface = 0; iface < nbNew; iface++) {
7399 int nbNodes = quantities[iface];
7400 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7401 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7402 poly_nodes[ii] = polygons_nodes[inode];
7404 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7405 myLastCreatedElems.Append(newElem);
7407 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7410 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7411 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7412 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7414 if (nbNew > 0) quid = nbNew - 1;
7415 vector<int> newquant(quantities.begin()+quid, quantities.end());
7416 const SMDS_MeshElement* newElem = 0;
7417 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7418 myLastCreatedElems.Append(newElem);
7419 if ( aShapeId && newElem )
7420 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7421 rmElemIds.push_back(elem->GetID());
7424 rmElemIds.push_back(elem->GetID());
7428 else if (elem->GetType() == SMDSAbs_Volume) {
7429 // Polyhedral volume
7430 if (nbUniqueNodes < 4) {
7431 rmElemIds.push_back(elem->GetID());
7434 // each face has to be analyzed in order to check volume validity
7435 const SMDS_VtkVolume* aPolyedre =
7436 dynamic_cast<const SMDS_VtkVolume*>( elem );
7438 int nbFaces = aPolyedre->NbFaces();
7440 vector<const SMDS_MeshNode *> poly_nodes;
7441 vector<int> quantities;
7443 for (int iface = 1; iface <= nbFaces; iface++) {
7444 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7445 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7447 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7448 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7449 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7450 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7451 faceNode = (*nnIt).second;
7453 faceNodes[inode - 1] = faceNode;
7456 SimplifyFace(faceNodes, poly_nodes, quantities);
7459 if (quantities.size() > 3) {
7460 // to be done: remove coincident faces
7463 if (quantities.size() > 3)
7465 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7466 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7467 const SMDS_MeshElement* newElem = 0;
7468 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7469 myLastCreatedElems.Append(newElem);
7470 if ( aShapeId && newElem )
7471 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7472 rmElemIds.push_back(elem->GetID());
7476 rmElemIds.push_back(elem->GetID());
7487 // TODO not all the possible cases are solved. Find something more generic?
7488 switch ( nbNodes ) {
7489 case 2: ///////////////////////////////////// EDGE
7490 isOk = false; break;
7491 case 3: ///////////////////////////////////// TRIANGLE
7492 isOk = false; break;
7494 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7496 else { //////////////////////////////////// QUADRANGLE
7497 if ( nbUniqueNodes < 3 )
7499 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7500 isOk = false; // opposite nodes stick
7501 //MESSAGE("isOk " << isOk);
7504 case 6: ///////////////////////////////////// PENTAHEDRON
7505 if ( nbUniqueNodes == 4 ) {
7506 // ---------------------------------> tetrahedron
7508 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7509 // all top nodes stick: reverse a bottom
7510 uniqueNodes[ 0 ] = curNodes [ 1 ];
7511 uniqueNodes[ 1 ] = curNodes [ 0 ];
7513 else if (nbRepl == 3 &&
7514 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7515 // all bottom nodes stick: set a top before
7516 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7517 uniqueNodes[ 0 ] = curNodes [ 3 ];
7518 uniqueNodes[ 1 ] = curNodes [ 4 ];
7519 uniqueNodes[ 2 ] = curNodes [ 5 ];
7521 else if (nbRepl == 4 &&
7522 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7523 // a lateral face turns into a line: reverse a bottom
7524 uniqueNodes[ 0 ] = curNodes [ 1 ];
7525 uniqueNodes[ 1 ] = curNodes [ 0 ];
7530 else if ( nbUniqueNodes == 5 ) {
7531 // PENTAHEDRON --------------------> 2 tetrahedrons
7532 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7533 // a bottom node sticks with a linked top one
7535 SMDS_MeshElement* newElem =
7536 aMesh->AddVolume(curNodes[ 3 ],
7539 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7540 myLastCreatedElems.Append(newElem);
7542 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7543 // 2. : reverse a bottom
7544 uniqueNodes[ 0 ] = curNodes [ 1 ];
7545 uniqueNodes[ 1 ] = curNodes [ 0 ];
7555 if(elem->IsQuadratic()) { // Quadratic quadrangle
7567 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7570 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7572 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7573 uniqueNodes[0] = curNodes[0];
7574 uniqueNodes[1] = curNodes[2];
7575 uniqueNodes[2] = curNodes[3];
7576 uniqueNodes[3] = curNodes[5];
7577 uniqueNodes[4] = curNodes[6];
7578 uniqueNodes[5] = curNodes[7];
7581 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7582 uniqueNodes[0] = curNodes[0];
7583 uniqueNodes[1] = curNodes[1];
7584 uniqueNodes[2] = curNodes[2];
7585 uniqueNodes[3] = curNodes[4];
7586 uniqueNodes[4] = curNodes[5];
7587 uniqueNodes[5] = curNodes[6];
7590 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7591 uniqueNodes[0] = curNodes[1];
7592 uniqueNodes[1] = curNodes[2];
7593 uniqueNodes[2] = curNodes[3];
7594 uniqueNodes[3] = curNodes[5];
7595 uniqueNodes[4] = curNodes[6];
7596 uniqueNodes[5] = curNodes[0];
7599 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7600 uniqueNodes[0] = curNodes[0];
7601 uniqueNodes[1] = curNodes[1];
7602 uniqueNodes[2] = curNodes[3];
7603 uniqueNodes[3] = curNodes[4];
7604 uniqueNodes[4] = curNodes[6];
7605 uniqueNodes[5] = curNodes[7];
7608 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7609 uniqueNodes[0] = curNodes[0];
7610 uniqueNodes[1] = curNodes[2];
7611 uniqueNodes[2] = curNodes[3];
7612 uniqueNodes[3] = curNodes[1];
7613 uniqueNodes[4] = curNodes[6];
7614 uniqueNodes[5] = curNodes[7];
7617 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
7618 uniqueNodes[0] = curNodes[0];
7619 uniqueNodes[1] = curNodes[1];
7620 uniqueNodes[2] = curNodes[2];
7621 uniqueNodes[3] = curNodes[4];
7622 uniqueNodes[4] = curNodes[5];
7623 uniqueNodes[5] = curNodes[7];
7626 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7627 uniqueNodes[0] = curNodes[0];
7628 uniqueNodes[1] = curNodes[1];
7629 uniqueNodes[2] = curNodes[3];
7630 uniqueNodes[3] = curNodes[4];
7631 uniqueNodes[4] = curNodes[2];
7632 uniqueNodes[5] = curNodes[7];
7635 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7636 uniqueNodes[0] = curNodes[0];
7637 uniqueNodes[1] = curNodes[1];
7638 uniqueNodes[2] = curNodes[2];
7639 uniqueNodes[3] = curNodes[4];
7640 uniqueNodes[4] = curNodes[5];
7641 uniqueNodes[5] = curNodes[3];
7646 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7649 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7653 //////////////////////////////////// HEXAHEDRON
7655 SMDS_VolumeTool hexa (elem);
7656 hexa.SetExternalNormal();
7657 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7658 //////////////////////// ---> tetrahedron
7659 for ( int iFace = 0; iFace < 6; iFace++ ) {
7660 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7661 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7662 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7663 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7664 // one face turns into a point ...
7665 int iOppFace = hexa.GetOppFaceIndex( iFace );
7666 ind = hexa.GetFaceNodesIndices( iOppFace );
7668 iUnique = 2; // reverse a tetrahedron bottom
7669 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7670 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7672 else if ( iUnique >= 0 )
7673 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7675 if ( nbStick == 1 ) {
7676 // ... and the opposite one - into a triangle.
7678 ind = hexa.GetFaceNodesIndices( iFace );
7679 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7686 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7687 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
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 1 bottom
7698 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7699 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7701 else if ( iUnique >= 0 )
7702 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7704 if ( nbStick == 0 ) {
7705 // ... and the opposite one is a quadrangle
7707 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7708 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7711 SMDS_MeshElement* newElem =
7712 aMesh->AddVolume(curNodes[ind[ 0 ]],
7715 curNodes[indTop[ 0 ]]);
7716 myLastCreatedElems.Append(newElem);
7718 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7725 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7726 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7727 // find indices of quad and tri faces
7728 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7729 for ( iFace = 0; iFace < 6; iFace++ ) {
7730 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7732 for ( iCur = 0; iCur < 4; iCur++ )
7733 nodeSet.insert( curNodes[ind[ iCur ]] );
7734 nbUniqueNodes = nodeSet.size();
7735 if ( nbUniqueNodes == 3 )
7736 iTriFace[ nbTri++ ] = iFace;
7737 else if ( nbUniqueNodes == 4 )
7738 iQuadFace[ nbQuad++ ] = iFace;
7740 if (nbQuad == 2 && nbTri == 4 &&
7741 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7742 // 2 opposite quadrangles stuck with a diagonal;
7743 // sample groups of merged indices: (0-4)(2-6)
7744 // --------------------------------------------> 2 tetrahedrons
7745 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7746 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7747 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7748 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7749 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7750 // stuck with 0-2 diagonal
7758 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7759 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7760 // stuck with 1-3 diagonal
7772 uniqueNodes[ 0 ] = curNodes [ i0 ];
7773 uniqueNodes[ 1 ] = curNodes [ i1d ];
7774 uniqueNodes[ 2 ] = curNodes [ i3d ];
7775 uniqueNodes[ 3 ] = curNodes [ i0t ];
7778 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7782 myLastCreatedElems.Append(newElem);
7784 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7787 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7788 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7789 // --------------------------------------------> prism
7790 // find 2 opposite triangles
7792 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7793 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7794 // find indices of kept and replaced nodes
7795 // and fill unique nodes of 2 opposite triangles
7796 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7797 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7798 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7799 // fill unique nodes
7802 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7803 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7804 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7806 // iCur of a linked node of the opposite face (make normals co-directed):
7807 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7808 // check that correspondent corners of triangles are linked
7809 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7812 uniqueNodes[ iUnique ] = n;
7813 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7822 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7828 } // switch ( nbNodes )
7830 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7832 if ( isOk ) { // the elem remains valid after sticking nodes
7833 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
7835 // Change nodes of polyedre
7836 const SMDS_VtkVolume* aPolyedre =
7837 dynamic_cast<const SMDS_VtkVolume*>( elem );
7839 int nbFaces = aPolyedre->NbFaces();
7841 vector<const SMDS_MeshNode *> poly_nodes;
7842 vector<int> quantities (nbFaces);
7844 for (int iface = 1; iface <= nbFaces; iface++) {
7845 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7846 quantities[iface - 1] = nbFaceNodes;
7848 for (inode = 1; inode <= nbFaceNodes; inode++) {
7849 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7851 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7852 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7853 curNode = (*nnIt).second;
7855 poly_nodes.push_back(curNode);
7858 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7861 else // replace non-polyhedron elements
7863 const SMDSAbs_ElementType etyp = elem->GetType();
7864 const int elemId = elem->GetID();
7865 const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
7866 uniqueNodes.resize(nbUniqueNodes);
7868 SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
7870 aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
7871 SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
7872 if ( sm && newElem )
7873 sm->AddElement( newElem );
7874 if ( elem != newElem )
7875 ReplaceElemInGroups( elem, newElem, aMesh );
7879 // Remove invalid regular element or invalid polygon
7880 rmElemIds.push_back( elem->GetID() );
7883 } // loop on elements
7885 // Remove bad elements, then equal nodes (order important)
7887 Remove( rmElemIds, false );
7888 Remove( rmNodeIds, true );
7893 // ========================================================
7894 // class : SortableElement
7895 // purpose : allow sorting elements basing on their nodes
7896 // ========================================================
7897 class SortableElement : public set <const SMDS_MeshElement*>
7901 SortableElement( const SMDS_MeshElement* theElem )
7904 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7905 while ( nodeIt->more() )
7906 this->insert( nodeIt->next() );
7909 const SMDS_MeshElement* Get() const
7912 void Set(const SMDS_MeshElement* e) const
7917 mutable const SMDS_MeshElement* myElem;
7920 //=======================================================================
7921 //function : FindEqualElements
7922 //purpose : Return list of group of elements built on the same nodes.
7923 // Search among theElements or in the whole mesh if theElements is empty
7924 //=======================================================================
7925 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7926 TListOfListOfElementsID & theGroupsOfElementsID)
7928 myLastCreatedElems.Clear();
7929 myLastCreatedNodes.Clear();
7931 typedef set<const SMDS_MeshElement*> TElemsSet;
7932 typedef map< SortableElement, int > TMapOfNodeSet;
7933 typedef list<int> TGroupOfElems;
7936 if ( theElements.empty() )
7937 { // get all elements in the mesh
7938 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7939 while ( eIt->more() )
7940 elems.insert( elems.end(), eIt->next());
7943 elems = theElements;
7945 vector< TGroupOfElems > arrayOfGroups;
7946 TGroupOfElems groupOfElems;
7947 TMapOfNodeSet mapOfNodeSet;
7949 TElemsSet::iterator elemIt = elems.begin();
7950 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7951 const SMDS_MeshElement* curElem = *elemIt;
7952 SortableElement SE(curElem);
7955 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7956 if( !(pp.second) ) {
7957 TMapOfNodeSet::iterator& itSE = pp.first;
7958 ind = (*itSE).second;
7959 arrayOfGroups[ind].push_back(curElem->GetID());
7962 groupOfElems.clear();
7963 groupOfElems.push_back(curElem->GetID());
7964 arrayOfGroups.push_back(groupOfElems);
7969 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7970 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7971 groupOfElems = *groupIt;
7972 if ( groupOfElems.size() > 1 ) {
7973 groupOfElems.sort();
7974 theGroupsOfElementsID.push_back(groupOfElems);
7979 //=======================================================================
7980 //function : MergeElements
7981 //purpose : In each given group, substitute all elements by the first one.
7982 //=======================================================================
7984 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
7986 myLastCreatedElems.Clear();
7987 myLastCreatedNodes.Clear();
7989 typedef list<int> TListOfIDs;
7990 TListOfIDs rmElemIds; // IDs of elems to remove
7992 SMESHDS_Mesh* aMesh = GetMeshDS();
7994 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
7995 while ( groupsIt != theGroupsOfElementsID.end() ) {
7996 TListOfIDs& aGroupOfElemID = *groupsIt;
7997 aGroupOfElemID.sort();
7998 int elemIDToKeep = aGroupOfElemID.front();
7999 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8000 aGroupOfElemID.pop_front();
8001 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8002 while ( idIt != aGroupOfElemID.end() ) {
8003 int elemIDToRemove = *idIt;
8004 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8005 // add the kept element in groups of removed one (PAL15188)
8006 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8007 rmElemIds.push_back( elemIDToRemove );
8013 Remove( rmElemIds, false );
8016 //=======================================================================
8017 //function : MergeEqualElements
8018 //purpose : Remove all but one of elements built on the same nodes.
8019 //=======================================================================
8021 void SMESH_MeshEditor::MergeEqualElements()
8023 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8024 to merge equal elements in the whole mesh */
8025 TListOfListOfElementsID aGroupsOfElementsID;
8026 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8027 MergeElements(aGroupsOfElementsID);
8030 //=======================================================================
8031 //function : FindFaceInSet
8032 //purpose : Return a face having linked nodes n1 and n2 and which is
8033 // - not in avoidSet,
8034 // - in elemSet provided that !elemSet.empty()
8035 // i1 and i2 optionally returns indices of n1 and n2
8036 //=======================================================================
8038 const SMDS_MeshElement*
8039 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8040 const SMDS_MeshNode* n2,
8041 const TIDSortedElemSet& elemSet,
8042 const TIDSortedElemSet& avoidSet,
8048 const SMDS_MeshElement* face = 0;
8050 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8051 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8052 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8054 //MESSAGE("in while ( invElemIt->more() && !face )");
8055 const SMDS_MeshElement* elem = invElemIt->next();
8056 if (avoidSet.count( elem ))
8058 if ( !elemSet.empty() && !elemSet.count( elem ))
8061 i1 = elem->GetNodeIndex( n1 );
8062 // find a n2 linked to n1
8063 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8064 for ( int di = -1; di < 2 && !face; di += 2 )
8066 i2 = (i1+di+nbN) % nbN;
8067 if ( elem->GetNode( i2 ) == n2 )
8070 if ( !face && elem->IsQuadratic())
8072 // analysis for quadratic elements using all nodes
8073 const SMDS_VtkFace* F =
8074 dynamic_cast<const SMDS_VtkFace*>(elem);
8075 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8076 // use special nodes iterator
8077 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8078 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8079 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8081 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8082 if ( n1 == prevN && n2 == n )
8086 else if ( n2 == prevN && n1 == n )
8088 face = elem; swap( i1, i2 );
8094 if ( n1ind ) *n1ind = i1;
8095 if ( n2ind ) *n2ind = i2;
8099 //=======================================================================
8100 //function : findAdjacentFace
8102 //=======================================================================
8104 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8105 const SMDS_MeshNode* n2,
8106 const SMDS_MeshElement* elem)
8108 TIDSortedElemSet elemSet, avoidSet;
8110 avoidSet.insert ( elem );
8111 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8114 //=======================================================================
8115 //function : FindFreeBorder
8117 //=======================================================================
8119 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8121 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8122 const SMDS_MeshNode* theSecondNode,
8123 const SMDS_MeshNode* theLastNode,
8124 list< const SMDS_MeshNode* > & theNodes,
8125 list< const SMDS_MeshElement* >& theFaces)
8127 if ( !theFirstNode || !theSecondNode )
8129 // find border face between theFirstNode and theSecondNode
8130 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8134 theFaces.push_back( curElem );
8135 theNodes.push_back( theFirstNode );
8136 theNodes.push_back( theSecondNode );
8138 //vector<const SMDS_MeshNode*> nodes;
8139 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8140 TIDSortedElemSet foundElems;
8141 bool needTheLast = ( theLastNode != 0 );
8143 while ( nStart != theLastNode ) {
8144 if ( nStart == theFirstNode )
8145 return !needTheLast;
8147 // find all free border faces sharing form nStart
8149 list< const SMDS_MeshElement* > curElemList;
8150 list< const SMDS_MeshNode* > nStartList;
8151 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8152 while ( invElemIt->more() ) {
8153 const SMDS_MeshElement* e = invElemIt->next();
8154 if ( e == curElem || foundElems.insert( e ).second ) {
8156 int iNode = 0, nbNodes = e->NbNodes();
8157 //const SMDS_MeshNode* nodes[nbNodes+1];
8158 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8160 if(e->IsQuadratic()) {
8161 const SMDS_VtkFace* F =
8162 dynamic_cast<const SMDS_VtkFace*>(e);
8163 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8164 // use special nodes iterator
8165 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8166 while( anIter->more() ) {
8167 nodes[ iNode++ ] = cast2Node(anIter->next());
8171 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8172 while ( nIt->more() )
8173 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8175 nodes[ iNode ] = nodes[ 0 ];
8177 for ( iNode = 0; iNode < nbNodes; iNode++ )
8178 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8179 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8180 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8182 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8183 curElemList.push_back( e );
8187 // analyse the found
8189 int nbNewBorders = curElemList.size();
8190 if ( nbNewBorders == 0 ) {
8191 // no free border furthermore
8192 return !needTheLast;
8194 else if ( nbNewBorders == 1 ) {
8195 // one more element found
8197 nStart = nStartList.front();
8198 curElem = curElemList.front();
8199 theFaces.push_back( curElem );
8200 theNodes.push_back( nStart );
8203 // several continuations found
8204 list< const SMDS_MeshElement* >::iterator curElemIt;
8205 list< const SMDS_MeshNode* >::iterator nStartIt;
8206 // check if one of them reached the last node
8207 if ( needTheLast ) {
8208 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8209 curElemIt!= curElemList.end();
8210 curElemIt++, nStartIt++ )
8211 if ( *nStartIt == theLastNode ) {
8212 theFaces.push_back( *curElemIt );
8213 theNodes.push_back( *nStartIt );
8217 // find the best free border by the continuations
8218 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8219 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8220 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8221 curElemIt!= curElemList.end();
8222 curElemIt++, nStartIt++ )
8224 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8225 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8226 // find one more free border
8227 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8231 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8232 // choice: clear a worse one
8233 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8234 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8235 contNodes[ iWorse ].clear();
8236 contFaces[ iWorse ].clear();
8239 if ( contNodes[0].empty() && contNodes[1].empty() )
8242 // append the best free border
8243 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8244 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8245 theNodes.pop_back(); // remove nIgnore
8246 theNodes.pop_back(); // remove nStart
8247 theFaces.pop_back(); // remove curElem
8248 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8249 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8250 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8251 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8254 } // several continuations found
8255 } // while ( nStart != theLastNode )
8260 //=======================================================================
8261 //function : CheckFreeBorderNodes
8262 //purpose : Return true if the tree nodes are on a free border
8263 //=======================================================================
8265 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8266 const SMDS_MeshNode* theNode2,
8267 const SMDS_MeshNode* theNode3)
8269 list< const SMDS_MeshNode* > nodes;
8270 list< const SMDS_MeshElement* > faces;
8271 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8274 //=======================================================================
8275 //function : SewFreeBorder
8277 //=======================================================================
8279 SMESH_MeshEditor::Sew_Error
8280 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8281 const SMDS_MeshNode* theBordSecondNode,
8282 const SMDS_MeshNode* theBordLastNode,
8283 const SMDS_MeshNode* theSideFirstNode,
8284 const SMDS_MeshNode* theSideSecondNode,
8285 const SMDS_MeshNode* theSideThirdNode,
8286 const bool theSideIsFreeBorder,
8287 const bool toCreatePolygons,
8288 const bool toCreatePolyedrs)
8290 myLastCreatedElems.Clear();
8291 myLastCreatedNodes.Clear();
8293 MESSAGE("::SewFreeBorder()");
8294 Sew_Error aResult = SEW_OK;
8296 // ====================================
8297 // find side nodes and elements
8298 // ====================================
8300 list< const SMDS_MeshNode* > nSide[ 2 ];
8301 list< const SMDS_MeshElement* > eSide[ 2 ];
8302 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8303 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8307 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8308 nSide[0], eSide[0])) {
8309 MESSAGE(" Free Border 1 not found " );
8310 aResult = SEW_BORDER1_NOT_FOUND;
8312 if (theSideIsFreeBorder) {
8315 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8316 nSide[1], eSide[1])) {
8317 MESSAGE(" Free Border 2 not found " );
8318 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8321 if ( aResult != SEW_OK )
8324 if (!theSideIsFreeBorder) {
8328 // -------------------------------------------------------------------------
8330 // 1. If nodes to merge are not coincident, move nodes of the free border
8331 // from the coord sys defined by the direction from the first to last
8332 // nodes of the border to the correspondent sys of the side 2
8333 // 2. On the side 2, find the links most co-directed with the correspondent
8334 // links of the free border
8335 // -------------------------------------------------------------------------
8337 // 1. Since sewing may break if there are volumes to split on the side 2,
8338 // we wont move nodes but just compute new coordinates for them
8339 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8340 TNodeXYZMap nBordXYZ;
8341 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8342 list< const SMDS_MeshNode* >::iterator nBordIt;
8344 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8345 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8346 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8347 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8348 double tol2 = 1.e-8;
8349 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8350 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8351 // Need node movement.
8353 // find X and Z axes to create trsf
8354 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8356 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8358 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8361 gp_Ax3 toBordAx( Pb1, Zb, X );
8362 gp_Ax3 fromSideAx( Ps1, Zs, X );
8363 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8365 gp_Trsf toBordSys, fromSide2Sys;
8366 toBordSys.SetTransformation( toBordAx );
8367 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8368 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8371 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8372 const SMDS_MeshNode* n = *nBordIt;
8373 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8374 toBordSys.Transforms( xyz );
8375 fromSide2Sys.Transforms( xyz );
8376 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8380 // just insert nodes XYZ in the nBordXYZ map
8381 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8382 const SMDS_MeshNode* n = *nBordIt;
8383 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8387 // 2. On the side 2, find the links most co-directed with the correspondent
8388 // links of the free border
8390 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8391 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8392 sideNodes.push_back( theSideFirstNode );
8394 bool hasVolumes = false;
8395 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8396 set<long> foundSideLinkIDs, checkedLinkIDs;
8397 SMDS_VolumeTool volume;
8398 //const SMDS_MeshNode* faceNodes[ 4 ];
8400 const SMDS_MeshNode* sideNode;
8401 const SMDS_MeshElement* sideElem;
8402 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8403 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8404 nBordIt = bordNodes.begin();
8406 // border node position and border link direction to compare with
8407 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8408 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8409 // choose next side node by link direction or by closeness to
8410 // the current border node:
8411 bool searchByDir = ( *nBordIt != theBordLastNode );
8413 // find the next node on the Side 2
8415 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8417 checkedLinkIDs.clear();
8418 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8420 // loop on inverse elements of current node (prevSideNode) on the Side 2
8421 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8422 while ( invElemIt->more() )
8424 const SMDS_MeshElement* elem = invElemIt->next();
8425 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8426 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8427 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8428 bool isVolume = volume.Set( elem );
8429 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8430 if ( isVolume ) // --volume
8432 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8433 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8434 if(elem->IsQuadratic()) {
8435 const SMDS_VtkFace* F =
8436 dynamic_cast<const SMDS_VtkFace*>(elem);
8437 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8438 // use special nodes iterator
8439 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8440 while( anIter->more() ) {
8441 nodes[ iNode ] = cast2Node(anIter->next());
8442 if ( nodes[ iNode++ ] == prevSideNode )
8443 iPrevNode = iNode - 1;
8447 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8448 while ( nIt->more() ) {
8449 nodes[ iNode ] = cast2Node( nIt->next() );
8450 if ( nodes[ iNode++ ] == prevSideNode )
8451 iPrevNode = iNode - 1;
8454 // there are 2 links to check
8459 // loop on links, to be precise, on the second node of links
8460 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8461 const SMDS_MeshNode* n = nodes[ iNode ];
8463 if ( !volume.IsLinked( n, prevSideNode ))
8467 if ( iNode ) // a node before prevSideNode
8468 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8469 else // a node after prevSideNode
8470 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8472 // check if this link was already used
8473 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8474 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8475 if (!isJustChecked &&
8476 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8478 // test a link geometrically
8479 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8480 bool linkIsBetter = false;
8481 double dot = 0.0, dist = 0.0;
8482 if ( searchByDir ) { // choose most co-directed link
8483 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8484 linkIsBetter = ( dot > maxDot );
8486 else { // choose link with the node closest to bordPos
8487 dist = ( nextXYZ - bordPos ).SquareModulus();
8488 linkIsBetter = ( dist < minDist );
8490 if ( linkIsBetter ) {
8499 } // loop on inverse elements of prevSideNode
8502 MESSAGE(" Cant find path by links of the Side 2 ");
8503 return SEW_BAD_SIDE_NODES;
8505 sideNodes.push_back( sideNode );
8506 sideElems.push_back( sideElem );
8507 foundSideLinkIDs.insert ( linkID );
8508 prevSideNode = sideNode;
8510 if ( *nBordIt == theBordLastNode )
8511 searchByDir = false;
8513 // find the next border link to compare with
8514 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8515 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8516 // move to next border node if sideNode is before forward border node (bordPos)
8517 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8518 prevBordNode = *nBordIt;
8520 bordPos = nBordXYZ[ *nBordIt ];
8521 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8522 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8526 while ( sideNode != theSideSecondNode );
8528 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8529 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8530 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8532 } // end nodes search on the side 2
8534 // ============================
8535 // sew the border to the side 2
8536 // ============================
8538 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8539 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8541 TListOfListOfNodes nodeGroupsToMerge;
8542 if ( nbNodes[0] == nbNodes[1] ||
8543 ( theSideIsFreeBorder && !theSideThirdNode)) {
8545 // all nodes are to be merged
8547 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8548 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8549 nIt[0]++, nIt[1]++ )
8551 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8552 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8553 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8558 // insert new nodes into the border and the side to get equal nb of segments
8560 // get normalized parameters of nodes on the borders
8561 //double param[ 2 ][ maxNbNodes ];
8563 param[0] = new double [ maxNbNodes ];
8564 param[1] = new double [ maxNbNodes ];
8566 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8567 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8568 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8569 const SMDS_MeshNode* nPrev = *nIt;
8570 double bordLength = 0;
8571 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8572 const SMDS_MeshNode* nCur = *nIt;
8573 gp_XYZ segment (nCur->X() - nPrev->X(),
8574 nCur->Y() - nPrev->Y(),
8575 nCur->Z() - nPrev->Z());
8576 double segmentLen = segment.Modulus();
8577 bordLength += segmentLen;
8578 param[ iBord ][ iNode ] = bordLength;
8581 // normalize within [0,1]
8582 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8583 param[ iBord ][ iNode ] /= bordLength;
8587 // loop on border segments
8588 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8589 int i[ 2 ] = { 0, 0 };
8590 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8591 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8593 TElemOfNodeListMap insertMap;
8594 TElemOfNodeListMap::iterator insertMapIt;
8596 // key: elem to insert nodes into
8597 // value: 2 nodes to insert between + nodes to be inserted
8599 bool next[ 2 ] = { false, false };
8601 // find min adjacent segment length after sewing
8602 double nextParam = 10., prevParam = 0;
8603 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8604 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8605 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8606 if ( i[ iBord ] > 0 )
8607 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8609 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8610 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8611 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8613 // choose to insert or to merge nodes
8614 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8615 if ( Abs( du ) <= minSegLen * 0.2 ) {
8618 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8619 const SMDS_MeshNode* n0 = *nIt[0];
8620 const SMDS_MeshNode* n1 = *nIt[1];
8621 nodeGroupsToMerge.back().push_back( n1 );
8622 nodeGroupsToMerge.back().push_back( n0 );
8623 // position of node of the border changes due to merge
8624 param[ 0 ][ i[0] ] += du;
8625 // move n1 for the sake of elem shape evaluation during insertion.
8626 // n1 will be removed by MergeNodes() anyway
8627 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8628 next[0] = next[1] = true;
8633 int intoBord = ( du < 0 ) ? 0 : 1;
8634 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8635 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8636 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8637 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8638 if ( intoBord == 1 ) {
8639 // move node of the border to be on a link of elem of the side
8640 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8641 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8642 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8643 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8644 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8646 insertMapIt = insertMap.find( elem );
8647 bool notFound = ( insertMapIt == insertMap.end() );
8648 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8650 // insert into another link of the same element:
8651 // 1. perform insertion into the other link of the elem
8652 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8653 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8654 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8655 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8656 // 2. perform insertion into the link of adjacent faces
8658 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8660 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8664 if (toCreatePolyedrs) {
8665 // perform insertion into the links of adjacent volumes
8666 UpdateVolumes(n12, n22, nodeList);
8668 // 3. find an element appeared on n1 and n2 after the insertion
8669 insertMap.erase( elem );
8670 elem = findAdjacentFace( n1, n2, 0 );
8672 if ( notFound || otherLink ) {
8673 // add element and nodes of the side into the insertMap
8674 insertMapIt = insertMap.insert
8675 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8676 (*insertMapIt).second.push_back( n1 );
8677 (*insertMapIt).second.push_back( n2 );
8679 // add node to be inserted into elem
8680 (*insertMapIt).second.push_back( nIns );
8681 next[ 1 - intoBord ] = true;
8684 // go to the next segment
8685 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8686 if ( next[ iBord ] ) {
8687 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8689 nPrev[ iBord ] = *nIt[ iBord ];
8690 nIt[ iBord ]++; i[ iBord ]++;
8694 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8696 // perform insertion of nodes into elements
8698 for (insertMapIt = insertMap.begin();
8699 insertMapIt != insertMap.end();
8702 const SMDS_MeshElement* elem = (*insertMapIt).first;
8703 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8704 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8705 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8707 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8709 if ( !theSideIsFreeBorder ) {
8710 // look for and insert nodes into the faces adjacent to elem
8712 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8714 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8719 if (toCreatePolyedrs) {
8720 // perform insertion into the links of adjacent volumes
8721 UpdateVolumes(n1, n2, nodeList);
8727 } // end: insert new nodes
8729 MergeNodes ( nodeGroupsToMerge );
8734 //=======================================================================
8735 //function : InsertNodesIntoLink
8736 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8737 // and theBetweenNode2 and split theElement
8738 //=======================================================================
8740 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8741 const SMDS_MeshNode* theBetweenNode1,
8742 const SMDS_MeshNode* theBetweenNode2,
8743 list<const SMDS_MeshNode*>& theNodesToInsert,
8744 const bool toCreatePoly)
8746 if ( theFace->GetType() != SMDSAbs_Face ) return;
8748 // find indices of 2 link nodes and of the rest nodes
8749 int iNode = 0, il1, il2, i3, i4;
8750 il1 = il2 = i3 = i4 = -1;
8751 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8752 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8754 if(theFace->IsQuadratic()) {
8755 const SMDS_VtkFace* F =
8756 dynamic_cast<const SMDS_VtkFace*>(theFace);
8757 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8758 // use special nodes iterator
8759 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8760 while( anIter->more() ) {
8761 const SMDS_MeshNode* n = cast2Node(anIter->next());
8762 if ( n == theBetweenNode1 )
8764 else if ( n == theBetweenNode2 )
8770 nodes[ iNode++ ] = n;
8774 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8775 while ( nodeIt->more() ) {
8776 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8777 if ( n == theBetweenNode1 )
8779 else if ( n == theBetweenNode2 )
8785 nodes[ iNode++ ] = n;
8788 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8791 // arrange link nodes to go one after another regarding the face orientation
8792 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8793 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8798 aNodesToInsert.reverse();
8800 // check that not link nodes of a quadrangles are in good order
8801 int nbFaceNodes = theFace->NbNodes();
8802 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8808 if (toCreatePoly || theFace->IsPoly()) {
8811 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8813 // add nodes of face up to first node of link
8816 if(theFace->IsQuadratic()) {
8817 const SMDS_VtkFace* F =
8818 dynamic_cast<const SMDS_VtkFace*>(theFace);
8819 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8820 // use special nodes iterator
8821 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8822 while( anIter->more() && !isFLN ) {
8823 const SMDS_MeshNode* n = cast2Node(anIter->next());
8824 poly_nodes[iNode++] = n;
8825 if (n == nodes[il1]) {
8829 // add nodes to insert
8830 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8831 for (; nIt != aNodesToInsert.end(); nIt++) {
8832 poly_nodes[iNode++] = *nIt;
8834 // add nodes of face starting from last node of link
8835 while ( anIter->more() ) {
8836 poly_nodes[iNode++] = cast2Node(anIter->next());
8840 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8841 while ( nodeIt->more() && !isFLN ) {
8842 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8843 poly_nodes[iNode++] = n;
8844 if (n == nodes[il1]) {
8848 // add nodes to insert
8849 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8850 for (; nIt != aNodesToInsert.end(); nIt++) {
8851 poly_nodes[iNode++] = *nIt;
8853 // add nodes of face starting from last node of link
8854 while ( nodeIt->more() ) {
8855 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8856 poly_nodes[iNode++] = n;
8860 // edit or replace the face
8861 SMESHDS_Mesh *aMesh = GetMeshDS();
8863 if (theFace->IsPoly()) {
8864 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8867 int aShapeId = FindShape( theFace );
8869 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8870 myLastCreatedElems.Append(newElem);
8871 if ( aShapeId && newElem )
8872 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8874 aMesh->RemoveElement(theFace);
8879 SMESHDS_Mesh *aMesh = GetMeshDS();
8880 if( !theFace->IsQuadratic() ) {
8882 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8883 int nbLinkNodes = 2 + aNodesToInsert.size();
8884 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8885 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8886 linkNodes[ 0 ] = nodes[ il1 ];
8887 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8888 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8889 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8890 linkNodes[ iNode++ ] = *nIt;
8892 // decide how to split a quadrangle: compare possible variants
8893 // and choose which of splits to be a quadrangle
8894 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8895 if ( nbFaceNodes == 3 ) {
8896 iBestQuad = nbSplits;
8899 else if ( nbFaceNodes == 4 ) {
8900 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8901 double aBestRate = DBL_MAX;
8902 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8904 double aBadRate = 0;
8905 // evaluate elements quality
8906 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8907 if ( iSplit == iQuad ) {
8908 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8912 aBadRate += getBadRate( &quad, aCrit );
8915 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8917 nodes[ iSplit < iQuad ? i4 : i3 ]);
8918 aBadRate += getBadRate( &tria, aCrit );
8922 if ( aBadRate < aBestRate ) {
8924 aBestRate = aBadRate;
8929 // create new elements
8930 int aShapeId = FindShape( theFace );
8933 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8934 SMDS_MeshElement* newElem = 0;
8935 if ( iSplit == iBestQuad )
8936 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8941 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8943 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8944 myLastCreatedElems.Append(newElem);
8945 if ( aShapeId && newElem )
8946 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8949 // change nodes of theFace
8950 const SMDS_MeshNode* newNodes[ 4 ];
8951 newNodes[ 0 ] = linkNodes[ i1 ];
8952 newNodes[ 1 ] = linkNodes[ i2 ];
8953 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8954 newNodes[ 3 ] = nodes[ i4 ];
8955 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8956 const SMDS_MeshElement* newElem = 0;
8957 if (iSplit == iBestQuad)
8958 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8960 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8961 myLastCreatedElems.Append(newElem);
8962 if ( aShapeId && newElem )
8963 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8964 } // end if(!theFace->IsQuadratic())
8965 else { // theFace is quadratic
8966 // we have to split theFace on simple triangles and one simple quadrangle
8968 int nbshift = tmp*2;
8969 // shift nodes in nodes[] by nbshift
8971 for(i=0; i<nbshift; i++) {
8972 const SMDS_MeshNode* n = nodes[0];
8973 for(j=0; j<nbFaceNodes-1; j++) {
8974 nodes[j] = nodes[j+1];
8976 nodes[nbFaceNodes-1] = n;
8978 il1 = il1 - nbshift;
8979 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
8980 // n0 n1 n2 n0 n1 n2
8981 // +-----+-----+ +-----+-----+
8990 // create new elements
8991 int aShapeId = FindShape( theFace );
8994 if(nbFaceNodes==6) { // quadratic triangle
8995 SMDS_MeshElement* newElem =
8996 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
8997 myLastCreatedElems.Append(newElem);
8998 if ( aShapeId && newElem )
8999 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9000 if(theFace->IsMediumNode(nodes[il1])) {
9001 // create quadrangle
9002 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9003 myLastCreatedElems.Append(newElem);
9004 if ( aShapeId && newElem )
9005 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9011 // create quadrangle
9012 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9013 myLastCreatedElems.Append(newElem);
9014 if ( aShapeId && newElem )
9015 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9021 else { // nbFaceNodes==8 - quadratic quadrangle
9022 SMDS_MeshElement* newElem =
9023 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9024 myLastCreatedElems.Append(newElem);
9025 if ( aShapeId && newElem )
9026 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9027 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9028 myLastCreatedElems.Append(newElem);
9029 if ( aShapeId && newElem )
9030 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9032 myLastCreatedElems.Append(newElem);
9033 if ( aShapeId && newElem )
9034 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9035 if(theFace->IsMediumNode(nodes[il1])) {
9036 // create quadrangle
9037 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9038 myLastCreatedElems.Append(newElem);
9039 if ( aShapeId && newElem )
9040 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9046 // create quadrangle
9047 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9048 myLastCreatedElems.Append(newElem);
9049 if ( aShapeId && newElem )
9050 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9056 // create needed triangles using n1,n2,n3 and inserted nodes
9057 int nbn = 2 + aNodesToInsert.size();
9058 //const SMDS_MeshNode* aNodes[nbn];
9059 vector<const SMDS_MeshNode*> aNodes(nbn);
9060 aNodes[0] = nodes[n1];
9061 aNodes[nbn-1] = nodes[n2];
9062 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9063 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9064 aNodes[iNode++] = *nIt;
9066 for(i=1; i<nbn; i++) {
9067 SMDS_MeshElement* newElem =
9068 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9069 myLastCreatedElems.Append(newElem);
9070 if ( aShapeId && newElem )
9071 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9075 aMesh->RemoveElement(theFace);
9078 //=======================================================================
9079 //function : UpdateVolumes
9081 //=======================================================================
9082 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9083 const SMDS_MeshNode* theBetweenNode2,
9084 list<const SMDS_MeshNode*>& theNodesToInsert)
9086 myLastCreatedElems.Clear();
9087 myLastCreatedNodes.Clear();
9089 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9090 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9091 const SMDS_MeshElement* elem = invElemIt->next();
9093 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9094 SMDS_VolumeTool aVolume (elem);
9095 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9098 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9099 int iface, nbFaces = aVolume.NbFaces();
9100 vector<const SMDS_MeshNode *> poly_nodes;
9101 vector<int> quantities (nbFaces);
9103 for (iface = 0; iface < nbFaces; iface++) {
9104 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9105 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9106 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9108 for (int inode = 0; inode < nbFaceNodes; inode++) {
9109 poly_nodes.push_back(faceNodes[inode]);
9111 if (nbInserted == 0) {
9112 if (faceNodes[inode] == theBetweenNode1) {
9113 if (faceNodes[inode + 1] == theBetweenNode2) {
9114 nbInserted = theNodesToInsert.size();
9116 // add nodes to insert
9117 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9118 for (; nIt != theNodesToInsert.end(); nIt++) {
9119 poly_nodes.push_back(*nIt);
9123 else if (faceNodes[inode] == theBetweenNode2) {
9124 if (faceNodes[inode + 1] == theBetweenNode1) {
9125 nbInserted = theNodesToInsert.size();
9127 // add nodes to insert in reversed order
9128 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9130 for (; nIt != theNodesToInsert.begin(); nIt--) {
9131 poly_nodes.push_back(*nIt);
9133 poly_nodes.push_back(*nIt);
9140 quantities[iface] = nbFaceNodes + nbInserted;
9143 // Replace or update the volume
9144 SMESHDS_Mesh *aMesh = GetMeshDS();
9146 if (elem->IsPoly()) {
9147 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9151 int aShapeId = FindShape( elem );
9153 SMDS_MeshElement* newElem =
9154 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9155 myLastCreatedElems.Append(newElem);
9156 if (aShapeId && newElem)
9157 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9159 aMesh->RemoveElement(elem);
9164 //=======================================================================
9166 * \brief Convert elements contained in a submesh to quadratic
9167 * \return int - nb of checked elements
9169 //=======================================================================
9171 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9172 SMESH_MesherHelper& theHelper,
9173 const bool theForce3d)
9176 if( !theSm ) return nbElem;
9178 vector<int> nbNodeInFaces;
9179 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9180 while(ElemItr->more())
9183 const SMDS_MeshElement* elem = ElemItr->next();
9184 if( !elem || elem->IsQuadratic() ) continue;
9186 int id = elem->GetID();
9187 int nbNodes = elem->NbNodes();
9188 SMDSAbs_ElementType aType = elem->GetType();
9190 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9191 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9192 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9194 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9196 const SMDS_MeshElement* NewElem = 0;
9202 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9210 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9213 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9216 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9221 case SMDSAbs_Volume :
9226 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9229 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9232 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9235 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9236 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9239 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9246 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9248 theSm->AddElement( NewElem );
9250 // if (!GetMeshDS()->isCompacted())
9251 // GetMeshDS()->compactMesh();
9255 //=======================================================================
9256 //function : ConvertToQuadratic
9258 //=======================================================================
9259 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9261 SMESHDS_Mesh* meshDS = GetMeshDS();
9263 SMESH_MesherHelper aHelper(*myMesh);
9264 aHelper.SetIsQuadratic( true );
9266 int nbCheckedElems = 0;
9267 if ( myMesh->HasShapeToMesh() )
9269 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9271 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9272 while ( smIt->more() ) {
9273 SMESH_subMesh* sm = smIt->next();
9274 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9275 aHelper.SetSubShape( sm->GetSubShape() );
9276 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9281 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9282 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9284 SMESHDS_SubMesh *smDS = 0;
9285 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9286 while(aEdgeItr->more())
9288 const SMDS_MeshEdge* edge = aEdgeItr->next();
9289 if(edge && !edge->IsQuadratic())
9291 int id = edge->GetID();
9292 //MESSAGE("edge->GetID() " << id);
9293 const SMDS_MeshNode* n1 = edge->GetNode(0);
9294 const SMDS_MeshNode* n2 = edge->GetNode(1);
9296 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9298 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9299 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9302 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9303 while(aFaceItr->more())
9305 const SMDS_MeshFace* face = aFaceItr->next();
9306 if(!face || face->IsQuadratic() ) continue;
9308 int id = face->GetID();
9309 int nbNodes = face->NbNodes();
9310 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9312 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9314 SMDS_MeshFace * NewFace = 0;
9318 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9321 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9324 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9326 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9328 vector<int> nbNodeInFaces;
9329 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9330 while(aVolumeItr->more())
9332 const SMDS_MeshVolume* volume = aVolumeItr->next();
9333 if(!volume || volume->IsQuadratic() ) continue;
9335 int id = volume->GetID();
9336 int nbNodes = volume->NbNodes();
9337 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9338 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9339 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9341 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9343 SMDS_MeshVolume * NewVolume = 0;
9347 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9348 nodes[3], id, theForce3d );
9351 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9352 nodes[3], nodes[4], id, theForce3d);
9355 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9356 nodes[3], nodes[4], nodes[5], id, theForce3d);
9359 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9360 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9363 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9365 ReplaceElemInGroups(volume, NewVolume, meshDS);
9369 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9370 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9371 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9372 aHelper.FixQuadraticElements();
9376 //================================================================================
9378 * \brief Makes given elements quadratic
9379 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9380 * \param theElements - elements to make quadratic
9382 //================================================================================
9384 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9385 TIDSortedElemSet& theElements)
9387 if ( theElements.empty() ) return;
9389 // we believe that all theElements are of the same type
9390 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9392 // get all nodes shared by theElements
9393 TIDSortedNodeSet allNodes;
9394 TIDSortedElemSet::iterator eIt = theElements.begin();
9395 for ( ; eIt != theElements.end(); ++eIt )
9396 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9398 // complete theElements with elements of lower dim whose all nodes are in allNodes
9400 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9401 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9402 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9403 for ( ; nIt != allNodes.end(); ++nIt )
9405 const SMDS_MeshNode* n = *nIt;
9406 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9407 while ( invIt->more() )
9409 const SMDS_MeshElement* e = invIt->next();
9410 if ( e->IsQuadratic() )
9412 quadAdjacentElems[ e->GetType() ].insert( e );
9415 if ( e->GetType() >= elemType )
9417 continue; // same type of more complex linear element
9420 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9421 continue; // e is already checked
9425 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9426 while ( nodeIt->more() && allIn )
9427 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9429 theElements.insert(e );
9433 SMESH_MesherHelper helper(*myMesh);
9434 helper.SetIsQuadratic( true );
9436 // add links of quadratic adjacent elements to the helper
9438 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9439 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9440 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9442 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9444 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9445 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9446 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9448 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9450 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9451 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9452 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9454 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9457 // make quadratic elements instead of linear ones
9459 SMESHDS_Mesh* meshDS = GetMeshDS();
9460 SMESHDS_SubMesh* smDS = 0;
9461 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9463 const SMDS_MeshElement* elem = *eIt;
9464 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9467 int id = elem->GetID();
9468 SMDSAbs_ElementType type = elem->GetType();
9469 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9471 if ( !smDS || !smDS->Contains( elem ))
9472 smDS = meshDS->MeshElements( elem->getshapeId() );
9473 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9475 SMDS_MeshElement * newElem = 0;
9476 switch( nodes.size() )
9478 case 4: // cases for most multiple element types go first (for optimization)
9479 if ( type == SMDSAbs_Volume )
9480 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9482 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9485 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9486 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9489 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9492 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9495 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9496 nodes[4], id, theForce3d);
9499 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9500 nodes[4], nodes[5], id, theForce3d);
9504 ReplaceElemInGroups( elem, newElem, meshDS);
9505 if( newElem && smDS )
9506 smDS->AddElement( newElem );
9509 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9510 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9511 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9512 helper.FixQuadraticElements();
9516 //=======================================================================
9518 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9519 * \return int - nb of checked elements
9521 //=======================================================================
9523 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9524 SMDS_ElemIteratorPtr theItr,
9525 const int theShapeID)
9528 SMESHDS_Mesh* meshDS = GetMeshDS();
9530 while( theItr->more() )
9532 const SMDS_MeshElement* elem = theItr->next();
9534 if( elem && elem->IsQuadratic())
9536 int id = elem->GetID();
9537 int nbCornerNodes = elem->NbCornerNodes();
9538 SMDSAbs_ElementType aType = elem->GetType();
9540 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9542 //remove a quadratic element
9543 if ( !theSm || !theSm->Contains( elem ))
9544 theSm = meshDS->MeshElements( elem->getshapeId() );
9545 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9547 // remove medium nodes
9548 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9549 if ( nodes[i]->NbInverseElements() == 0 )
9550 meshDS->RemoveFreeNode( nodes[i], theSm );
9552 // add a linear element
9553 nodes.resize( nbCornerNodes );
9554 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9555 ReplaceElemInGroups(elem, newElem, meshDS);
9556 if( theSm && newElem )
9557 theSm->AddElement( newElem );
9563 //=======================================================================
9564 //function : ConvertFromQuadratic
9566 //=======================================================================
9568 bool SMESH_MeshEditor::ConvertFromQuadratic()
9570 int nbCheckedElems = 0;
9571 if ( myMesh->HasShapeToMesh() )
9573 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9575 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9576 while ( smIt->more() ) {
9577 SMESH_subMesh* sm = smIt->next();
9578 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9579 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9585 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9586 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9588 SMESHDS_SubMesh *aSM = 0;
9589 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9597 //================================================================================
9599 * \brief Return true if all medium nodes of the element are in the node set
9601 //================================================================================
9603 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9605 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9606 if ( !nodeSet.count( elem->GetNode(i) ))
9612 //================================================================================
9614 * \brief Makes given elements linear
9616 //================================================================================
9618 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9620 if ( theElements.empty() ) return;
9622 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9623 set<int> mediumNodeIDs;
9624 TIDSortedElemSet::iterator eIt = theElements.begin();
9625 for ( ; eIt != theElements.end(); ++eIt )
9627 const SMDS_MeshElement* e = *eIt;
9628 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9629 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9632 // replace given elements by linear ones
9633 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9634 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9635 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9637 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9638 // except those elements sharing medium nodes of quadratic element whose medium nodes
9639 // are not all in mediumNodeIDs
9641 // get remaining medium nodes
9642 TIDSortedNodeSet mediumNodes;
9643 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9644 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9645 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9646 mediumNodes.insert( mediumNodes.end(), n );
9648 // find more quadratic elements to convert
9649 TIDSortedElemSet moreElemsToConvert;
9650 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9651 for ( ; nIt != mediumNodes.end(); ++nIt )
9653 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9654 while ( invIt->more() )
9656 const SMDS_MeshElement* e = invIt->next();
9657 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9659 // find a more complex element including e and
9660 // whose medium nodes are not in mediumNodes
9661 bool complexFound = false;
9662 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9664 SMDS_ElemIteratorPtr invIt2 =
9665 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9666 while ( invIt2->more() )
9668 const SMDS_MeshElement* eComplex = invIt2->next();
9669 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9671 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9672 if ( nbCommonNodes == e->NbNodes())
9674 complexFound = true;
9675 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9681 if ( !complexFound )
9682 moreElemsToConvert.insert( e );
9686 elemIt = SMDS_ElemIteratorPtr
9687 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9688 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9691 //=======================================================================
9692 //function : SewSideElements
9694 //=======================================================================
9696 SMESH_MeshEditor::Sew_Error
9697 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9698 TIDSortedElemSet& theSide2,
9699 const SMDS_MeshNode* theFirstNode1,
9700 const SMDS_MeshNode* theFirstNode2,
9701 const SMDS_MeshNode* theSecondNode1,
9702 const SMDS_MeshNode* theSecondNode2)
9704 myLastCreatedElems.Clear();
9705 myLastCreatedNodes.Clear();
9707 MESSAGE ("::::SewSideElements()");
9708 if ( theSide1.size() != theSide2.size() )
9709 return SEW_DIFF_NB_OF_ELEMENTS;
9711 Sew_Error aResult = SEW_OK;
9713 // 1. Build set of faces representing each side
9714 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9715 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9717 // =======================================================================
9718 // 1. Build set of faces representing each side:
9719 // =======================================================================
9720 // a. build set of nodes belonging to faces
9721 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9722 // c. create temporary faces representing side of volumes if correspondent
9723 // face does not exist
9725 SMESHDS_Mesh* aMesh = GetMeshDS();
9726 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9727 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9728 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9729 set<const SMDS_MeshElement*> volSet1, volSet2;
9730 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9731 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9732 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9733 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9734 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9735 int iSide, iFace, iNode;
9737 list<const SMDS_MeshElement* > tempFaceList;
9738 for ( iSide = 0; iSide < 2; iSide++ ) {
9739 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9740 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9741 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9742 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9743 set<const SMDS_MeshElement*>::iterator vIt;
9744 TIDSortedElemSet::iterator eIt;
9745 set<const SMDS_MeshNode*>::iterator nIt;
9747 // check that given nodes belong to given elements
9748 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9749 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9750 int firstIndex = -1, secondIndex = -1;
9751 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9752 const SMDS_MeshElement* elem = *eIt;
9753 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9754 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9755 if ( firstIndex > -1 && secondIndex > -1 ) break;
9757 if ( firstIndex < 0 || secondIndex < 0 ) {
9758 // we can simply return until temporary faces created
9759 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9762 // -----------------------------------------------------------
9763 // 1a. Collect nodes of existing faces
9764 // and build set of face nodes in order to detect missing
9765 // faces corresponding to sides of volumes
9766 // -----------------------------------------------------------
9768 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9770 // loop on the given element of a side
9771 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9772 //const SMDS_MeshElement* elem = *eIt;
9773 const SMDS_MeshElement* elem = *eIt;
9774 if ( elem->GetType() == SMDSAbs_Face ) {
9775 faceSet->insert( elem );
9776 set <const SMDS_MeshNode*> faceNodeSet;
9777 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9778 while ( nodeIt->more() ) {
9779 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9780 nodeSet->insert( n );
9781 faceNodeSet.insert( n );
9783 setOfFaceNodeSet.insert( faceNodeSet );
9785 else if ( elem->GetType() == SMDSAbs_Volume )
9786 volSet->insert( elem );
9788 // ------------------------------------------------------------------------------
9789 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9790 // ------------------------------------------------------------------------------
9792 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9793 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9794 while ( fIt->more() ) { // loop on faces sharing a node
9795 const SMDS_MeshElement* f = fIt->next();
9796 if ( faceSet->find( f ) == faceSet->end() ) {
9797 // check if all nodes are in nodeSet and
9798 // complete setOfFaceNodeSet if they are
9799 set <const SMDS_MeshNode*> faceNodeSet;
9800 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9801 bool allInSet = true;
9802 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9803 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9804 if ( nodeSet->find( n ) == nodeSet->end() )
9807 faceNodeSet.insert( n );
9810 faceSet->insert( f );
9811 setOfFaceNodeSet.insert( faceNodeSet );
9817 // -------------------------------------------------------------------------
9818 // 1c. Create temporary faces representing sides of volumes if correspondent
9819 // face does not exist
9820 // -------------------------------------------------------------------------
9822 if ( !volSet->empty() ) {
9823 //int nodeSetSize = nodeSet->size();
9825 // loop on given volumes
9826 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9827 SMDS_VolumeTool vol (*vIt);
9828 // loop on volume faces: find free faces
9829 // --------------------------------------
9830 list<const SMDS_MeshElement* > freeFaceList;
9831 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9832 if ( !vol.IsFreeFace( iFace ))
9834 // check if there is already a face with same nodes in a face set
9835 const SMDS_MeshElement* aFreeFace = 0;
9836 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9837 int nbNodes = vol.NbFaceNodes( iFace );
9838 set <const SMDS_MeshNode*> faceNodeSet;
9839 vol.GetFaceNodes( iFace, faceNodeSet );
9840 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9842 // no such a face is given but it still can exist, check it
9843 if ( nbNodes == 3 ) {
9844 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9846 else if ( nbNodes == 4 ) {
9847 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9850 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9851 aFreeFace = aMesh->FindFace(poly_nodes);
9855 // create a temporary face
9856 if ( nbNodes == 3 ) {
9857 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9858 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9860 else if ( nbNodes == 4 ) {
9861 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9862 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9865 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9866 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9867 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9871 freeFaceList.push_back( aFreeFace );
9872 tempFaceList.push_back( aFreeFace );
9875 } // loop on faces of a volume
9877 // choose one of several free faces
9878 // --------------------------------------
9879 if ( freeFaceList.size() > 1 ) {
9880 // choose a face having max nb of nodes shared by other elems of a side
9881 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9882 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9883 while ( fIt != freeFaceList.end() ) { // loop on free faces
9884 int nbSharedNodes = 0;
9885 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9886 while ( nodeIt->more() ) { // loop on free face nodes
9887 const SMDS_MeshNode* n =
9888 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9889 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9890 while ( invElemIt->more() ) {
9891 const SMDS_MeshElement* e = invElemIt->next();
9892 if ( faceSet->find( e ) != faceSet->end() )
9894 if ( elemSet->find( e ) != elemSet->end() )
9898 if ( nbSharedNodes >= maxNbNodes ) {
9899 maxNbNodes = nbSharedNodes;
9903 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9905 if ( freeFaceList.size() > 1 )
9907 // could not choose one face, use another way
9908 // choose a face most close to the bary center of the opposite side
9909 gp_XYZ aBC( 0., 0., 0. );
9910 set <const SMDS_MeshNode*> addedNodes;
9911 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9912 eIt = elemSet2->begin();
9913 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9914 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9915 while ( nodeIt->more() ) { // loop on free face nodes
9916 const SMDS_MeshNode* n =
9917 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9918 if ( addedNodes.insert( n ).second )
9919 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9922 aBC /= addedNodes.size();
9923 double minDist = DBL_MAX;
9924 fIt = freeFaceList.begin();
9925 while ( fIt != freeFaceList.end() ) { // loop on free faces
9927 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9928 while ( nodeIt->more() ) { // loop on free face nodes
9929 const SMDS_MeshNode* n =
9930 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9931 gp_XYZ p( n->X(),n->Y(),n->Z() );
9932 dist += ( aBC - p ).SquareModulus();
9934 if ( dist < minDist ) {
9936 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9939 fIt = freeFaceList.erase( fIt++ );
9942 } // choose one of several free faces of a volume
9944 if ( freeFaceList.size() == 1 ) {
9945 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9946 faceSet->insert( aFreeFace );
9947 // complete a node set with nodes of a found free face
9948 // for ( iNode = 0; iNode < ; iNode++ )
9949 // nodeSet->insert( fNodes[ iNode ] );
9952 } // loop on volumes of a side
9954 // // complete a set of faces if new nodes in a nodeSet appeared
9955 // // ----------------------------------------------------------
9956 // if ( nodeSetSize != nodeSet->size() ) {
9957 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9958 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9959 // while ( fIt->more() ) { // loop on faces sharing a node
9960 // const SMDS_MeshElement* f = fIt->next();
9961 // if ( faceSet->find( f ) == faceSet->end() ) {
9962 // // check if all nodes are in nodeSet and
9963 // // complete setOfFaceNodeSet if they are
9964 // set <const SMDS_MeshNode*> faceNodeSet;
9965 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9966 // bool allInSet = true;
9967 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9968 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9969 // if ( nodeSet->find( n ) == nodeSet->end() )
9970 // allInSet = false;
9972 // faceNodeSet.insert( n );
9974 // if ( allInSet ) {
9975 // faceSet->insert( f );
9976 // setOfFaceNodeSet.insert( faceNodeSet );
9982 } // Create temporary faces, if there are volumes given
9985 if ( faceSet1.size() != faceSet2.size() ) {
9986 // delete temporary faces: they are in reverseElements of actual nodes
9987 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
9988 // while ( tmpFaceIt->more() )
9989 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
9990 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
9991 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
9992 // aMesh->RemoveElement(*tmpFaceIt);
9993 MESSAGE("Diff nb of faces");
9994 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
9997 // ============================================================
9998 // 2. Find nodes to merge:
9999 // bind a node to remove to a node to put instead
10000 // ============================================================
10002 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10003 if ( theFirstNode1 != theFirstNode2 )
10004 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10005 if ( theSecondNode1 != theSecondNode2 )
10006 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10008 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10009 set< long > linkIdSet; // links to process
10010 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10012 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10013 list< NLink > linkList[2];
10014 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10015 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10016 // loop on links in linkList; find faces by links and append links
10017 // of the found faces to linkList
10018 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10019 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10020 NLink link[] = { *linkIt[0], *linkIt[1] };
10021 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10022 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10025 // by links, find faces in the face sets,
10026 // and find indices of link nodes in the found faces;
10027 // in a face set, there is only one or no face sharing a link
10028 // ---------------------------------------------------------------
10030 const SMDS_MeshElement* face[] = { 0, 0 };
10031 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10032 vector<const SMDS_MeshNode*> fnodes1(9);
10033 vector<const SMDS_MeshNode*> fnodes2(9);
10034 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10035 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10036 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10037 int iLinkNode[2][2];
10038 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10039 const SMDS_MeshNode* n1 = link[iSide].first;
10040 const SMDS_MeshNode* n2 = link[iSide].second;
10041 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10042 set< const SMDS_MeshElement* > fMap;
10043 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10044 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10045 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10046 while ( fIt->more() ) { // loop on faces sharing a node
10047 const SMDS_MeshElement* f = fIt->next();
10048 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10049 ! fMap.insert( f ).second ) // f encounters twice
10051 if ( face[ iSide ] ) {
10052 MESSAGE( "2 faces per link " );
10053 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10057 faceSet->erase( f );
10058 // get face nodes and find ones of a link
10063 fnodes1.resize(f->NbNodes()+1);
10064 notLinkNodes1.resize(f->NbNodes()-2);
10067 fnodes2.resize(f->NbNodes()+1);
10068 notLinkNodes2.resize(f->NbNodes()-2);
10071 if(!f->IsQuadratic()) {
10072 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10073 while ( nIt->more() ) {
10074 const SMDS_MeshNode* n =
10075 static_cast<const SMDS_MeshNode*>( nIt->next() );
10077 iLinkNode[ iSide ][ 0 ] = iNode;
10079 else if ( n == n2 ) {
10080 iLinkNode[ iSide ][ 1 ] = iNode;
10082 //else if ( notLinkNodes[ iSide ][ 0 ] )
10083 // notLinkNodes[ iSide ][ 1 ] = n;
10085 // notLinkNodes[ iSide ][ 0 ] = n;
10089 notLinkNodes1[nbl] = n;
10090 //notLinkNodes1.push_back(n);
10092 notLinkNodes2[nbl] = n;
10093 //notLinkNodes2.push_back(n);
10095 //faceNodes[ iSide ][ iNode++ ] = n;
10097 fnodes1[iNode++] = n;
10100 fnodes2[iNode++] = n;
10104 else { // f->IsQuadratic()
10105 const SMDS_VtkFace* F =
10106 dynamic_cast<const SMDS_VtkFace*>(f);
10107 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10108 // use special nodes iterator
10109 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10110 while ( anIter->more() ) {
10111 const SMDS_MeshNode* n =
10112 static_cast<const SMDS_MeshNode*>( anIter->next() );
10114 iLinkNode[ iSide ][ 0 ] = iNode;
10116 else if ( n == n2 ) {
10117 iLinkNode[ iSide ][ 1 ] = iNode;
10122 notLinkNodes1[nbl] = n;
10125 notLinkNodes2[nbl] = n;
10129 fnodes1[iNode++] = n;
10132 fnodes2[iNode++] = n;
10136 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10138 fnodes1[iNode] = fnodes1[0];
10141 fnodes2[iNode] = fnodes1[0];
10148 // check similarity of elements of the sides
10149 if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
10150 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10151 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10152 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10155 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10157 break; // do not return because it s necessary to remove tmp faces
10160 // set nodes to merge
10161 // -------------------
10163 if ( face[0] && face[1] ) {
10164 int nbNodes = face[0]->NbNodes();
10165 if ( nbNodes != face[1]->NbNodes() ) {
10166 MESSAGE("Diff nb of face nodes");
10167 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10168 break; // do not return because it s necessary to remove tmp faces
10170 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10171 if ( nbNodes == 3 ) {
10172 //nReplaceMap.insert( TNodeNodeMap::value_type
10173 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10174 nReplaceMap.insert( TNodeNodeMap::value_type
10175 ( notLinkNodes1[0], notLinkNodes2[0] ));
10178 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10179 // analyse link orientation in faces
10180 int i1 = iLinkNode[ iSide ][ 0 ];
10181 int i2 = iLinkNode[ iSide ][ 1 ];
10182 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10183 // if notLinkNodes are the first and the last ones, then
10184 // their order does not correspond to the link orientation
10185 if (( i1 == 1 && i2 == 2 ) ||
10186 ( i1 == 2 && i2 == 1 ))
10187 reverse[ iSide ] = !reverse[ iSide ];
10189 if ( reverse[0] == reverse[1] ) {
10190 //nReplaceMap.insert( TNodeNodeMap::value_type
10191 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10192 //nReplaceMap.insert( TNodeNodeMap::value_type
10193 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10194 for(int nn=0; nn<nbNodes-2; nn++) {
10195 nReplaceMap.insert( TNodeNodeMap::value_type
10196 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10200 //nReplaceMap.insert( TNodeNodeMap::value_type
10201 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10202 //nReplaceMap.insert( TNodeNodeMap::value_type
10203 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10204 for(int nn=0; nn<nbNodes-2; nn++) {
10205 nReplaceMap.insert( TNodeNodeMap::value_type
10206 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10211 // add other links of the faces to linkList
10212 // -----------------------------------------
10214 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10215 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10216 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10217 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10218 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10219 if ( !iter_isnew.second ) { // already in a set: no need to process
10220 linkIdSet.erase( iter_isnew.first );
10222 else // new in set == encountered for the first time: add
10224 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10225 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10226 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10227 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10228 linkList[0].push_back ( NLink( n1, n2 ));
10229 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10233 } // loop on link lists
10235 if ( aResult == SEW_OK &&
10236 ( linkIt[0] != linkList[0].end() ||
10237 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10238 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10239 " " << (faceSetPtr[1]->empty()));
10240 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10243 // ====================================================================
10244 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10245 // ====================================================================
10247 // delete temporary faces: they are in reverseElements of actual nodes
10248 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10249 // while ( tmpFaceIt->more() )
10250 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10251 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10252 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10253 // aMesh->RemoveElement(*tmpFaceIt);
10255 if ( aResult != SEW_OK)
10258 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10259 // loop on nodes replacement map
10260 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10261 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10262 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10263 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10264 nodeIDsToRemove.push_back( nToRemove->GetID() );
10265 // loop on elements sharing nToRemove
10266 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10267 while ( invElemIt->more() ) {
10268 const SMDS_MeshElement* e = invElemIt->next();
10269 // get a new suite of nodes: make replacement
10270 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10271 vector< const SMDS_MeshNode*> nodes( nbNodes );
10272 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10273 while ( nIt->more() ) {
10274 const SMDS_MeshNode* n =
10275 static_cast<const SMDS_MeshNode*>( nIt->next() );
10276 nnIt = nReplaceMap.find( n );
10277 if ( nnIt != nReplaceMap.end() ) {
10279 n = (*nnIt).second;
10283 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10284 // elemIDsToRemove.push_back( e->GetID() );
10288 SMDSAbs_ElementType etyp = e->GetType();
10289 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10292 myLastCreatedElems.Append(newElem);
10293 AddToSameGroups(newElem, e, aMesh);
10294 int aShapeId = e->getshapeId();
10297 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10300 aMesh->RemoveElement(e);
10305 Remove( nodeIDsToRemove, true );
10310 //================================================================================
10312 * \brief Find corresponding nodes in two sets of faces
10313 * \param theSide1 - first face set
10314 * \param theSide2 - second first face
10315 * \param theFirstNode1 - a boundary node of set 1
10316 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10317 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10318 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10319 * \param nReplaceMap - output map of corresponding nodes
10320 * \return bool - is a success or not
10322 //================================================================================
10325 //#define DEBUG_MATCHING_NODES
10328 SMESH_MeshEditor::Sew_Error
10329 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10330 set<const SMDS_MeshElement*>& theSide2,
10331 const SMDS_MeshNode* theFirstNode1,
10332 const SMDS_MeshNode* theFirstNode2,
10333 const SMDS_MeshNode* theSecondNode1,
10334 const SMDS_MeshNode* theSecondNode2,
10335 TNodeNodeMap & nReplaceMap)
10337 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10339 nReplaceMap.clear();
10340 if ( theFirstNode1 != theFirstNode2 )
10341 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10342 if ( theSecondNode1 != theSecondNode2 )
10343 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10345 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10346 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10348 list< NLink > linkList[2];
10349 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10350 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10352 // loop on links in linkList; find faces by links and append links
10353 // of the found faces to linkList
10354 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10355 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10356 NLink link[] = { *linkIt[0], *linkIt[1] };
10357 if ( linkSet.find( link[0] ) == linkSet.end() )
10360 // by links, find faces in the face sets,
10361 // and find indices of link nodes in the found faces;
10362 // in a face set, there is only one or no face sharing a link
10363 // ---------------------------------------------------------------
10365 const SMDS_MeshElement* face[] = { 0, 0 };
10366 list<const SMDS_MeshNode*> notLinkNodes[2];
10367 //bool reverse[] = { false, false }; // order of notLinkNodes
10369 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10371 const SMDS_MeshNode* n1 = link[iSide].first;
10372 const SMDS_MeshNode* n2 = link[iSide].second;
10373 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10374 set< const SMDS_MeshElement* > facesOfNode1;
10375 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10377 // during a loop of the first node, we find all faces around n1,
10378 // during a loop of the second node, we find one face sharing both n1 and n2
10379 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10380 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10381 while ( fIt->more() ) { // loop on faces sharing a node
10382 const SMDS_MeshElement* f = fIt->next();
10383 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10384 ! facesOfNode1.insert( f ).second ) // f encounters twice
10386 if ( face[ iSide ] ) {
10387 MESSAGE( "2 faces per link " );
10388 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10391 faceSet->erase( f );
10393 // get not link nodes
10394 int nbN = f->NbNodes();
10395 if ( f->IsQuadratic() )
10397 nbNodes[ iSide ] = nbN;
10398 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10399 int i1 = f->GetNodeIndex( n1 );
10400 int i2 = f->GetNodeIndex( n2 );
10401 int iEnd = nbN, iBeg = -1, iDelta = 1;
10402 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10404 std::swap( iEnd, iBeg ); iDelta = -1;
10409 if ( i == iEnd ) i = iBeg + iDelta;
10410 if ( i == i1 ) break;
10411 nodes.push_back ( f->GetNode( i ) );
10417 // check similarity of elements of the sides
10418 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10419 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10420 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10421 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10424 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10428 // set nodes to merge
10429 // -------------------
10431 if ( face[0] && face[1] ) {
10432 if ( nbNodes[0] != nbNodes[1] ) {
10433 MESSAGE("Diff nb of face nodes");
10434 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10436 #ifdef DEBUG_MATCHING_NODES
10437 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10438 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10439 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10441 int nbN = nbNodes[0];
10443 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10444 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10445 for ( int i = 0 ; i < nbN - 2; ++i ) {
10446 #ifdef DEBUG_MATCHING_NODES
10447 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10449 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10453 // add other links of the face 1 to linkList
10454 // -----------------------------------------
10456 const SMDS_MeshElement* f0 = face[0];
10457 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10458 for ( int i = 0; i < nbN; i++ )
10460 const SMDS_MeshNode* n2 = f0->GetNode( i );
10461 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10462 linkSet.insert( SMESH_TLink( n1, n2 ));
10463 if ( !iter_isnew.second ) { // already in a set: no need to process
10464 linkSet.erase( iter_isnew.first );
10466 else // new in set == encountered for the first time: add
10468 #ifdef DEBUG_MATCHING_NODES
10469 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10470 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10472 linkList[0].push_back ( NLink( n1, n2 ));
10473 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10478 } // loop on link lists
10483 //================================================================================
10485 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10486 \param theElems - the list of elements (edges or faces) to be replicated
10487 The nodes for duplication could be found from these elements
10488 \param theNodesNot - list of nodes to NOT replicate
10489 \param theAffectedElems - the list of elements (cells and edges) to which the
10490 replicated nodes should be associated to.
10491 \return TRUE if operation has been completed successfully, FALSE otherwise
10493 //================================================================================
10495 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10496 const TIDSortedElemSet& theNodesNot,
10497 const TIDSortedElemSet& theAffectedElems )
10499 myLastCreatedElems.Clear();
10500 myLastCreatedNodes.Clear();
10502 if ( theElems.size() == 0 )
10505 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10510 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10511 // duplicate elements and nodes
10512 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10513 // replce nodes by duplications
10514 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10518 //================================================================================
10520 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10521 \param theMeshDS - mesh instance
10522 \param theElems - the elements replicated or modified (nodes should be changed)
10523 \param theNodesNot - nodes to NOT replicate
10524 \param theNodeNodeMap - relation of old node to new created node
10525 \param theIsDoubleElem - flag os to replicate element or modify
10526 \return TRUE if operation has been completed successfully, FALSE otherwise
10528 //================================================================================
10530 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10531 const TIDSortedElemSet& theElems,
10532 const TIDSortedElemSet& theNodesNot,
10533 std::map< const SMDS_MeshNode*,
10534 const SMDS_MeshNode* >& theNodeNodeMap,
10535 const bool theIsDoubleElem )
10537 MESSAGE("doubleNodes");
10538 // iterate on through element and duplicate them (by nodes duplication)
10540 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10541 for ( ; elemItr != theElems.end(); ++elemItr )
10543 const SMDS_MeshElement* anElem = *elemItr;
10547 bool isDuplicate = false;
10548 // duplicate nodes to duplicate element
10549 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10550 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10552 while ( anIter->more() )
10555 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10556 SMDS_MeshNode* aNewNode = aCurrNode;
10557 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10558 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10559 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10562 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10563 theNodeNodeMap[ aCurrNode ] = aNewNode;
10564 myLastCreatedNodes.Append( aNewNode );
10566 isDuplicate |= (aCurrNode != aNewNode);
10567 newNodes[ ind++ ] = aNewNode;
10569 if ( !isDuplicate )
10572 if ( theIsDoubleElem )
10573 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10576 MESSAGE("ChangeElementNodes");
10577 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10584 //================================================================================
10586 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10587 \param theNodes - identifiers of nodes to be doubled
10588 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10589 nodes. If list of element identifiers is empty then nodes are doubled but
10590 they not assigned to elements
10591 \return TRUE if operation has been completed successfully, FALSE otherwise
10593 //================================================================================
10595 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10596 const std::list< int >& theListOfModifiedElems )
10598 MESSAGE("DoubleNodes");
10599 myLastCreatedElems.Clear();
10600 myLastCreatedNodes.Clear();
10602 if ( theListOfNodes.size() == 0 )
10605 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10609 // iterate through nodes and duplicate them
10611 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10613 std::list< int >::const_iterator aNodeIter;
10614 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10616 int aCurr = *aNodeIter;
10617 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10623 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10626 anOldNodeToNewNode[ aNode ] = aNewNode;
10627 myLastCreatedNodes.Append( aNewNode );
10631 // Create map of new nodes for modified elements
10633 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10635 std::list< int >::const_iterator anElemIter;
10636 for ( anElemIter = theListOfModifiedElems.begin();
10637 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10639 int aCurr = *anElemIter;
10640 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10644 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10646 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10648 while ( anIter->more() )
10650 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10651 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10653 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10654 aNodeArr[ ind++ ] = aNewNode;
10657 aNodeArr[ ind++ ] = aCurrNode;
10659 anElemToNodes[ anElem ] = aNodeArr;
10662 // Change nodes of elements
10664 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10665 anElemToNodesIter = anElemToNodes.begin();
10666 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10668 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10669 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10672 MESSAGE("ChangeElementNodes");
10673 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10682 //================================================================================
10684 \brief Check if element located inside shape
10685 \return TRUE if IN or ON shape, FALSE otherwise
10687 //================================================================================
10689 template<class Classifier>
10690 bool isInside(const SMDS_MeshElement* theElem,
10691 Classifier& theClassifier,
10692 const double theTol)
10694 gp_XYZ centerXYZ (0, 0, 0);
10695 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10696 while (aNodeItr->more())
10697 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10699 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10700 theClassifier.Perform(aPnt, theTol);
10701 TopAbs_State aState = theClassifier.State();
10702 return (aState == TopAbs_IN || aState == TopAbs_ON );
10705 //================================================================================
10707 * \brief Classifier of the 3D point on the TopoDS_Face
10708 * with interaface suitable for isInside()
10710 //================================================================================
10712 struct _FaceClassifier
10714 Extrema_ExtPS _extremum;
10715 BRepAdaptor_Surface _surface;
10716 TopAbs_State _state;
10718 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10720 _extremum.Initialize( _surface,
10721 _surface.FirstUParameter(), _surface.LastUParameter(),
10722 _surface.FirstVParameter(), _surface.LastVParameter(),
10723 _surface.Tolerance(), _surface.Tolerance() );
10725 void Perform(const gp_Pnt& aPnt, double theTol)
10727 _state = TopAbs_OUT;
10728 _extremum.Perform(aPnt);
10729 if ( _extremum.IsDone() )
10730 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10731 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10733 TopAbs_State State() const
10740 //================================================================================
10742 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10743 \param theElems - group of of elements (edges or faces) to be replicated
10744 \param theNodesNot - group of nodes not to replicate
10745 \param theShape - shape to detect affected elements (element which geometric center
10746 located on or inside shape).
10747 The replicated nodes should be associated to affected elements.
10748 \return TRUE if operation has been completed successfully, FALSE otherwise
10750 //================================================================================
10752 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10753 const TIDSortedElemSet& theNodesNot,
10754 const TopoDS_Shape& theShape )
10756 if ( theShape.IsNull() )
10759 const double aTol = Precision::Confusion();
10760 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10761 auto_ptr<_FaceClassifier> aFaceClassifier;
10762 if ( theShape.ShapeType() == TopAbs_SOLID )
10764 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10765 bsc3d->PerformInfinitePoint(aTol);
10767 else if (theShape.ShapeType() == TopAbs_FACE )
10769 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10772 // iterates on indicated elements and get elements by back references from their nodes
10773 TIDSortedElemSet anAffected;
10774 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10775 for ( ; elemItr != theElems.end(); ++elemItr )
10777 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10781 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10782 while ( nodeItr->more() )
10784 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10785 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10787 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10788 while ( backElemItr->more() )
10790 const SMDS_MeshElement* curElem = backElemItr->next();
10791 if ( curElem && theElems.find(curElem) == theElems.end() &&
10793 isInside( curElem, *bsc3d, aTol ) :
10794 isInside( curElem, *aFaceClassifier, aTol )))
10795 anAffected.insert( curElem );
10799 return DoubleNodes( theElems, theNodesNot, anAffected );
10803 * \brief compute an oriented angle between two planes defined by four points.
10804 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10805 * @param p0 base of the rotation axe
10806 * @param p1 extremity of the rotation axe
10807 * @param g1 belongs to the first plane
10808 * @param g2 belongs to the second plane
10810 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10812 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10813 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10814 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10815 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10816 gp_Vec vref(p0, p1);
10819 gp_Vec n1 = vref.Crossed(v1);
10820 gp_Vec n2 = vref.Crossed(v2);
10821 return n2.AngleWithRef(n1, vref);
10825 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10826 * The list of groups must describe a partition of the mesh volumes.
10827 * The nodes of the internal faces at the boundaries of the groups are doubled.
10828 * In option, the internal faces are replaced by flat elements.
10829 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10830 * The flat elements are stored in groups of volumes.
10831 * @param theElems - list of groups of volumes, where a group of volume is a set of
10832 * SMDS_MeshElements sorted by Id.
10833 * @param createJointElems - if TRUE, create the elements
10834 * @return TRUE if operation has been completed successfully, FALSE otherwise
10836 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10837 bool createJointElems)
10839 MESSAGE("----------------------------------------------");
10840 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10841 MESSAGE("----------------------------------------------");
10843 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10844 meshDS->BuildDownWardConnectivity(true);
10846 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10848 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10849 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10850 // build the list of nodes shared by 2 or more domains, with their domain indexes
10852 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10853 std::map<int,int>celldom; // cell vtkId --> domain
10854 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10855 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10856 faceDomains.clear();
10858 cellDomains.clear();
10859 nodeDomains.clear();
10860 std::map<int,int> emptyMap;
10861 std::set<int> emptySet;
10864 for (int idom = 0; idom < theElems.size(); idom++)
10867 // --- build a map (face to duplicate --> volume to modify)
10868 // with all the faces shared by 2 domains (group of elements)
10869 // and corresponding volume of this domain, for each shared face.
10870 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10872 const TIDSortedElemSet& domain = theElems[idom];
10873 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10874 for (; elemItr != domain.end(); ++elemItr)
10876 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10879 int vtkId = anElem->getVtkId();
10880 int neighborsVtkIds[NBMAXNEIGHBORS];
10881 int downIds[NBMAXNEIGHBORS];
10882 unsigned char downTypes[NBMAXNEIGHBORS];
10883 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10884 for (int n = 0; n < nbNeighbors; n++)
10886 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10887 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10888 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10890 DownIdType face(downIds[n], downTypes[n]);
10891 if (!faceDomains.count(face))
10892 faceDomains[face] = emptyMap; // create an empty entry for face
10893 if (!faceDomains[face].count(idom))
10895 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10896 celldom[vtkId] = idom;
10903 //MESSAGE("Number of shared faces " << faceDomains.size());
10904 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10906 // --- explore the shared faces domain by domain,
10907 // explore the nodes of the face and see if they belong to a cell in the domain,
10908 // which has only a node or an edge on the border (not a shared face)
10910 for (int idomain = 0; idomain < theElems.size(); idomain++)
10912 const TIDSortedElemSet& domain = theElems[idomain];
10913 itface = faceDomains.begin();
10914 for (; itface != faceDomains.end(); ++itface)
10916 std::map<int, int> domvol = itface->second;
10917 if (!domvol.count(idomain))
10919 DownIdType face = itface->first;
10920 //MESSAGE(" --- face " << face.cellId);
10921 std::set<int> oldNodes;
10923 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10924 std::set<int>::iterator itn = oldNodes.begin();
10925 for (; itn != oldNodes.end(); ++itn)
10928 //MESSAGE(" node " << oldId);
10929 std::set<int> cells;
10931 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10932 for (int i=0; i<l.ncells; i++)
10934 int vtkId = l.cells[i];
10935 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10936 if (!domain.count(anElem))
10938 int vtkType = grid->GetCellType(vtkId);
10939 int downId = grid->CellIdToDownId(vtkId);
10942 MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
10943 continue; // not OK at this stage of the algorithm:
10944 //no cells created after BuildDownWardConnectivity
10946 DownIdType aCell(downId, vtkType);
10947 if (celldom.count(vtkId))
10949 cellDomains[aCell][idomain] = vtkId;
10950 celldom[vtkId] = idomain;
10956 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10957 // for each shared face, get the nodes
10958 // for each node, for each domain of the face, create a clone of the node
10960 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10961 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10962 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10964 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10965 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10967 for (int idomain = 0; idomain < theElems.size(); idomain++)
10969 itface = faceDomains.begin();
10970 for (; itface != faceDomains.end(); ++itface)
10972 std::map<int, int> domvol = itface->second;
10973 if (!domvol.count(idomain))
10975 DownIdType face = itface->first;
10976 //MESSAGE(" --- face " << face.cellId);
10977 std::set<int> oldNodes;
10979 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10980 bool isMultipleDetected = false;
10981 std::set<int>::iterator itn = oldNodes.begin();
10982 for (; itn != oldNodes.end(); ++itn)
10985 //MESSAGE(" node " << oldId);
10986 if (!nodeDomains.count(oldId))
10987 nodeDomains[oldId] = emptyMap; // create an empty entry for node
10988 if (nodeDomains[oldId].empty())
10989 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
10990 std::map<int, int>::iterator itdom = domvol.begin();
10991 for (; itdom != domvol.end(); ++itdom)
10993 int idom = itdom->first;
10994 //MESSAGE(" domain " << idom);
10995 if (!nodeDomains[oldId].count(idom)) // --- node to clone
10997 if (nodeDomains[oldId].size() >= 2) // a multiple node
10999 vector<int> orderedDoms;
11000 //MESSAGE("multiple node " << oldId);
11001 isMultipleDetected =true;
11002 if (mutipleNodes.count(oldId))
11003 orderedDoms = mutipleNodes[oldId];
11006 map<int,int>::iterator it = nodeDomains[oldId].begin();
11007 for (; it != nodeDomains[oldId].end(); ++it)
11008 orderedDoms.push_back(it->first);
11010 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11011 //stringstream txt;
11012 //for (int i=0; i<orderedDoms.size(); i++)
11013 // txt << orderedDoms[i] << " ";
11014 //MESSAGE("orderedDoms " << txt.str());
11015 mutipleNodes[oldId] = orderedDoms;
11017 double *coords = grid->GetPoint(oldId);
11018 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11019 int newId = newNode->getVtkId();
11020 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11021 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11023 if (nodeDomains[oldId].size() >= 3)
11025 //MESSAGE("confirm multiple node " << oldId);
11026 isMultipleDetected =true;
11030 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11032 //MESSAGE("multiple Nodes detected on a shared face");
11033 int downId = itface->first.cellId;
11034 unsigned char cellType = itface->first.cellType;
11035 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11036 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11037 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11038 for (int ie =0; ie < nbEdges; ie++)
11041 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11042 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11044 vector<int> vn0 = mutipleNodes[nodes[0]];
11045 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11046 sort( vn0.begin(), vn0.end() );
11047 sort( vn1.begin(), vn1.end() );
11050 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11051 double *coords = grid->GetPoint(nodes[0]);
11052 gp_Pnt p0(coords[0], coords[1], coords[2]);
11053 coords = grid->GetPoint(nodes[nbNodes - 1]);
11054 gp_Pnt p1(coords[0], coords[1], coords[2]);
11056 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11057 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11058 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11059 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11060 for (int id=0; id < vn0.size(); id++)
11062 int idom = vn0[id];
11063 for (int ivol=0; ivol<nbvol; ivol++)
11065 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11066 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11067 if (theElems[idom].count(elem))
11069 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11070 domvol[idom] = svol;
11071 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11073 vtkIdType npts = 0;
11074 vtkIdType* pts = 0;
11075 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11076 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11079 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11080 angleDom[idom] = 0;
11084 gp_Pnt g(values[0], values[1], values[2]);
11085 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11086 //MESSAGE(" angle=" << angleDom[idom]);
11092 map<double, int> sortedDom; // sort domains by angle
11093 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11094 sortedDom[ia->second] = ia->first;
11095 vector<int> vnodes;
11097 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11099 vdom.push_back(ib->second);
11100 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11102 for (int ino = 0; ino < nbNodes; ino++)
11103 vnodes.push_back(nodes[ino]);
11104 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11112 // --- iterate on shared faces (volumes to modify, face to extrude)
11113 // get node id's of the face (id SMDS = id VTK)
11114 // create flat element with old and new nodes if requested
11116 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11117 // (domain1 X domain2) = domain1 + MAXINT*domain2
11119 std::map<int, std::map<long,int> > nodeQuadDomains;
11120 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11122 if (createJointElems)
11124 itface = faceDomains.begin();
11125 for (; itface != faceDomains.end(); ++itface)
11127 DownIdType face = itface->first;
11128 std::set<int> oldNodes;
11129 std::set<int>::iterator itn;
11131 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11133 std::map<int, int> domvol = itface->second;
11134 std::map<int, int>::iterator itdom = domvol.begin();
11135 int dom1 = itdom->first;
11136 int vtkVolId = itdom->second;
11138 int dom2 = itdom->first;
11139 SMDS_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
11141 stringstream grpname;
11144 grpname << dom1 << "_" << dom2;
11146 grpname << dom2 << "_" << dom1;
11148 string namegrp = grpname.str();
11149 if (!mapOfJunctionGroups.count(namegrp))
11150 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11151 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11153 sgrp->Add(vol->GetID());
11157 // --- create volumes on multiple domain intersection if requested
11158 // iterate on edgesMultiDomains
11160 if (createJointElems)
11162 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11163 for (; ite != edgesMultiDomains.end(); ++ite)
11165 vector<int> nodes = ite->first;
11166 vector<int> orderDom = ite->second;
11167 vector<vtkIdType> orderedNodes;
11168 if (nodes.size() == 2)
11170 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11171 for (int ino=0; ino < nodes.size(); ino++)
11172 if (orderDom.size() == 3)
11173 for (int idom = 0; idom <orderDom.size(); idom++)
11174 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11176 for (int idom = orderDom.size()-1; idom >=0; idom--)
11177 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11178 SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11180 stringstream grpname;
11182 grpname << 0 << "_" << 0;
11184 string namegrp = grpname.str();
11185 if (!mapOfJunctionGroups.count(namegrp))
11186 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11187 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11189 sgrp->Add(vol->GetID());
11193 //MESSAGE("Quadratic multiple joints not implemented");
11194 // TODO quadratic nodes
11199 // --- list the explicit faces and edges of the mesh that need to be modified,
11200 // i.e. faces and edges built with one or more duplicated nodes.
11201 // associate these faces or edges to their corresponding domain.
11202 // only the first domain found is kept when a face or edge is shared
11204 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11205 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11206 faceOrEdgeDom.clear();
11209 for (int idomain = 0; idomain < theElems.size(); idomain++)
11211 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11212 for (; itnod != nodeDomains.end(); ++itnod)
11214 int oldId = itnod->first;
11215 //MESSAGE(" node " << oldId);
11216 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11217 for (int i = 0; i < l.ncells; i++)
11219 int vtkId = l.cells[i];
11220 int vtkType = grid->GetCellType(vtkId);
11221 int downId = grid->CellIdToDownId(vtkId);
11223 continue; // new cells: not to be modified
11224 DownIdType aCell(downId, vtkType);
11225 int volParents[1000];
11226 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11227 for (int j = 0; j < nbvol; j++)
11228 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11229 if (!feDom.count(vtkId))
11231 feDom[vtkId] = idomain;
11232 faceOrEdgeDom[aCell] = emptyMap;
11233 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11234 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11235 // << " type " << vtkType << " downId " << downId);
11241 // --- iterate on shared faces (volumes to modify, face to extrude)
11242 // get node id's of the face
11243 // replace old nodes by new nodes in volumes, and update inverse connectivity
11245 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11246 for (int m=0; m<3; m++)
11248 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11249 itface = (*amap).begin();
11250 for (; itface != (*amap).end(); ++itface)
11252 DownIdType face = itface->first;
11253 std::set<int> oldNodes;
11254 std::set<int>::iterator itn;
11256 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11257 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11258 std::map<int, int> localClonedNodeIds;
11260 std::map<int, int> domvol = itface->second;
11261 std::map<int, int>::iterator itdom = domvol.begin();
11262 for (; itdom != domvol.end(); ++itdom)
11264 int idom = itdom->first;
11265 int vtkVolId = itdom->second;
11266 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11267 localClonedNodeIds.clear();
11268 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11271 if (nodeDomains[oldId].count(idom))
11273 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11274 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11277 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11282 meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
11283 grid->BuildLinks();
11291 * \brief Double nodes on some external faces and create flat elements.
11292 * Flat elements are mainly used by some types of mechanic calculations.
11294 * Each group of the list must be constituted of faces.
11295 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
11296 * @param theElems - list of groups of faces, where a group of faces is a set of
11297 * SMDS_MeshElements sorted by Id.
11298 * @return TRUE if operation has been completed successfully, FALSE otherwise
11300 bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
11302 MESSAGE("-------------------------------------------------");
11303 MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
11304 MESSAGE("-------------------------------------------------");
11306 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
11308 // --- For each group of faces
11309 // duplicate the nodes, create a flat element based on the face
11310 // replace the nodes of the faces by their clones
11312 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
11313 std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
11314 clonedNodes.clear();
11315 intermediateNodes.clear();
11316 std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
11317 mapOfJunctionGroups.clear();
11319 for (int idom = 0; idom < theElems.size(); idom++)
11321 const TIDSortedElemSet& domain = theElems[idom];
11322 TIDSortedElemSet::const_iterator elemItr = domain.begin();
11323 for (; elemItr != domain.end(); ++elemItr)
11325 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
11326 SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
11329 // MESSAGE("aFace=" << aFace->GetID());
11330 bool isQuad = aFace->IsQuadratic();
11331 vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
11333 // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
11335 SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
11336 while (nodeIt->more())
11338 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
11339 bool isMedium = isQuad && (aFace->IsMediumNode(node));
11341 ln2.push_back(node);
11343 ln0.push_back(node);
11345 const SMDS_MeshNode* clone = 0;
11346 if (!clonedNodes.count(node))
11348 clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
11349 clonedNodes[node] = clone;
11352 clone = clonedNodes[node];
11355 ln3.push_back(clone);
11357 ln1.push_back(clone);
11359 const SMDS_MeshNode* inter = 0;
11360 if (isQuad && (!isMedium))
11362 if (!intermediateNodes.count(node))
11364 inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
11365 intermediateNodes[node] = inter;
11368 inter = intermediateNodes[node];
11369 ln4.push_back(inter);
11373 // --- extrude the face
11375 vector<const SMDS_MeshNode*> ln;
11376 SMDS_MeshVolume* vol = 0;
11377 vtkIdType aType = aFace->GetVtkType();
11381 vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
11382 // MESSAGE("vol prism " << vol->GetID());
11383 ln.push_back(ln1[0]);
11384 ln.push_back(ln1[1]);
11385 ln.push_back(ln1[2]);
11388 vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
11389 // MESSAGE("vol hexa " << vol->GetID());
11390 ln.push_back(ln1[0]);
11391 ln.push_back(ln1[1]);
11392 ln.push_back(ln1[2]);
11393 ln.push_back(ln1[3]);
11395 case VTK_QUADRATIC_TRIANGLE:
11396 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
11397 ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
11398 // MESSAGE("vol quad prism " << vol->GetID());
11399 ln.push_back(ln1[0]);
11400 ln.push_back(ln1[1]);
11401 ln.push_back(ln1[2]);
11402 ln.push_back(ln3[0]);
11403 ln.push_back(ln3[1]);
11404 ln.push_back(ln3[2]);
11406 case VTK_QUADRATIC_QUAD:
11407 // vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
11408 // ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
11409 // ln4[0], ln4[1], ln4[2], ln4[3]);
11410 vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
11411 ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
11412 ln4[0], ln4[1], ln4[2], ln4[3]);
11413 // MESSAGE("vol quad hexa " << vol->GetID());
11414 ln.push_back(ln1[0]);
11415 ln.push_back(ln1[1]);
11416 ln.push_back(ln1[2]);
11417 ln.push_back(ln1[3]);
11418 ln.push_back(ln3[0]);
11419 ln.push_back(ln3[1]);
11420 ln.push_back(ln3[2]);
11421 ln.push_back(ln3[3]);
11431 stringstream grpname;
11435 string namegrp = grpname.str();
11436 if (!mapOfJunctionGroups.count(namegrp))
11437 mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
11438 SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
11440 sgrp->Add(vol->GetID());
11443 // --- modify the face
11445 aFace->ChangeNodes(&ln[0], ln.size());
11451 //================================================================================
11453 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11454 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11455 * \return TRUE if operation has been completed successfully, FALSE otherwise
11457 //================================================================================
11459 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11461 // iterates on volume elements and detect all free faces on them
11462 SMESHDS_Mesh* aMesh = GetMeshDS();
11465 //bool res = false;
11466 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11467 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11470 const SMDS_MeshVolume* volume = vIt->next();
11471 SMDS_VolumeTool vTool( volume );
11472 vTool.SetExternalNormal();
11473 const bool isPoly = volume->IsPoly();
11474 const bool isQuad = volume->IsQuadratic();
11475 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11477 if (!vTool.IsFreeFace(iface))
11480 vector<const SMDS_MeshNode *> nodes;
11481 int nbFaceNodes = vTool.NbFaceNodes(iface);
11482 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11484 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11485 nodes.push_back(faceNodes[inode]);
11487 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11488 nodes.push_back(faceNodes[inode]);
11490 // add new face based on volume nodes
11491 if (aMesh->FindFace( nodes ) ) {
11493 continue; // face already exsist
11495 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11499 return ( nbFree==(nbExisted+nbCreated) );
11504 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11506 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11508 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11511 //================================================================================
11513 * \brief Creates missing boundary elements
11514 * \param elements - elements whose boundary is to be checked
11515 * \param dimension - defines type of boundary elements to create
11516 * \param group - a group to store created boundary elements in
11517 * \param targetMesh - a mesh to store created boundary elements in
11518 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11519 * \param toCopyExistingBondary - if true, not only new but also pre-existing
11520 * boundary elements will be copied into the targetMesh
11521 * \param toAddExistingBondary - if true, not only new but also pre-existing
11522 * boundary elements will be added into the new group
11523 * \param aroundElements - if true, elements will be created on boundary of given
11524 * elements else, on boundary of the whole mesh. This
11525 * option works for 2D elements only.
11526 * \return nb of added boundary elements
11528 //================================================================================
11530 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11531 Bnd_Dimension dimension,
11532 SMESH_Group* group/*=0*/,
11533 SMESH_Mesh* targetMesh/*=0*/,
11534 bool toCopyElements/*=false*/,
11535 bool toCopyExistingBondary/*=false*/,
11536 bool toAddExistingBondary/*= false*/,
11537 bool aroundElements/*= false*/)
11539 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11540 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11541 // hope that all elements are of the same type, do not check them all
11542 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11543 throw SALOME_Exception(LOCALIZED("wrong element type"));
11545 if ( aroundElements && elemType == SMDSAbs_Volume )
11546 throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11549 toCopyElements = toCopyExistingBondary = false;
11551 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11552 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11553 int nbAddedBnd = 0;
11555 // editor adding present bnd elements and optionally holding elements to add to the group
11556 SMESH_MeshEditor* presentEditor;
11557 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11558 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11560 SMDS_VolumeTool vTool;
11561 TIDSortedElemSet avoidSet;
11562 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11565 typedef vector<const SMDS_MeshNode*> TConnectivity;
11567 SMDS_ElemIteratorPtr eIt;
11568 if (elements.empty())
11569 eIt = aMesh->elementsIterator(elemType);
11571 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11573 while (eIt->more())
11575 const SMDS_MeshElement* elem = eIt->next();
11576 const int iQuad = elem->IsQuadratic();
11578 // ------------------------------------------------------------------------------------
11579 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11580 // ------------------------------------------------------------------------------------
11581 vector<const SMDS_MeshElement*> presentBndElems;
11582 vector<TConnectivity> missingBndElems;
11583 TConnectivity nodes;
11584 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11586 vTool.SetExternalNormal();
11587 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11589 if (!vTool.IsFreeFace(iface))
11591 int nbFaceNodes = vTool.NbFaceNodes(iface);
11592 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11593 if ( missType == SMDSAbs_Edge ) // boundary edges
11595 nodes.resize( 2+iQuad );
11596 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11598 for ( int j = 0; j < nodes.size(); ++j )
11600 if ( const SMDS_MeshElement* edge =
11601 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11602 presentBndElems.push_back( edge );
11604 missingBndElems.push_back( nodes );
11607 else // boundary face
11610 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11611 nodes.push_back( nn[inode] );
11613 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11614 nodes.push_back( nn[inode] );
11616 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11617 presentBndElems.push_back( f );
11619 missingBndElems.push_back( nodes );
11623 else // elem is a face ------------------------------------------
11625 avoidSet.clear(), avoidSet.insert( elem );
11626 int nbNodes = elem->NbCornerNodes();
11627 nodes.resize( 2 /*+ iQuad*/);
11628 for ( int i = 0; i < nbNodes; i++ )
11630 nodes[0] = elem->GetNode(i);
11631 nodes[1] = elem->GetNode((i+1)%nbNodes);
11632 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11633 continue; // not free link
11636 //nodes[2] = elem->GetNode( i + nbNodes );
11637 if ( const SMDS_MeshElement* edge =
11638 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11639 presentBndElems.push_back( edge );
11641 missingBndElems.push_back( nodes );
11645 // ---------------------------------
11646 // 2. Add missing boundary elements
11647 // ---------------------------------
11648 if ( targetMesh != myMesh )
11649 // instead of making a map of nodes in this mesh and targetMesh,
11650 // we create nodes with same IDs. We can renumber them later, if needed
11651 for ( int i = 0; i < missingBndElems.size(); ++i )
11653 TConnectivity& srcNodes = missingBndElems[i];
11654 TConnectivity nodes( srcNodes.size() );
11655 for ( inode = 0; inode < nodes.size(); ++inode )
11656 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11657 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11659 /*noMedium=*/true))
11661 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11665 for ( int i = 0; i < missingBndElems.size(); ++i )
11667 TConnectivity& nodes = missingBndElems[i];
11668 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11670 /*noMedium=*/true))
11672 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11676 // ----------------------------------
11677 // 3. Copy present boundary elements
11678 // ----------------------------------
11679 if ( toCopyExistingBondary )
11680 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11682 const SMDS_MeshElement* e = presentBndElems[i];
11683 TConnectivity nodes( e->NbNodes() );
11684 for ( inode = 0; inode < nodes.size(); ++inode )
11685 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11686 presentEditor->AddElement(nodes, missType, e->IsPoly());
11688 else // store present elements to add them to a group
11689 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11691 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11694 } // loop on given elements
11696 // ---------------------------------------------
11697 // 4. Fill group with boundary elements
11698 // ---------------------------------------------
11701 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11702 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11703 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11705 tgtEditor.myLastCreatedElems.Clear();
11706 tgtEditor2.myLastCreatedElems.Clear();
11708 // -----------------------
11709 // 5. Copy given elements
11710 // -----------------------
11711 if ( toCopyElements && targetMesh != myMesh )
11713 if (elements.empty())
11714 eIt = aMesh->elementsIterator(elemType);
11716 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11717 while (eIt->more())
11719 const SMDS_MeshElement* elem = eIt->next();
11720 TConnectivity nodes( elem->NbNodes() );
11721 for ( inode = 0; inode < nodes.size(); ++inode )
11722 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11723 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11725 tgtEditor.myLastCreatedElems.Clear();