1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SMESH SMESH : idl implementation based on 'SMESH' unit's classes
24 // File : SMESH_MeshEditor.cxx
25 // Created : Mon Apr 12 16:10:22 2004
26 // Author : Edward AGAPOV (eap)
29 #include "SMESH_MeshEditor.hxx"
31 #include "SMDS_FaceOfNodes.hxx"
32 #include "SMDS_VolumeTool.hxx"
33 #include "SMDS_EdgePosition.hxx"
34 #include "SMDS_PolyhedralVolumeOfNodes.hxx"
35 #include "SMDS_FacePosition.hxx"
36 #include "SMDS_SpacePosition.hxx"
37 //#include "SMDS_QuadraticFaceOfNodes.hxx"
38 #include "SMDS_MeshGroup.hxx"
39 #include "SMDS_LinearEdge.hxx"
40 #include "SMDS_Downward.hxx"
41 #include "SMDS_SetIterator.hxx"
43 #include "SMESHDS_Group.hxx"
44 #include "SMESHDS_Mesh.hxx"
46 #include "SMESH_Algo.hxx"
47 #include "SMESH_ControlsDef.hxx"
48 #include "SMESH_Group.hxx"
49 #include "SMESH_MesherHelper.hxx"
50 #include "SMESH_OctreeNode.hxx"
51 #include "SMESH_subMesh.hxx"
53 #include "utilities.h"
55 #include <BRepAdaptor_Surface.hxx>
56 #include <BRepClass3d_SolidClassifier.hxx>
57 #include <BRep_Tool.hxx>
59 #include <Extrema_GenExtPS.hxx>
60 #include <Extrema_POnCurv.hxx>
61 #include <Extrema_POnSurf.hxx>
62 #include <GC_MakeSegment.hxx>
63 #include <Geom2d_Curve.hxx>
64 #include <GeomAPI_ExtremaCurveCurve.hxx>
65 #include <GeomAdaptor_Surface.hxx>
66 #include <Geom_Curve.hxx>
67 #include <Geom_Line.hxx>
68 #include <Geom_Surface.hxx>
69 #include <IntAna_IntConicQuad.hxx>
70 #include <IntAna_Quadric.hxx>
71 #include <Precision.hxx>
72 #include <TColStd_ListOfInteger.hxx>
73 #include <TopAbs_State.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_ListIteratorOfListOfShape.hxx>
77 #include <TopTools_ListOfShape.hxx>
78 #include <TopTools_SequenceOfShape.hxx>
80 #include <TopoDS_Face.hxx>
86 #include <gp_Trsf.hxx>
99 #define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
102 using namespace SMESH::Controls;
104 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshNode*> > TElemOfNodeListMap;
105 typedef map<const SMDS_MeshElement*, list<const SMDS_MeshElement*> > TElemOfElemListMap;
107 typedef SMDS_SetIterator< SMDS_pElement, TIDSortedElemSet::const_iterator> TSetIterator;
109 //=======================================================================
110 //function : SMESH_MeshEditor
112 //=======================================================================
114 SMESH_MeshEditor::SMESH_MeshEditor( SMESH_Mesh* theMesh )
115 :myMesh( theMesh ) // theMesh may be NULL
119 //=======================================================================
123 //=======================================================================
126 SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
127 const SMDSAbs_ElementType type,
131 //MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
132 SMDS_MeshElement* e = 0;
133 int nbnode = node.size();
134 SMESHDS_Mesh* mesh = GetMeshDS();
139 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
140 else e = mesh->AddFace (node[0], node[1], node[2] );
142 else if (nbnode == 4) {
143 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
144 else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
146 else if (nbnode == 6) {
147 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
148 node[4], node[5], ID);
149 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
152 else if (nbnode == 8) {
153 if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
154 node[4], node[5], node[6], node[7], ID);
155 else e = mesh->AddFace (node[0], node[1], node[2], node[3],
156 node[4], node[5], node[6], node[7] );
159 if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
160 else e = mesh->AddPolygonalFace (node );
167 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
168 else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
170 else if (nbnode == 5) {
171 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
173 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
176 else if (nbnode == 6) {
177 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
178 node[4], node[5], ID);
179 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
182 else if (nbnode == 8) {
183 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
184 node[4], node[5], node[6], node[7], ID);
185 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
186 node[4], node[5], node[6], node[7] );
188 else if (nbnode == 10) {
189 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
190 node[4], node[5], node[6], node[7],
191 node[8], node[9], ID);
192 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
193 node[4], node[5], node[6], node[7],
196 else if (nbnode == 13) {
197 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
198 node[4], node[5], node[6], node[7],
199 node[8], node[9], node[10],node[11],
201 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
202 node[4], node[5], node[6], node[7],
203 node[8], node[9], node[10],node[11],
206 else if (nbnode == 15) {
207 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
208 node[4], node[5], node[6], node[7],
209 node[8], node[9], node[10],node[11],
210 node[12],node[13],node[14],ID);
211 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
212 node[4], node[5], node[6], node[7],
213 node[8], node[9], node[10],node[11],
214 node[12],node[13],node[14] );
216 else if (nbnode == 20) {
217 if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
218 node[4], node[5], node[6], node[7],
219 node[8], node[9], node[10],node[11],
220 node[12],node[13],node[14],node[15],
221 node[16],node[17],node[18],node[19],ID);
222 else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
223 node[4], node[5], node[6], node[7],
224 node[8], node[9], node[10],node[11],
225 node[12],node[13],node[14],node[15],
226 node[16],node[17],node[18],node[19] );
233 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
234 else e = mesh->AddEdge (node[0], node[1] );
236 else if ( nbnode == 3 ) {
237 if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
238 else e = mesh->AddEdge (node[0], node[1], node[2] );
242 case SMDSAbs_0DElement:
244 if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
245 else e = mesh->Add0DElement (node[0] );
250 if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
251 else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
256 if ( e ) myLastCreatedElems.Append( e );
260 //=======================================================================
264 //=======================================================================
266 SMDS_MeshElement* SMESH_MeshEditor::AddElement(const vector<int> & nodeIDs,
267 const SMDSAbs_ElementType type,
271 vector<const SMDS_MeshNode*> nodes;
272 nodes.reserve( nodeIDs.size() );
273 vector<int>::const_iterator id = nodeIDs.begin();
274 while ( id != nodeIDs.end() ) {
275 if ( const SMDS_MeshNode* node = GetMeshDS()->FindNode( *id++ ))
276 nodes.push_back( node );
280 return AddElement( nodes, type, isPoly, ID );
283 //=======================================================================
285 //purpose : Remove a node or an element.
286 // Modify a compute state of sub-meshes which become empty
287 //=======================================================================
289 int SMESH_MeshEditor::Remove (const list< int >& theIDs,
292 myLastCreatedElems.Clear();
293 myLastCreatedNodes.Clear();
295 SMESHDS_Mesh* aMesh = GetMeshDS();
296 set< SMESH_subMesh *> smmap;
299 list<int>::const_iterator it = theIDs.begin();
300 for ( ; it != theIDs.end(); it++ ) {
301 const SMDS_MeshElement * elem;
303 elem = aMesh->FindNode( *it );
305 elem = aMesh->FindElement( *it );
309 // Notify VERTEX sub-meshes about modification
311 const SMDS_MeshNode* node = cast2Node( elem );
312 if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_VERTEX )
313 if ( int aShapeID = node->getshapeId() )
314 if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
317 // Find sub-meshes to notify about modification
318 // SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
319 // while ( nodeIt->more() ) {
320 // const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
321 // const SMDS_PositionPtr& aPosition = node->GetPosition();
322 // if ( aPosition.get() ) {
323 // if ( int aShapeID = aPosition->GetShapeId() ) {
324 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( aShapeID ) )
325 // smmap.insert( sm );
332 aMesh->RemoveNode( static_cast< const SMDS_MeshNode* >( elem ));
334 aMesh->RemoveElement( elem );
338 // Notify sub-meshes about modification
339 if ( !smmap.empty() ) {
340 set< SMESH_subMesh *>::iterator smIt;
341 for ( smIt = smmap.begin(); smIt != smmap.end(); smIt++ )
342 (*smIt)->ComputeStateEngine( SMESH_subMesh::MESH_ENTITY_REMOVED );
345 // // Check if the whole mesh becomes empty
346 // if ( SMESH_subMesh * sm = GetMesh()->GetSubMeshContaining( 1 ) )
347 // sm->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
352 //=======================================================================
353 //function : FindShape
354 //purpose : Return an index of the shape theElem is on
355 // or zero if a shape not found
356 //=======================================================================
358 int SMESH_MeshEditor::FindShape (const SMDS_MeshElement * theElem)
360 myLastCreatedElems.Clear();
361 myLastCreatedNodes.Clear();
363 SMESHDS_Mesh * aMesh = GetMeshDS();
364 if ( aMesh->ShapeToMesh().IsNull() )
367 if ( theElem->GetType() == SMDSAbs_Node )
369 int aShapeID = theElem->getshapeId();
376 TopoDS_Shape aShape; // the shape a node is on
377 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
378 while ( nodeIt->more() ) {
379 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
380 int aShapeID = node->getshapeId();
382 SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
384 if ( sm->Contains( theElem ))
386 if ( aShape.IsNull() )
387 aShape = aMesh->IndexToShape( aShapeID );
390 //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
395 // None of nodes is on a proper shape,
396 // find the shape among ancestors of aShape on which a node is
397 if ( aShape.IsNull() ) {
398 //MESSAGE ("::FindShape() - NONE node is on shape")
401 TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
402 for ( ; ancIt.More(); ancIt.Next() ) {
403 SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
404 if ( sm && sm->Contains( theElem ))
405 return aMesh->ShapeToIndex( ancIt.Value() );
408 //MESSAGE ("::FindShape() - SHAPE NOT FOUND")
412 //=======================================================================
413 //function : IsMedium
415 //=======================================================================
417 bool SMESH_MeshEditor::IsMedium(const SMDS_MeshNode* node,
418 const SMDSAbs_ElementType typeToCheck)
420 bool isMedium = false;
421 SMDS_ElemIteratorPtr it = node->GetInverseElementIterator(typeToCheck);
422 while (it->more() && !isMedium ) {
423 const SMDS_MeshElement* elem = it->next();
424 isMedium = elem->IsMediumNode(node);
429 //=======================================================================
430 //function : ShiftNodesQuadTria
432 // Shift nodes in the array corresponded to quadratic triangle
433 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
434 //=======================================================================
435 static void ShiftNodesQuadTria(const SMDS_MeshNode* aNodes[])
437 const SMDS_MeshNode* nd1 = aNodes[0];
438 aNodes[0] = aNodes[1];
439 aNodes[1] = aNodes[2];
441 const SMDS_MeshNode* nd2 = aNodes[3];
442 aNodes[3] = aNodes[4];
443 aNodes[4] = aNodes[5];
447 //=======================================================================
448 //function : GetNodesFromTwoTria
450 // Shift nodes in the array corresponded to quadratic triangle
451 // example: (0,1,2,3,4,5) -> (1,2,0,4,5,3)
452 //=======================================================================
453 static bool GetNodesFromTwoTria(const SMDS_MeshElement * theTria1,
454 const SMDS_MeshElement * theTria2,
455 const SMDS_MeshNode* N1[],
456 const SMDS_MeshNode* N2[])
458 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
461 N1[i] = static_cast<const SMDS_MeshNode*>( it->next() );
464 if(it->more()) return false;
465 it = theTria2->nodesIterator();
468 N2[i] = static_cast<const SMDS_MeshNode*>( it->next() );
471 if(it->more()) return false;
473 int sames[3] = {-1,-1,-1};
485 if(nbsames!=2) return false;
487 ShiftNodesQuadTria(N1);
489 ShiftNodesQuadTria(N1);
492 i = sames[0] + sames[1] + sames[2];
494 ShiftNodesQuadTria(N2);
496 // now we receive following N1 and N2 (using numeration as above image)
497 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
498 // i.e. first nodes from both arrays determ new diagonal
502 //=======================================================================
503 //function : InverseDiag
504 //purpose : Replace two neighbour triangles with ones built on the same 4 nodes
505 // but having other common link.
506 // Return False if args are improper
507 //=======================================================================
509 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshElement * theTria1,
510 const SMDS_MeshElement * theTria2 )
512 MESSAGE("InverseDiag");
513 myLastCreatedElems.Clear();
514 myLastCreatedNodes.Clear();
516 if (!theTria1 || !theTria2)
519 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( theTria1 );
520 if (!F1) return false;
521 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( theTria2 );
522 if (!F2) return false;
523 if ((theTria1->GetEntityType() == SMDSEntity_Triangle) &&
524 (theTria2->GetEntityType() == SMDSEntity_Triangle)) {
526 // 1 +--+ A theTria1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
527 // | /| theTria2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
531 // put nodes in array and find out indices of the same ones
532 const SMDS_MeshNode* aNodes [6];
533 int sameInd [] = { 0, 0, 0, 0, 0, 0 };
535 SMDS_ElemIteratorPtr it = theTria1->nodesIterator();
536 while ( it->more() ) {
537 aNodes[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
539 if ( i > 2 ) // theTria2
540 // find same node of theTria1
541 for ( int j = 0; j < 3; j++ )
542 if ( aNodes[ i ] == aNodes[ j ]) {
551 return false; // theTria1 is not a triangle
552 it = theTria2->nodesIterator();
554 if ( i == 6 && it->more() )
555 return false; // theTria2 is not a triangle
558 // find indices of 1,2 and of A,B in theTria1
559 int iA = 0, iB = 0, i1 = 0, i2 = 0;
560 for ( i = 0; i < 6; i++ ) {
561 if ( sameInd [ i ] == 0 ) {
570 // nodes 1 and 2 should not be the same
571 if ( aNodes[ i1 ] == aNodes[ i2 ] )
575 aNodes[ iA ] = aNodes[ i2 ];
577 aNodes[ sameInd[ iB ]] = aNodes[ i1 ];
579 GetMeshDS()->ChangeElementNodes( theTria1, aNodes, 3 );
580 GetMeshDS()->ChangeElementNodes( theTria2, &aNodes[ 3 ], 3 );
584 } // end if(F1 && F2)
586 // check case of quadratic faces
587 if (theTria1->GetEntityType() != SMDSEntity_Quad_Triangle)
589 if (theTria2->GetEntityType() != SMDSEntity_Quad_Triangle)
593 // 1 +--+--+ 2 theTria1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
594 // | /| theTria2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
602 const SMDS_MeshNode* N1 [6];
603 const SMDS_MeshNode* N2 [6];
604 if(!GetNodesFromTwoTria(theTria1,theTria2,N1,N2))
606 // now we receive following N1 and N2 (using numeration as above image)
607 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
608 // i.e. first nodes from both arrays determ new diagonal
610 const SMDS_MeshNode* N1new [6];
611 const SMDS_MeshNode* N2new [6];
624 // replaces nodes in faces
625 GetMeshDS()->ChangeElementNodes( theTria1, N1new, 6 );
626 GetMeshDS()->ChangeElementNodes( theTria2, N2new, 6 );
631 //=======================================================================
632 //function : findTriangles
633 //purpose : find triangles sharing theNode1-theNode2 link
634 //=======================================================================
636 static bool findTriangles(const SMDS_MeshNode * theNode1,
637 const SMDS_MeshNode * theNode2,
638 const SMDS_MeshElement*& theTria1,
639 const SMDS_MeshElement*& theTria2)
641 if ( !theNode1 || !theNode2 ) return false;
643 theTria1 = theTria2 = 0;
645 set< const SMDS_MeshElement* > emap;
646 SMDS_ElemIteratorPtr it = theNode1->GetInverseElementIterator(SMDSAbs_Face);
648 const SMDS_MeshElement* elem = it->next();
649 if ( elem->NbNodes() == 3 )
652 it = theNode2->GetInverseElementIterator(SMDSAbs_Face);
654 const SMDS_MeshElement* elem = it->next();
655 if ( emap.find( elem ) != emap.end() ) {
657 // theTria1 must be element with minimum ID
658 if( theTria1->GetID() < elem->GetID() ) {
672 return ( theTria1 && theTria2 );
675 //=======================================================================
676 //function : InverseDiag
677 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
678 // with ones built on the same 4 nodes but having other common link.
679 // Return false if proper faces not found
680 //=======================================================================
682 bool SMESH_MeshEditor::InverseDiag (const SMDS_MeshNode * theNode1,
683 const SMDS_MeshNode * theNode2)
685 myLastCreatedElems.Clear();
686 myLastCreatedNodes.Clear();
688 MESSAGE( "::InverseDiag()" );
690 const SMDS_MeshElement *tr1, *tr2;
691 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
694 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
695 if (!F1) return false;
696 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
697 if (!F2) return false;
698 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
699 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
701 // 1 +--+ A tr1: ( 1 A B ) A->2 ( 1 2 B ) 1 +--+ A
702 // | /| tr2: ( B A 2 ) B->1 ( 1 A 2 ) |\ |
706 // put nodes in array
707 // and find indices of 1,2 and of A in tr1 and of B in tr2
708 int i, iA1 = 0, i1 = 0;
709 const SMDS_MeshNode* aNodes1 [3];
710 SMDS_ElemIteratorPtr it;
711 for (i = 0, it = tr1->nodesIterator(); it->more(); i++ ) {
712 aNodes1[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
713 if ( aNodes1[ i ] == theNode1 )
714 iA1 = i; // node A in tr1
715 else if ( aNodes1[ i ] != theNode2 )
719 const SMDS_MeshNode* aNodes2 [3];
720 for (i = 0, it = tr2->nodesIterator(); it->more(); i++ ) {
721 aNodes2[ i ] = static_cast<const SMDS_MeshNode*>( it->next() );
722 if ( aNodes2[ i ] == theNode2 )
723 iB2 = i; // node B in tr2
724 else if ( aNodes2[ i ] != theNode1 )
728 // nodes 1 and 2 should not be the same
729 if ( aNodes1[ i1 ] == aNodes2[ i2 ] )
733 aNodes1[ iA1 ] = aNodes2[ i2 ];
735 aNodes2[ iB2 ] = aNodes1[ i1 ];
737 GetMeshDS()->ChangeElementNodes( tr1, aNodes1, 3 );
738 GetMeshDS()->ChangeElementNodes( tr2, aNodes2, 3 );
743 // check case of quadratic faces
744 return InverseDiag(tr1,tr2);
747 //=======================================================================
748 //function : getQuadrangleNodes
749 //purpose : fill theQuadNodes - nodes of a quadrangle resulting from
750 // fusion of triangles tr1 and tr2 having shared link on
751 // theNode1 and theNode2
752 //=======================================================================
754 bool getQuadrangleNodes(const SMDS_MeshNode * theQuadNodes [],
755 const SMDS_MeshNode * theNode1,
756 const SMDS_MeshNode * theNode2,
757 const SMDS_MeshElement * tr1,
758 const SMDS_MeshElement * tr2 )
760 if( tr1->NbNodes() != tr2->NbNodes() )
762 // find the 4-th node to insert into tr1
763 const SMDS_MeshNode* n4 = 0;
764 SMDS_ElemIteratorPtr it = tr2->nodesIterator();
766 while ( !n4 && i<3 ) {
767 const SMDS_MeshNode * n = cast2Node( it->next() );
769 bool isDiag = ( n == theNode1 || n == theNode2 );
773 // Make an array of nodes to be in a quadrangle
774 int iNode = 0, iFirstDiag = -1;
775 it = tr1->nodesIterator();
778 const SMDS_MeshNode * n = cast2Node( it->next() );
780 bool isDiag = ( n == theNode1 || n == theNode2 );
782 if ( iFirstDiag < 0 )
784 else if ( iNode - iFirstDiag == 1 )
785 theQuadNodes[ iNode++ ] = n4; // insert the 4-th node between diagonal nodes
787 else if ( n == n4 ) {
788 return false; // tr1 and tr2 should not have all the same nodes
790 theQuadNodes[ iNode++ ] = n;
792 if ( iNode == 3 ) // diagonal nodes have 0 and 2 indices
793 theQuadNodes[ iNode ] = n4;
798 //=======================================================================
799 //function : DeleteDiag
800 //purpose : Replace two neighbour triangles sharing theNode1-theNode2 link
801 // with a quadrangle built on the same 4 nodes.
802 // Return false if proper faces not found
803 //=======================================================================
805 bool SMESH_MeshEditor::DeleteDiag (const SMDS_MeshNode * theNode1,
806 const SMDS_MeshNode * theNode2)
808 myLastCreatedElems.Clear();
809 myLastCreatedNodes.Clear();
811 MESSAGE( "::DeleteDiag()" );
813 const SMDS_MeshElement *tr1, *tr2;
814 if ( !findTriangles( theNode1, theNode2, tr1, tr2 ))
817 const SMDS_VtkFace* F1 = dynamic_cast<const SMDS_VtkFace*>( tr1 );
818 if (!F1) return false;
819 const SMDS_VtkFace* F2 = dynamic_cast<const SMDS_VtkFace*>( tr2 );
820 if (!F2) return false;
821 SMESHDS_Mesh * aMesh = GetMeshDS();
823 if ((tr1->GetEntityType() == SMDSEntity_Triangle) &&
824 (tr2->GetEntityType() == SMDSEntity_Triangle)) {
826 const SMDS_MeshNode* aNodes [ 4 ];
827 if ( ! getQuadrangleNodes( aNodes, theNode1, theNode2, tr1, tr2 ))
830 const SMDS_MeshElement* newElem = 0;
831 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3] );
832 myLastCreatedElems.Append(newElem);
833 AddToSameGroups( newElem, tr1, aMesh );
834 int aShapeId = tr1->getshapeId();
837 aMesh->SetMeshElementOnShape( newElem, aShapeId );
839 aMesh->RemoveElement( tr1 );
840 aMesh->RemoveElement( tr2 );
845 // check case of quadratic faces
846 if (tr1->GetEntityType() != SMDSEntity_Quad_Triangle)
848 if (tr2->GetEntityType() != SMDSEntity_Quad_Triangle)
852 // 1 +--+--+ 2 tr1: (1 2 4 5 9 7) or (2 4 1 9 7 5) or (4 1 2 7 5 9)
853 // | /| tr2: (2 3 4 6 8 9) or (3 4 2 8 9 6) or (4 2 3 9 6 8)
861 const SMDS_MeshNode* N1 [6];
862 const SMDS_MeshNode* N2 [6];
863 if(!GetNodesFromTwoTria(tr1,tr2,N1,N2))
865 // now we receive following N1 and N2 (using numeration as above image)
866 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
867 // i.e. first nodes from both arrays determ new diagonal
869 const SMDS_MeshNode* aNodes[8];
879 const SMDS_MeshElement* newElem = 0;
880 newElem = aMesh->AddFace( aNodes[0], aNodes[1], aNodes[2], aNodes[3],
881 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
882 myLastCreatedElems.Append(newElem);
883 AddToSameGroups( newElem, tr1, aMesh );
884 int aShapeId = tr1->getshapeId();
887 aMesh->SetMeshElementOnShape( newElem, aShapeId );
889 aMesh->RemoveElement( tr1 );
890 aMesh->RemoveElement( tr2 );
892 // remove middle node (9)
893 GetMeshDS()->RemoveNode( N1[4] );
898 //=======================================================================
899 //function : Reorient
900 //purpose : Reverse theElement orientation
901 //=======================================================================
903 bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
906 myLastCreatedElems.Clear();
907 myLastCreatedNodes.Clear();
911 SMDS_ElemIteratorPtr it = theElem->nodesIterator();
912 if ( !it || !it->more() )
915 switch ( theElem->GetType() ) {
919 if(!theElem->IsQuadratic()) {
920 int i = theElem->NbNodes();
921 vector<const SMDS_MeshNode*> aNodes( i );
923 aNodes[ --i ]= static_cast<const SMDS_MeshNode*>( it->next() );
924 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], theElem->NbNodes() );
927 // quadratic elements
928 if(theElem->GetType()==SMDSAbs_Edge) {
929 vector<const SMDS_MeshNode*> aNodes(3);
930 aNodes[1]= static_cast<const SMDS_MeshNode*>( it->next() );
931 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
932 aNodes[2]= static_cast<const SMDS_MeshNode*>( it->next() );
933 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], 3 );
936 int nbn = theElem->NbNodes();
937 vector<const SMDS_MeshNode*> aNodes(nbn);
938 aNodes[0]= static_cast<const SMDS_MeshNode*>( it->next() );
940 for(; i<nbn/2; i++) {
941 aNodes[nbn/2-i]= static_cast<const SMDS_MeshNode*>( it->next() );
943 for(i=0; i<nbn/2; i++) {
944 aNodes[nbn-i-1]= static_cast<const SMDS_MeshNode*>( it->next() );
946 return GetMeshDS()->ChangeElementNodes( theElem, &aNodes[0], nbn );
950 case SMDSAbs_Volume: {
951 if (theElem->IsPoly()) {
952 // TODO reorient vtk polyhedron
953 MESSAGE("reorient vtk polyhedron ?");
954 const SMDS_VtkVolume* aPolyedre =
955 dynamic_cast<const SMDS_VtkVolume*>( theElem );
957 MESSAGE("Warning: bad volumic element");
961 int nbFaces = aPolyedre->NbFaces();
962 vector<const SMDS_MeshNode *> poly_nodes;
963 vector<int> quantities (nbFaces);
965 // reverse each face of the polyedre
966 for (int iface = 1; iface <= nbFaces; iface++) {
967 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
968 quantities[iface - 1] = nbFaceNodes;
970 for (inode = nbFaceNodes; inode >= 1; inode--) {
971 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
972 poly_nodes.push_back(curNode);
976 return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
980 SMDS_VolumeTool vTool;
981 if ( !vTool.Set( theElem ))
984 MESSAGE("ChangeElementNodes reorient: check vTool.Inverse");
985 return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
994 //=======================================================================
995 //function : getBadRate
997 //=======================================================================
999 static double getBadRate (const SMDS_MeshElement* theElem,
1000 SMESH::Controls::NumericalFunctorPtr& theCrit)
1002 SMESH::Controls::TSequenceOfXYZ P;
1003 if ( !theElem || !theCrit->GetPoints( theElem, P ))
1005 return theCrit->GetBadRate( theCrit->GetValue( P ), theElem->NbNodes() );
1006 //return theCrit->GetBadRate( theCrit->GetValue( theElem->GetID() ), theElem->NbNodes() );
1009 //=======================================================================
1010 //function : QuadToTri
1011 //purpose : Cut quadrangles into triangles.
1012 // theCrit is used to select a diagonal to cut
1013 //=======================================================================
1015 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1016 SMESH::Controls::NumericalFunctorPtr theCrit)
1018 myLastCreatedElems.Clear();
1019 myLastCreatedNodes.Clear();
1021 MESSAGE( "::QuadToTri()" );
1023 if ( !theCrit.get() )
1026 SMESHDS_Mesh * aMesh = GetMeshDS();
1028 Handle(Geom_Surface) surface;
1029 SMESH_MesherHelper helper( *GetMesh() );
1031 TIDSortedElemSet::iterator itElem;
1032 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1033 const SMDS_MeshElement* elem = *itElem;
1034 if ( !elem || elem->GetType() != SMDSAbs_Face )
1036 if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
1039 // retrieve element nodes
1040 const SMDS_MeshNode* aNodes [8];
1041 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1043 while ( itN->more() )
1044 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1046 // compare two sets of possible triangles
1047 double aBadRate1, aBadRate2; // to what extent a set is bad
1048 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1049 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1050 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1052 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1053 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1054 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1056 int aShapeId = FindShape( elem );
1057 const SMDS_MeshElement* newElem1 = 0;
1058 const SMDS_MeshElement* newElem2 = 0;
1060 if( !elem->IsQuadratic() ) {
1062 // split liner quadrangle
1063 if ( aBadRate1 <= aBadRate2 ) {
1064 // tr1 + tr2 is better
1065 newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1066 newElem2 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1069 // tr3 + tr4 is better
1070 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1071 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1076 // split quadratic quadrangle
1078 // get surface elem is on
1079 if ( aShapeId != helper.GetSubShapeID() ) {
1083 shape = aMesh->IndexToShape( aShapeId );
1084 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1085 TopoDS_Face face = TopoDS::Face( shape );
1086 surface = BRep_Tool::Surface( face );
1087 if ( !surface.IsNull() )
1088 helper.SetSubShape( shape );
1092 const SMDS_MeshNode* aNodes [8];
1093 const SMDS_MeshNode* inFaceNode = 0;
1094 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1096 while ( itN->more() ) {
1097 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1098 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1099 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1101 inFaceNode = aNodes[ i-1 ];
1104 // find middle point for (0,1,2,3)
1105 // and create a node in this point;
1107 if ( surface.IsNull() ) {
1109 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1113 TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
1116 uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
1118 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1120 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1121 myLastCreatedNodes.Append(newN);
1123 // create a new element
1124 const SMDS_MeshNode* N[6];
1125 if ( aBadRate1 <= aBadRate2 ) {
1132 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1133 aNodes[6], aNodes[7], newN );
1134 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1135 newN, aNodes[4], aNodes[5] );
1144 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1145 aNodes[7], aNodes[4], newN );
1146 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1147 newN, aNodes[5], aNodes[6] );
1151 // care of a new element
1153 myLastCreatedElems.Append(newElem1);
1154 myLastCreatedElems.Append(newElem2);
1155 AddToSameGroups( newElem1, elem, aMesh );
1156 AddToSameGroups( newElem2, elem, aMesh );
1158 // put a new triangle on the same shape
1161 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1162 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1164 aMesh->RemoveElement( elem );
1169 //=======================================================================
1170 //function : BestSplit
1171 //purpose : Find better diagonal for cutting.
1172 //=======================================================================
1174 int SMESH_MeshEditor::BestSplit (const SMDS_MeshElement* theQuad,
1175 SMESH::Controls::NumericalFunctorPtr theCrit)
1177 myLastCreatedElems.Clear();
1178 myLastCreatedNodes.Clear();
1183 if (!theQuad || theQuad->GetType() != SMDSAbs_Face )
1186 if( theQuad->NbNodes()==4 ||
1187 (theQuad->NbNodes()==8 && theQuad->IsQuadratic()) ) {
1189 // retrieve element nodes
1190 const SMDS_MeshNode* aNodes [4];
1191 SMDS_ElemIteratorPtr itN = theQuad->nodesIterator();
1193 //while (itN->more())
1195 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1197 // compare two sets of possible triangles
1198 double aBadRate1, aBadRate2; // to what extent a set is bad
1199 SMDS_FaceOfNodes tr1 ( aNodes[0], aNodes[1], aNodes[2] );
1200 SMDS_FaceOfNodes tr2 ( aNodes[2], aNodes[3], aNodes[0] );
1201 aBadRate1 = getBadRate( &tr1, theCrit ) + getBadRate( &tr2, theCrit );
1203 SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
1204 SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
1205 aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
1207 if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
1208 return 1; // diagonal 1-3
1210 return 2; // diagonal 2-4
1217 // Methods of splitting volumes into tetra
1219 const int theHexTo5_1[5*4+1] =
1221 0, 1, 2, 5, 0, 4, 5, 7, 0, 2, 3, 7, 2, 5, 6, 7, 0, 5, 2, 7, -1
1223 const int theHexTo5_2[5*4+1] =
1225 1, 2, 3, 6, 1, 4, 5, 6, 0, 1, 3, 4, 3, 4, 6, 7, 1, 3, 4, 6, -1
1227 const int* theHexTo5[2] = { theHexTo5_1, theHexTo5_2 };
1229 const int theHexTo6_1[6*4+1] =
1231 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
1233 const int theHexTo6_2[6*4+1] =
1235 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
1237 const int theHexTo6_3[6*4+1] =
1239 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
1241 const int theHexTo6_4[6*4+1] =
1243 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
1245 const int* theHexTo6[4] = { theHexTo6_1, theHexTo6_2, theHexTo6_3, theHexTo6_4 };
1247 const int thePyraTo2_1[2*4+1] =
1249 0, 1, 2, 4, 0, 2, 3, 4, -1
1251 const int thePyraTo2_2[2*4+1] =
1253 1, 2, 3, 4, 1, 3, 0, 4, -1
1255 const int* thePyraTo2[2] = { thePyraTo2_1, thePyraTo2_2 };
1257 const int thePentaTo3_1[3*4+1] =
1259 0, 1, 2, 3, 1, 3, 4, 2, 2, 3, 4, 5, -1
1261 const int thePentaTo3_2[3*4+1] =
1263 1, 2, 0, 4, 2, 4, 5, 0, 0, 4, 5, 3, -1
1265 const int thePentaTo3_3[3*4+1] =
1267 2, 0, 1, 5, 0, 5, 3, 1, 1, 5, 3, 4, -1
1269 const int thePentaTo3_4[3*4+1] =
1271 0, 1, 2, 3, 1, 3, 4, 5, 2, 3, 1, 5, -1
1273 const int thePentaTo3_5[3*4+1] =
1275 1, 2, 0, 4, 2, 4, 5, 3, 0, 4, 2, 3, -1
1277 const int thePentaTo3_6[3*4+1] =
1279 2, 0, 1, 5, 0, 5, 3, 4, 1, 5, 0, 4, -1
1281 const int* thePentaTo3[6] = { thePentaTo3_1, thePentaTo3_2, thePentaTo3_3,
1282 thePentaTo3_4, thePentaTo3_5, thePentaTo3_6 };
1284 struct TTriangleFacet //!< stores indices of three nodes of tetra facet
1287 TTriangleFacet(int n1, int n2, int n3): _n1(n1), _n2(n2), _n3(n3) {}
1288 bool contains(int n) const { return ( n == _n1 || n == _n2 || n == _n3 ); }
1289 bool hasAdjacentTetra( const SMDS_MeshElement* elem ) const;
1294 const int* _connectivity; //!< foursomes of tetra connectivy finished by -1
1295 bool _baryNode; //!< additional node is to be created at cell barycenter
1296 bool _ownConn; //!< to delete _connectivity in destructor
1297 map<int, const SMDS_MeshNode*> _faceBaryNode; //!< map face index to node at BC of face
1299 TSplitMethod( int nbTet=0, const int* conn=0, bool addNode=false)
1300 : _nbTetra(nbTet), _connectivity(conn), _baryNode(addNode), _ownConn(false) {}
1301 ~TSplitMethod() { if ( _ownConn ) delete [] _connectivity; _connectivity = 0; }
1302 bool hasFacet( const TTriangleFacet& facet ) const
1304 const int* tetConn = _connectivity;
1305 for ( ; tetConn[0] >= 0; tetConn += 4 )
1306 if (( facet.contains( tetConn[0] ) +
1307 facet.contains( tetConn[1] ) +
1308 facet.contains( tetConn[2] ) +
1309 facet.contains( tetConn[3] )) == 3 )
1315 //=======================================================================
1317 * \brief return TSplitMethod for the given element
1319 //=======================================================================
1321 TSplitMethod getSplitMethod( SMDS_VolumeTool& vol, const int theMethodFlags)
1323 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1325 // at HEXA_TO_24 method, each face of volume is split into triangles each based on
1326 // an edge and a face barycenter; tertaherdons are based on triangles and
1327 // a volume barycenter
1328 const bool is24TetMode = ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_24 );
1330 // Find out how adjacent volumes are split
1332 vector < list< TTriangleFacet > > triaSplitsByFace( vol.NbFaces() ); // splits of each side
1333 int hasAdjacentSplits = 0, maxTetConnSize = 0;
1334 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1336 int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1337 maxTetConnSize += 4 * ( nbNodes - (is24TetMode ? 0 : 2));
1338 if ( nbNodes < 4 ) continue;
1340 list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1341 const int* nInd = vol.GetFaceNodesIndices( iF );
1344 TTriangleFacet t012( nInd[0*iQ], nInd[1*iQ], nInd[2*iQ] );
1345 TTriangleFacet t123( nInd[1*iQ], nInd[2*iQ], nInd[3*iQ] );
1346 if ( t012.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t012 );
1347 else if ( t123.hasAdjacentTetra( vol.Element() )) triaSplits.push_back( t123 );
1351 int iCom = 0; // common node of triangle faces to split into
1352 for ( int iVar = 0; iVar < nbNodes; ++iVar, ++iCom )
1354 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1355 nInd[ iQ * ( (iCom+1)%nbNodes )],
1356 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1357 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1358 nInd[ iQ * ( (iCom+2)%nbNodes )],
1359 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1360 if ( t012.hasAdjacentTetra( vol.Element() ) && t023.hasAdjacentTetra( vol.Element() ))
1362 triaSplits.push_back( t012 );
1363 triaSplits.push_back( t023 );
1368 if ( !triaSplits.empty() )
1369 hasAdjacentSplits = true;
1372 // Among variants of split method select one compliant with adjacent volumes
1374 TSplitMethod method;
1375 if ( !vol.Element()->IsPoly() && !is24TetMode )
1377 int nbVariants = 2, nbTet = 0;
1378 const int** connVariants = 0;
1379 switch ( vol.Element()->GetEntityType() )
1381 case SMDSEntity_Hexa:
1382 case SMDSEntity_Quad_Hexa:
1383 if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
1384 connVariants = theHexTo5, nbTet = 5;
1386 connVariants = theHexTo6, nbTet = 6, nbVariants = 4;
1388 case SMDSEntity_Pyramid:
1389 case SMDSEntity_Quad_Pyramid:
1390 connVariants = thePyraTo2; nbTet = 2;
1392 case SMDSEntity_Penta:
1393 case SMDSEntity_Quad_Penta:
1394 connVariants = thePentaTo3; nbTet = 3; nbVariants = 6;
1399 for ( int variant = 0; variant < nbVariants && method._nbTetra == 0; ++variant )
1401 // check method compliancy with adjacent tetras,
1402 // all found splits must be among facets of tetras described by this method
1403 method = TSplitMethod( nbTet, connVariants[variant] );
1404 if ( hasAdjacentSplits && method._nbTetra > 0 )
1406 bool facetCreated = true;
1407 for ( int iF = 0; facetCreated && iF < triaSplitsByFace.size(); ++iF )
1409 list< TTriangleFacet >::const_iterator facet = triaSplitsByFace[iF].begin();
1410 for ( ; facetCreated && facet != triaSplitsByFace[iF].end(); ++facet )
1411 facetCreated = method.hasFacet( *facet );
1413 if ( !facetCreated )
1414 method = TSplitMethod(0); // incompatible method
1418 if ( method._nbTetra < 1 )
1420 // No standard method is applicable, use a generic solution:
1421 // each facet of a volume is split into triangles and
1422 // each of triangles and a volume barycenter form a tetrahedron.
1424 int* connectivity = new int[ maxTetConnSize + 1 ];
1425 method._connectivity = connectivity;
1426 method._ownConn = true;
1427 method._baryNode = true;
1430 int baryCenInd = vol.NbNodes();
1431 for ( int iF = 0; iF < vol.NbFaces(); ++iF )
1433 const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
1434 const int* nInd = vol.GetFaceNodesIndices( iF );
1435 // find common node of triangle facets of tetra to create
1436 int iCommon = 0; // index in linear numeration
1437 const list< TTriangleFacet >& triaSplits = triaSplitsByFace[ iF ];
1438 if ( !triaSplits.empty() )
1441 const TTriangleFacet* facet = &triaSplits.front();
1442 for ( ; iCommon < nbNodes-1 ; ++iCommon )
1443 if ( facet->contains( nInd[ iQ * iCommon ]) &&
1444 facet->contains( nInd[ iQ * ((iCommon+2)%nbNodes) ]))
1447 else if ( nbNodes > 3 && !is24TetMode )
1449 // find the best method of splitting into triangles by aspect ratio
1450 SMESH::Controls::NumericalFunctorPtr aspectRatio( new SMESH::Controls::AspectRatio);
1451 map< double, int > badness2iCommon;
1452 const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
1453 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1454 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
1455 for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
1457 SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
1458 nodes[ iQ*((iLast-1)%nbNodes)],
1459 nodes[ iQ*((iLast )%nbNodes)]);
1460 double badness = getBadRate( &tria, aspectRatio );
1461 badness2iCommon.insert( make_pair( badness, iCommon ));
1463 // use iCommon with lowest badness
1464 iCommon = badness2iCommon.begin()->second;
1466 if ( iCommon >= nbNodes )
1467 iCommon = 0; // something wrong
1469 // fill connectivity of tetrahedra based on a current face
1470 int nbTet = nbNodes - 2;
1471 if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
1473 method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
1474 int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
1476 for ( int i = 0; i < nbTet; ++i )
1478 int i1 = i, i2 = (i+1) % nbNodes;
1479 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1480 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1481 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1482 connectivity[ connSize++ ] = faceBaryCenInd;
1483 connectivity[ connSize++ ] = baryCenInd;
1488 for ( int i = 0; i < nbTet; ++i )
1490 int i1 = (iCommon+1+i) % nbNodes, i2 = (iCommon+2+i) % nbNodes;
1491 if ( !vol.IsFaceExternal( iF )) swap( i1, i2 );
1492 connectivity[ connSize++ ] = nInd[ iQ * iCommon ];
1493 connectivity[ connSize++ ] = nInd[ iQ * i1 ];
1494 connectivity[ connSize++ ] = nInd[ iQ * i2 ];
1495 connectivity[ connSize++ ] = baryCenInd;
1498 method._nbTetra += nbTet;
1500 connectivity[ connSize++ ] = -1;
1504 //================================================================================
1506 * \brief Check if there is a tetraherdon adjacent to the given element via this facet
1508 //================================================================================
1510 bool TTriangleFacet::hasAdjacentTetra( const SMDS_MeshElement* elem ) const
1512 // find the tetrahedron including the three nodes of facet
1513 const SMDS_MeshNode* n1 = elem->GetNode(_n1);
1514 const SMDS_MeshNode* n2 = elem->GetNode(_n2);
1515 const SMDS_MeshNode* n3 = elem->GetNode(_n3);
1516 SMDS_ElemIteratorPtr volIt1 = n1->GetInverseElementIterator(SMDSAbs_Volume);
1517 while ( volIt1->more() )
1519 const SMDS_MeshElement* v = volIt1->next();
1520 if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
1522 SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
1523 while ( volIt2->more() )
1524 if ( v != volIt2->next() )
1526 SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
1527 while ( volIt3->more() )
1528 if ( v == volIt3->next() )
1534 //=======================================================================
1536 * \brief A key of a face of volume
1538 //=======================================================================
1540 struct TVolumeFaceKey: pair< int, pair< int, int> >
1542 TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
1544 TIDSortedNodeSet sortedNodes;
1545 const int iQ = vol.Element()->IsQuadratic() ? 2 : 1;
1546 int nbNodes = vol.NbFaceNodes( iF );
1547 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iF );
1548 for ( int i = 0; i < nbNodes; i += iQ )
1549 sortedNodes.insert( fNodes[i] );
1550 TIDSortedNodeSet::iterator n = sortedNodes.begin();
1551 first = (*(n++))->GetID();
1552 second.first = (*(n++))->GetID();
1553 second.second = (*(n++))->GetID();
1558 //=======================================================================
1559 //function : SplitVolumesIntoTetra
1560 //purpose : Split volumic elements into tetrahedra.
1561 //=======================================================================
1563 void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
1564 const int theMethodFlags)
1566 // std-like iterator on coordinates of nodes of mesh element
1567 typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
1568 NXyzIterator xyzEnd;
1570 SMDS_VolumeTool volTool;
1571 SMESH_MesherHelper helper( *GetMesh());
1573 SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
1574 SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
1576 SMESH_SequenceOfElemPtr newNodes, newElems;
1578 // map face of volume to it's baricenrtic node
1579 map< TVolumeFaceKey, const SMDS_MeshNode* > volFace2BaryNode;
1582 TIDSortedElemSet::const_iterator elem = theElems.begin();
1583 for ( ; elem != theElems.end(); ++elem )
1585 SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
1586 if ( geomType <= SMDSEntity_Quad_Tetra )
1587 continue; // tetra or face or ...
1589 if ( !volTool.Set( *elem )) continue; // not volume? strange...
1591 TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
1592 if ( splitMethod._nbTetra < 1 ) continue;
1594 // find submesh to add new tetras to
1595 if ( !subMesh || !subMesh->Contains( *elem ))
1597 int shapeID = FindShape( *elem );
1598 helper.SetSubShape( shapeID ); // helper will add tetras to the found submesh
1599 subMesh = GetMeshDS()->MeshElements( shapeID );
1602 if ( (*elem)->IsQuadratic() )
1605 // add quadratic links to the helper
1606 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1608 const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
1609 for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
1610 helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
1612 helper.SetIsQuadratic( true );
1617 helper.SetIsQuadratic( false );
1619 vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
1620 if ( splitMethod._baryNode )
1622 // make a node at barycenter
1623 volTool.GetBaryCenter( bc[0], bc[1], bc[2] );
1624 SMDS_MeshNode* gcNode = helper.AddNode( bc[0], bc[1], bc[2] );
1625 nodes.push_back( gcNode );
1626 newNodes.Append( gcNode );
1628 if ( !splitMethod._faceBaryNode.empty() )
1630 // make or find baricentric nodes of faces
1631 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.begin();
1632 for ( ; iF_n != splitMethod._faceBaryNode.end(); ++iF_n )
1634 map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
1635 volFace2BaryNode.insert
1636 ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
1639 volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
1640 newNodes.Append( f_n->second = helper.AddNode( bc[0], bc[1], bc[2] ));
1642 nodes.push_back( iF_n->second = f_n->second );
1647 helper.SetElementsOnShape( true );
1648 vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
1649 const int* tetConn = splitMethod._connectivity;
1650 for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
1651 newElems.Append( tetras[ i ] = helper.AddVolume( nodes[ tetConn[0] ],
1652 nodes[ tetConn[1] ],
1653 nodes[ tetConn[2] ],
1654 nodes[ tetConn[3] ]));
1656 ReplaceElemInGroups( *elem, tetras, GetMeshDS() );
1658 // Split faces on sides of the split volume
1660 const SMDS_MeshNode** volNodes = volTool.GetNodes();
1661 for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
1663 const int nbNodes = volTool.NbFaceNodes( iF ) / iQ;
1664 if ( nbNodes < 4 ) continue;
1666 // find an existing face
1667 vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
1668 volTool.GetFaceNodes( iF ) + nbNodes*iQ );
1669 while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
1672 helper.SetElementsOnShape( false );
1673 vector< const SMDS_MeshElement* > triangles;
1675 map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
1676 if ( iF_n != splitMethod._faceBaryNode.end() )
1678 for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
1680 const SMDS_MeshNode* n1 = fNodes[iN];
1681 const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
1682 const SMDS_MeshNode *n3 = iF_n->second;
1683 if ( !volTool.IsFaceExternal( iF ))
1685 triangles.push_back( helper.AddFace( n1,n2,n3 ));
1690 // among possible triangles create ones discribed by split method
1691 const int* nInd = volTool.GetFaceNodesIndices( iF );
1692 int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
1693 int iCom = 0; // common node of triangle faces to split into
1694 list< TTriangleFacet > facets;
1695 for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCom )
1697 TTriangleFacet t012( nInd[ iQ * ( iCom )],
1698 nInd[ iQ * ( (iCom+1)%nbNodes )],
1699 nInd[ iQ * ( (iCom+2)%nbNodes )]);
1700 TTriangleFacet t023( nInd[ iQ * ( iCom )],
1701 nInd[ iQ * ( (iCom+2)%nbNodes )],
1702 nInd[ iQ * ( (iCom+3)%nbNodes )]);
1703 if ( splitMethod.hasFacet( t012 ) && splitMethod.hasFacet( t023 ))
1705 facets.push_back( t012 );
1706 facets.push_back( t023 );
1707 for ( int iLast = iCom+4; iLast < iCom+nbNodes; ++iLast )
1708 facets.push_back( TTriangleFacet( nInd[ iQ * ( iCom )],
1709 nInd[ iQ * ((iLast-1)%nbNodes )],
1710 nInd[ iQ * ((iLast )%nbNodes )]));
1714 list< TTriangleFacet >::iterator facet = facets.begin();
1715 for ( ; facet != facets.end(); ++facet )
1717 if ( !volTool.IsFaceExternal( iF ))
1718 swap( facet->_n2, facet->_n3 );
1719 triangles.push_back( helper.AddFace( volNodes[ facet->_n1 ],
1720 volNodes[ facet->_n2 ],
1721 volNodes[ facet->_n3 ]));
1724 // find submesh to add new triangles in
1725 if ( !fSubMesh || !fSubMesh->Contains( face ))
1727 int shapeID = FindShape( face );
1728 fSubMesh = GetMeshDS()->MeshElements( shapeID );
1730 for ( int i = 0; i < triangles.size(); ++i )
1732 if ( !triangles[i] ) continue;
1734 fSubMesh->AddElement( triangles[i]);
1735 newElems.Append( triangles[i] );
1737 ReplaceElemInGroups( face, triangles, GetMeshDS() );
1738 GetMeshDS()->RemoveFreeElement( face, fSubMesh, /*fromGroups=*/false );
1741 } // loop on volume faces to split them into triangles
1743 GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
1745 } // loop on volumes to split
1747 myLastCreatedNodes = newNodes;
1748 myLastCreatedElems = newElems;
1751 //=======================================================================
1752 //function : AddToSameGroups
1753 //purpose : add elemToAdd to the groups the elemInGroups belongs to
1754 //=======================================================================
1756 void SMESH_MeshEditor::AddToSameGroups (const SMDS_MeshElement* elemToAdd,
1757 const SMDS_MeshElement* elemInGroups,
1758 SMESHDS_Mesh * aMesh)
1760 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1761 if (!groups.empty()) {
1762 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1763 for ( ; grIt != groups.end(); grIt++ ) {
1764 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1765 if ( group && group->Contains( elemInGroups ))
1766 group->SMDSGroup().Add( elemToAdd );
1772 //=======================================================================
1773 //function : RemoveElemFromGroups
1774 //purpose : Remove removeelem to the groups the elemInGroups belongs to
1775 //=======================================================================
1776 void SMESH_MeshEditor::RemoveElemFromGroups (const SMDS_MeshElement* removeelem,
1777 SMESHDS_Mesh * aMesh)
1779 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1780 if (!groups.empty())
1782 set<SMESHDS_GroupBase*>::const_iterator GrIt = groups.begin();
1783 for (; GrIt != groups.end(); GrIt++)
1785 SMESHDS_Group* grp = dynamic_cast<SMESHDS_Group*>(*GrIt);
1786 if (!grp || grp->IsEmpty()) continue;
1787 grp->SMDSGroup().Remove(removeelem);
1792 //================================================================================
1794 * \brief Replace elemToRm by elemToAdd in the all groups
1796 //================================================================================
1798 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1799 const SMDS_MeshElement* elemToAdd,
1800 SMESHDS_Mesh * aMesh)
1802 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1803 if (!groups.empty()) {
1804 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1805 for ( ; grIt != groups.end(); grIt++ ) {
1806 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1807 if ( group && group->SMDSGroup().Remove( elemToRm ) && elemToAdd )
1808 group->SMDSGroup().Add( elemToAdd );
1813 //================================================================================
1815 * \brief Replace elemToRm by elemToAdd in the all groups
1817 //================================================================================
1819 void SMESH_MeshEditor::ReplaceElemInGroups (const SMDS_MeshElement* elemToRm,
1820 const vector<const SMDS_MeshElement*>& elemToAdd,
1821 SMESHDS_Mesh * aMesh)
1823 const set<SMESHDS_GroupBase*>& groups = aMesh->GetGroups();
1824 if (!groups.empty())
1826 set<SMESHDS_GroupBase*>::const_iterator grIt = groups.begin();
1827 for ( ; grIt != groups.end(); grIt++ ) {
1828 SMESHDS_Group* group = dynamic_cast<SMESHDS_Group*>( *grIt );
1829 if ( group && group->SMDSGroup().Remove( elemToRm ) )
1830 for ( int i = 0; i < elemToAdd.size(); ++i )
1831 group->SMDSGroup().Add( elemToAdd[ i ] );
1836 //=======================================================================
1837 //function : QuadToTri
1838 //purpose : Cut quadrangles into triangles.
1839 // theCrit is used to select a diagonal to cut
1840 //=======================================================================
1842 bool SMESH_MeshEditor::QuadToTri (TIDSortedElemSet & theElems,
1843 const bool the13Diag)
1845 myLastCreatedElems.Clear();
1846 myLastCreatedNodes.Clear();
1848 MESSAGE( "::QuadToTri()" );
1850 SMESHDS_Mesh * aMesh = GetMeshDS();
1852 Handle(Geom_Surface) surface;
1853 SMESH_MesherHelper helper( *GetMesh() );
1855 TIDSortedElemSet::iterator itElem;
1856 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
1857 const SMDS_MeshElement* elem = *itElem;
1858 if ( !elem || elem->GetType() != SMDSAbs_Face )
1860 bool isquad = elem->NbNodes()==4 || elem->NbNodes()==8;
1861 if(!isquad) continue;
1863 if(elem->NbNodes()==4) {
1864 // retrieve element nodes
1865 const SMDS_MeshNode* aNodes [4];
1866 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1868 while ( itN->more() )
1869 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1871 int aShapeId = FindShape( elem );
1872 const SMDS_MeshElement* newElem1 = 0;
1873 const SMDS_MeshElement* newElem2 = 0;
1875 newElem1 = aMesh->AddFace( aNodes[2], aNodes[0], aNodes[1] );
1876 newElem2 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
1879 newElem1 = aMesh->AddFace( aNodes[3], aNodes[0], aNodes[1] );
1880 newElem2 = aMesh->AddFace( aNodes[3], aNodes[1], aNodes[2] );
1882 myLastCreatedElems.Append(newElem1);
1883 myLastCreatedElems.Append(newElem2);
1884 // put a new triangle on the same shape and add to the same groups
1887 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1888 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1890 AddToSameGroups( newElem1, elem, aMesh );
1891 AddToSameGroups( newElem2, elem, aMesh );
1892 //aMesh->RemoveFreeElement(elem, aMesh->MeshElements(aShapeId), true);
1893 aMesh->RemoveElement( elem );
1896 // Quadratic quadrangle
1898 if( elem->NbNodes()==8 && elem->IsQuadratic() ) {
1900 // get surface elem is on
1901 int aShapeId = FindShape( elem );
1902 if ( aShapeId != helper.GetSubShapeID() ) {
1906 shape = aMesh->IndexToShape( aShapeId );
1907 if ( !shape.IsNull() && shape.ShapeType() == TopAbs_FACE ) {
1908 TopoDS_Face face = TopoDS::Face( shape );
1909 surface = BRep_Tool::Surface( face );
1910 if ( !surface.IsNull() )
1911 helper.SetSubShape( shape );
1915 const SMDS_MeshNode* aNodes [8];
1916 const SMDS_MeshNode* inFaceNode = 0;
1917 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
1919 while ( itN->more() ) {
1920 aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
1921 if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
1922 aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
1924 inFaceNode = aNodes[ i-1 ];
1928 // find middle point for (0,1,2,3)
1929 // and create a node in this point;
1931 if ( surface.IsNull() ) {
1933 p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
1937 TopoDS_Face geomFace = TopoDS::Face( helper.GetSubShape() );
1940 uv += helper.GetNodeUV( geomFace, aNodes[i], inFaceNode );
1942 p = surface->Value( uv.X(), uv.Y() ).XYZ();
1944 const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
1945 myLastCreatedNodes.Append(newN);
1947 // create a new element
1948 const SMDS_MeshElement* newElem1 = 0;
1949 const SMDS_MeshElement* newElem2 = 0;
1950 const SMDS_MeshNode* N[6];
1958 newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
1959 aNodes[6], aNodes[7], newN );
1960 newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
1961 newN, aNodes[4], aNodes[5] );
1970 newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
1971 aNodes[7], aNodes[4], newN );
1972 newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
1973 newN, aNodes[5], aNodes[6] );
1975 myLastCreatedElems.Append(newElem1);
1976 myLastCreatedElems.Append(newElem2);
1977 // put a new triangle on the same shape and add to the same groups
1980 aMesh->SetMeshElementOnShape( newElem1, aShapeId );
1981 aMesh->SetMeshElementOnShape( newElem2, aShapeId );
1983 AddToSameGroups( newElem1, elem, aMesh );
1984 AddToSameGroups( newElem2, elem, aMesh );
1985 aMesh->RemoveElement( elem );
1992 //=======================================================================
1993 //function : getAngle
1995 //=======================================================================
1997 double getAngle(const SMDS_MeshElement * tr1,
1998 const SMDS_MeshElement * tr2,
1999 const SMDS_MeshNode * n1,
2000 const SMDS_MeshNode * n2)
2002 double angle = 2*PI; // bad angle
2005 SMESH::Controls::TSequenceOfXYZ P1, P2;
2006 if ( !SMESH::Controls::NumericalFunctor::GetPoints( tr1, P1 ) ||
2007 !SMESH::Controls::NumericalFunctor::GetPoints( tr2, P2 ))
2010 if(!tr1->IsQuadratic())
2011 N1 = gp_Vec( P1(2) - P1(1) ) ^ gp_Vec( P1(3) - P1(1) );
2013 N1 = gp_Vec( P1(3) - P1(1) ) ^ gp_Vec( P1(5) - P1(1) );
2014 if ( N1.SquareMagnitude() <= gp::Resolution() )
2016 if(!tr2->IsQuadratic())
2017 N2 = gp_Vec( P2(2) - P2(1) ) ^ gp_Vec( P2(3) - P2(1) );
2019 N2 = gp_Vec( P2(3) - P2(1) ) ^ gp_Vec( P2(5) - P2(1) );
2020 if ( N2.SquareMagnitude() <= gp::Resolution() )
2023 // find the first diagonal node n1 in the triangles:
2024 // take in account a diagonal link orientation
2025 const SMDS_MeshElement *nFirst[2], *tr[] = { tr1, tr2 };
2026 for ( int t = 0; t < 2; t++ ) {
2027 SMDS_ElemIteratorPtr it = tr[ t ]->nodesIterator();
2028 int i = 0, iDiag = -1;
2029 while ( it->more()) {
2030 const SMDS_MeshElement *n = it->next();
2031 if ( n == n1 || n == n2 ) {
2035 if ( i - iDiag == 1 )
2036 nFirst[ t ] = ( n == n1 ? n2 : n1 );
2045 if ( nFirst[ 0 ] == nFirst[ 1 ] )
2048 angle = N1.Angle( N2 );
2053 // =================================================
2054 // class generating a unique ID for a pair of nodes
2055 // and able to return nodes by that ID
2056 // =================================================
2060 LinkID_Gen( const SMESHDS_Mesh* theMesh )
2061 :myMesh( theMesh ), myMaxID( theMesh->MaxNodeID() + 1)
2064 long GetLinkID (const SMDS_MeshNode * n1,
2065 const SMDS_MeshNode * n2) const
2067 return ( Min(n1->GetID(),n2->GetID()) * myMaxID + Max(n1->GetID(),n2->GetID()));
2070 bool GetNodes (const long theLinkID,
2071 const SMDS_MeshNode* & theNode1,
2072 const SMDS_MeshNode* & theNode2) const
2074 theNode1 = myMesh->FindNode( theLinkID / myMaxID );
2075 if ( !theNode1 ) return false;
2076 theNode2 = myMesh->FindNode( theLinkID % myMaxID );
2077 if ( !theNode2 ) return false;
2083 const SMESHDS_Mesh* myMesh;
2088 //=======================================================================
2089 //function : TriToQuad
2090 //purpose : Fuse neighbour triangles into quadrangles.
2091 // theCrit is used to select a neighbour to fuse with.
2092 // theMaxAngle is a max angle between element normals at which
2093 // fusion is still performed.
2094 //=======================================================================
2096 bool SMESH_MeshEditor::TriToQuad (TIDSortedElemSet & theElems,
2097 SMESH::Controls::NumericalFunctorPtr theCrit,
2098 const double theMaxAngle)
2100 myLastCreatedElems.Clear();
2101 myLastCreatedNodes.Clear();
2103 MESSAGE( "::TriToQuad()" );
2105 if ( !theCrit.get() )
2108 SMESHDS_Mesh * aMesh = GetMeshDS();
2110 // Prepare data for algo: build
2111 // 1. map of elements with their linkIDs
2112 // 2. map of linkIDs with their elements
2114 map< SMESH_TLink, list< const SMDS_MeshElement* > > mapLi_listEl;
2115 map< SMESH_TLink, list< const SMDS_MeshElement* > >::iterator itLE;
2116 map< const SMDS_MeshElement*, set< SMESH_TLink > > mapEl_setLi;
2117 map< const SMDS_MeshElement*, set< SMESH_TLink > >::iterator itEL;
2119 TIDSortedElemSet::iterator itElem;
2120 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2121 const SMDS_MeshElement* elem = *itElem;
2122 if(!elem || elem->GetType() != SMDSAbs_Face ) continue;
2123 bool IsTria = elem->NbNodes()==3 || (elem->NbNodes()==6 && elem->IsQuadratic());
2124 if(!IsTria) continue;
2126 // retrieve element nodes
2127 const SMDS_MeshNode* aNodes [4];
2128 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2131 aNodes[ i++ ] = cast2Node( itN->next() );
2132 aNodes[ 3 ] = aNodes[ 0 ];
2135 for ( i = 0; i < 3; i++ ) {
2136 SMESH_TLink link( aNodes[i], aNodes[i+1] );
2137 // check if elements sharing a link can be fused
2138 itLE = mapLi_listEl.find( link );
2139 if ( itLE != mapLi_listEl.end() ) {
2140 if ((*itLE).second.size() > 1 ) // consider only 2 elems adjacent by a link
2142 const SMDS_MeshElement* elem2 = (*itLE).second.front();
2143 //if ( FindShape( elem ) != FindShape( elem2 ))
2144 // continue; // do not fuse triangles laying on different shapes
2145 if ( getAngle( elem, elem2, aNodes[i], aNodes[i+1] ) > theMaxAngle )
2146 continue; // avoid making badly shaped quads
2147 (*itLE).second.push_back( elem );
2150 mapLi_listEl[ link ].push_back( elem );
2152 mapEl_setLi [ elem ].insert( link );
2155 // Clean the maps from the links shared by a sole element, ie
2156 // links to which only one element is bound in mapLi_listEl
2158 for ( itLE = mapLi_listEl.begin(); itLE != mapLi_listEl.end(); itLE++ ) {
2159 int nbElems = (*itLE).second.size();
2160 if ( nbElems < 2 ) {
2161 const SMDS_MeshElement* elem = (*itLE).second.front();
2162 SMESH_TLink link = (*itLE).first;
2163 mapEl_setLi[ elem ].erase( link );
2164 if ( mapEl_setLi[ elem ].empty() )
2165 mapEl_setLi.erase( elem );
2169 // Algo: fuse triangles into quadrangles
2171 while ( ! mapEl_setLi.empty() ) {
2172 // Look for the start element:
2173 // the element having the least nb of shared links
2174 const SMDS_MeshElement* startElem = 0;
2176 for ( itEL = mapEl_setLi.begin(); itEL != mapEl_setLi.end(); itEL++ ) {
2177 int nbLinks = (*itEL).second.size();
2178 if ( nbLinks < minNbLinks ) {
2179 startElem = (*itEL).first;
2180 minNbLinks = nbLinks;
2181 if ( minNbLinks == 1 )
2186 // search elements to fuse starting from startElem or links of elements
2187 // fused earlyer - startLinks
2188 list< SMESH_TLink > startLinks;
2189 while ( startElem || !startLinks.empty() ) {
2190 while ( !startElem && !startLinks.empty() ) {
2191 // Get an element to start, by a link
2192 SMESH_TLink linkId = startLinks.front();
2193 startLinks.pop_front();
2194 itLE = mapLi_listEl.find( linkId );
2195 if ( itLE != mapLi_listEl.end() ) {
2196 list< const SMDS_MeshElement* > & listElem = (*itLE).second;
2197 list< const SMDS_MeshElement* >::iterator itE = listElem.begin();
2198 for ( ; itE != listElem.end() ; itE++ )
2199 if ( mapEl_setLi.find( (*itE) ) != mapEl_setLi.end() )
2201 mapLi_listEl.erase( itLE );
2206 // Get candidates to be fused
2207 const SMDS_MeshElement *tr1 = startElem, *tr2 = 0, *tr3 = 0;
2208 const SMESH_TLink *link12, *link13;
2210 ASSERT( mapEl_setLi.find( tr1 ) != mapEl_setLi.end() );
2211 set< SMESH_TLink >& setLi = mapEl_setLi[ tr1 ];
2212 ASSERT( !setLi.empty() );
2213 set< SMESH_TLink >::iterator itLi;
2214 for ( itLi = setLi.begin(); itLi != setLi.end(); itLi++ )
2216 const SMESH_TLink & link = (*itLi);
2217 itLE = mapLi_listEl.find( link );
2218 if ( itLE == mapLi_listEl.end() )
2221 const SMDS_MeshElement* elem = (*itLE).second.front();
2223 elem = (*itLE).second.back();
2224 mapLi_listEl.erase( itLE );
2225 if ( mapEl_setLi.find( elem ) == mapEl_setLi.end())
2236 // add other links of elem to list of links to re-start from
2237 set< SMESH_TLink >& links = mapEl_setLi[ elem ];
2238 set< SMESH_TLink >::iterator it;
2239 for ( it = links.begin(); it != links.end(); it++ ) {
2240 const SMESH_TLink& link2 = (*it);
2241 if ( link2 != link )
2242 startLinks.push_back( link2 );
2246 // Get nodes of possible quadrangles
2247 const SMDS_MeshNode *n12 [4], *n13 [4];
2248 bool Ok12 = false, Ok13 = false;
2249 const SMDS_MeshNode *linkNode1, *linkNode2;
2251 linkNode1 = link12->first;
2252 linkNode2 = link12->second;
2253 if ( tr2 && getQuadrangleNodes( n12, linkNode1, linkNode2, tr1, tr2 ))
2257 linkNode1 = link13->first;
2258 linkNode2 = link13->second;
2259 if ( tr3 && getQuadrangleNodes( n13, linkNode1, linkNode2, tr1, tr3 ))
2263 // Choose a pair to fuse
2264 if ( Ok12 && Ok13 ) {
2265 SMDS_FaceOfNodes quad12 ( n12[ 0 ], n12[ 1 ], n12[ 2 ], n12[ 3 ] );
2266 SMDS_FaceOfNodes quad13 ( n13[ 0 ], n13[ 1 ], n13[ 2 ], n13[ 3 ] );
2267 double aBadRate12 = getBadRate( &quad12, theCrit );
2268 double aBadRate13 = getBadRate( &quad13, theCrit );
2269 if ( aBadRate13 < aBadRate12 )
2276 // and remove fused elems and removed links from the maps
2277 mapEl_setLi.erase( tr1 );
2279 mapEl_setLi.erase( tr2 );
2280 mapLi_listEl.erase( *link12 );
2281 if(tr1->NbNodes()==3) {
2282 const SMDS_MeshElement* newElem = 0;
2283 newElem = aMesh->AddFace(n12[0], n12[1], n12[2], n12[3] );
2284 myLastCreatedElems.Append(newElem);
2285 AddToSameGroups( newElem, tr1, aMesh );
2286 int aShapeId = tr1->getshapeId();
2289 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2291 aMesh->RemoveElement( tr1 );
2292 aMesh->RemoveElement( tr2 );
2295 const SMDS_MeshNode* N1 [6];
2296 const SMDS_MeshNode* N2 [6];
2297 GetNodesFromTwoTria(tr1,tr2,N1,N2);
2298 // now we receive following N1 and N2 (using numeration as above image)
2299 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2300 // i.e. first nodes from both arrays determ new diagonal
2301 const SMDS_MeshNode* aNodes[8];
2310 const SMDS_MeshElement* newElem = 0;
2311 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2312 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2313 myLastCreatedElems.Append(newElem);
2314 AddToSameGroups( newElem, tr1, aMesh );
2315 int aShapeId = tr1->getshapeId();
2318 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2320 aMesh->RemoveElement( tr1 );
2321 aMesh->RemoveElement( tr2 );
2322 // remove middle node (9)
2323 GetMeshDS()->RemoveNode( N1[4] );
2327 mapEl_setLi.erase( tr3 );
2328 mapLi_listEl.erase( *link13 );
2329 if(tr1->NbNodes()==3) {
2330 const SMDS_MeshElement* newElem = 0;
2331 newElem = aMesh->AddFace(n13[0], n13[1], n13[2], n13[3] );
2332 myLastCreatedElems.Append(newElem);
2333 AddToSameGroups( newElem, tr1, aMesh );
2334 int aShapeId = tr1->getshapeId();
2337 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2339 aMesh->RemoveElement( tr1 );
2340 aMesh->RemoveElement( tr3 );
2343 const SMDS_MeshNode* N1 [6];
2344 const SMDS_MeshNode* N2 [6];
2345 GetNodesFromTwoTria(tr1,tr3,N1,N2);
2346 // now we receive following N1 and N2 (using numeration as above image)
2347 // tria1 : (1 2 4 5 9 7) and tria2 : (3 4 2 8 9 6)
2348 // i.e. first nodes from both arrays determ new diagonal
2349 const SMDS_MeshNode* aNodes[8];
2358 const SMDS_MeshElement* newElem = 0;
2359 newElem = aMesh->AddFace(aNodes[0], aNodes[1], aNodes[2], aNodes[3],
2360 aNodes[4], aNodes[5], aNodes[6], aNodes[7]);
2361 myLastCreatedElems.Append(newElem);
2362 AddToSameGroups( newElem, tr1, aMesh );
2363 int aShapeId = tr1->getshapeId();
2366 aMesh->SetMeshElementOnShape( newElem, aShapeId );
2368 aMesh->RemoveElement( tr1 );
2369 aMesh->RemoveElement( tr3 );
2370 // remove middle node (9)
2371 GetMeshDS()->RemoveNode( N1[4] );
2375 // Next element to fuse: the rejected one
2377 startElem = Ok12 ? tr3 : tr2;
2379 } // if ( startElem )
2380 } // while ( startElem || !startLinks.empty() )
2381 } // while ( ! mapEl_setLi.empty() )
2387 /*#define DUMPSO(txt) \
2388 // cout << txt << endl;
2389 //=============================================================================
2393 //=============================================================================
2394 static void swap( int i1, int i2, int idNodes[], gp_Pnt P[] )
2398 int tmp = idNodes[ i1 ];
2399 idNodes[ i1 ] = idNodes[ i2 ];
2400 idNodes[ i2 ] = tmp;
2401 gp_Pnt Ptmp = P[ i1 ];
2404 DUMPSO( i1 << "(" << idNodes[ i2 ] << ") <-> " << i2 << "(" << idNodes[ i1 ] << ")");
2407 //=======================================================================
2408 //function : SortQuadNodes
2409 //purpose : Set 4 nodes of a quadrangle face in a good order.
2410 // Swap 1<->2 or 2<->3 nodes and correspondingly return
2412 //=======================================================================
2414 int SMESH_MeshEditor::SortQuadNodes (const SMDS_Mesh * theMesh,
2419 for ( i = 0; i < 4; i++ ) {
2420 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2422 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2425 gp_Vec V1(P[0], P[1]);
2426 gp_Vec V2(P[0], P[2]);
2427 gp_Vec V3(P[0], P[3]);
2429 gp_Vec Cross1 = V1 ^ V2;
2430 gp_Vec Cross2 = V2 ^ V3;
2433 if (Cross1.Dot(Cross2) < 0)
2438 if (Cross1.Dot(Cross2) < 0)
2442 swap ( i, i + 1, idNodes, P );
2444 // for ( int ii = 0; ii < 4; ii++ ) {
2445 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2446 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2452 //=======================================================================
2453 //function : SortHexaNodes
2454 //purpose : Set 8 nodes of a hexahedron in a good order.
2455 // Return success status
2456 //=======================================================================
2458 bool SMESH_MeshEditor::SortHexaNodes (const SMDS_Mesh * theMesh,
2463 DUMPSO( "INPUT: ========================================");
2464 for ( i = 0; i < 8; i++ ) {
2465 const SMDS_MeshNode *n = theMesh->FindNode( idNodes[i] );
2466 if ( !n ) return false;
2467 P[ i ].SetCoord( n->X(), n->Y(), n->Z() );
2468 DUMPSO( i << "(" << idNodes[i] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2470 DUMPSO( "========================================");
2473 set<int> faceNodes; // ids of bottom face nodes, to be found
2474 set<int> checkedId1; // ids of tried 2-nd nodes
2475 Standard_Real leastDist = DBL_MAX; // dist of the 4-th node from 123 plane
2476 const Standard_Real tol = 1.e-6; // tolerance to find nodes in plane
2477 int iMin, iLoop1 = 0;
2479 // Loop to try the 2-nd nodes
2481 while ( leastDist > DBL_MIN && ++iLoop1 < 8 )
2483 // Find not checked 2-nd node
2484 for ( i = 1; i < 8; i++ )
2485 if ( checkedId1.find( idNodes[i] ) == checkedId1.end() ) {
2486 int id1 = idNodes[i];
2487 swap ( 1, i, idNodes, P );
2488 checkedId1.insert ( id1 );
2492 // Find the 3-d node so that 1-2-3 triangle to be on a hexa face,
2493 // ie that all but meybe one (id3 which is on the same face) nodes
2494 // lay on the same side from the triangle plane.
2496 bool manyInPlane = false; // more than 4 nodes lay in plane
2498 while ( ++iLoop2 < 6 ) {
2500 // get 1-2-3 plane coeffs
2501 Standard_Real A, B, C, D;
2502 gp_Vec N = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2503 if ( N.SquareMagnitude() > gp::Resolution() )
2505 gp_Pln pln ( P[0], N );
2506 pln.Coefficients( A, B, C, D );
2508 // find the node (iMin) closest to pln
2509 Standard_Real dist[ 8 ], minDist = DBL_MAX;
2511 for ( i = 3; i < 8; i++ ) {
2512 dist[i] = A * P[i].X() + B * P[i].Y() + C * P[i].Z() + D;
2513 if ( fabs( dist[i] ) < minDist ) {
2514 minDist = fabs( dist[i] );
2517 if ( fabs( dist[i] ) <= tol )
2518 idInPln.insert( idNodes[i] );
2521 // there should not be more than 4 nodes in bottom plane
2522 if ( idInPln.size() > 1 )
2524 DUMPSO( "### idInPln.size() = " << idInPln.size());
2525 // idInPlane does not contain the first 3 nodes
2526 if ( manyInPlane || idInPln.size() == 5)
2527 return false; // all nodes in one plane
2530 // set the 1-st node to be not in plane
2531 for ( i = 3; i < 8; i++ ) {
2532 if ( idInPln.find( idNodes[ i ] ) == idInPln.end() ) {
2533 DUMPSO( "### Reset 0-th node");
2534 swap( 0, i, idNodes, P );
2539 // reset to re-check second nodes
2540 leastDist = DBL_MAX;
2544 break; // from iLoop2;
2547 // check that the other 4 nodes are on the same side
2548 bool sameSide = true;
2549 bool isNeg = dist[ iMin == 3 ? 4 : 3 ] <= 0.;
2550 for ( i = 3; sameSide && i < 8; i++ ) {
2552 sameSide = ( isNeg == dist[i] <= 0.);
2555 // keep best solution
2556 if ( sameSide && minDist < leastDist ) {
2557 leastDist = minDist;
2559 faceNodes.insert( idNodes[ 1 ] );
2560 faceNodes.insert( idNodes[ 2 ] );
2561 faceNodes.insert( idNodes[ iMin ] );
2562 DUMPSO( "loop " << iLoop2 << " id2 " << idNodes[ 1 ] << " id3 " << idNodes[ 2 ]
2563 << " leastDist = " << leastDist);
2564 if ( leastDist <= DBL_MIN )
2569 // set next 3-d node to check
2570 int iNext = 2 + iLoop2;
2572 DUMPSO( "Try 2-nd");
2573 swap ( 2, iNext, idNodes, P );
2575 } // while ( iLoop2 < 6 )
2578 if ( faceNodes.empty() ) return false;
2580 // Put the faceNodes in proper places
2581 for ( i = 4; i < 8; i++ ) {
2582 if ( faceNodes.find( idNodes[ i ] ) != faceNodes.end() ) {
2583 // find a place to put
2585 while ( faceNodes.find( idNodes[ iTo ] ) != faceNodes.end() )
2587 DUMPSO( "Set faceNodes");
2588 swap ( iTo, i, idNodes, P );
2593 // Set nodes of the found bottom face in good order
2594 DUMPSO( " Found bottom face: ");
2595 i = SortQuadNodes( theMesh, idNodes );
2597 gp_Pnt Ptmp = P[ i ];
2602 // for ( int ii = 0; ii < 4; ii++ ) {
2603 // const SMDS_MeshNode *n = theMesh->FindNode( idNodes[ii] );
2604 // DUMPSO( ii << "(" << idNodes[ii] <<") : "<<n->X()<<" "<<n->Y()<<" "<<n->Z());
2607 // Gravity center of the top and bottom faces
2608 gp_Pnt aGCb = ( P[0].XYZ() + P[1].XYZ() + P[2].XYZ() + P[3].XYZ() ) / 4.;
2609 gp_Pnt aGCt = ( P[4].XYZ() + P[5].XYZ() + P[6].XYZ() + P[7].XYZ() ) / 4.;
2611 // Get direction from the bottom to the top face
2612 gp_Vec upDir ( aGCb, aGCt );
2613 Standard_Real upDirSize = upDir.Magnitude();
2614 if ( upDirSize <= gp::Resolution() ) return false;
2617 // Assure that the bottom face normal points up
2618 gp_Vec Nb = gp_Vec (P[0], P[1]).Crossed( gp_Vec (P[0], P[2]) );
2619 Nb += gp_Vec (P[0], P[2]).Crossed( gp_Vec (P[0], P[3]) );
2620 if ( Nb.Dot( upDir ) < 0 ) {
2621 DUMPSO( "Reverse bottom face");
2622 swap( 1, 3, idNodes, P );
2625 // Find 5-th node - the one closest to the 1-st among the last 4 nodes.
2626 Standard_Real minDist = DBL_MAX;
2627 for ( i = 4; i < 8; i++ ) {
2628 // projection of P[i] to the plane defined by P[0] and upDir
2629 gp_Pnt Pp = P[i].Translated( upDir * ( upDir.Dot( gp_Vec( P[i], P[0] ))));
2630 Standard_Real sqDist = P[0].SquareDistance( Pp );
2631 if ( sqDist < minDist ) {
2636 DUMPSO( "Set 4-th");
2637 swap ( 4, iMin, idNodes, P );
2639 // Set nodes of the top face in good order
2640 DUMPSO( "Sort top face");
2641 i = SortQuadNodes( theMesh, &idNodes[4] );
2644 gp_Pnt Ptmp = P[ i ];
2649 // Assure that direction of the top face normal is from the bottom face
2650 gp_Vec Nt = gp_Vec (P[4], P[5]).Crossed( gp_Vec (P[4], P[6]) );
2651 Nt += gp_Vec (P[4], P[6]).Crossed( gp_Vec (P[4], P[7]) );
2652 if ( Nt.Dot( upDir ) < 0 ) {
2653 DUMPSO( "Reverse top face");
2654 swap( 5, 7, idNodes, P );
2657 // DUMPSO( "OUTPUT: ========================================");
2658 // for ( i = 0; i < 8; i++ ) {
2659 // float *p = ugrid->GetPoint(idNodes[i]);
2660 // DUMPSO( i << "(" << idNodes[i] << ") : " << p[0] << " " << p[1] << " " << p[2]);
2666 //================================================================================
2668 * \brief Return nodes linked to the given one
2669 * \param theNode - the node
2670 * \param linkedNodes - the found nodes
2671 * \param type - the type of elements to check
2673 * Medium nodes are ignored
2675 //================================================================================
2677 void SMESH_MeshEditor::GetLinkedNodes( const SMDS_MeshNode* theNode,
2678 TIDSortedElemSet & linkedNodes,
2679 SMDSAbs_ElementType type )
2681 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(type);
2682 while ( elemIt->more() )
2684 const SMDS_MeshElement* elem = elemIt->next();
2685 if(elem->GetType() == SMDSAbs_0DElement)
2688 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
2689 if ( elem->GetType() == SMDSAbs_Volume )
2691 SMDS_VolumeTool vol( elem );
2692 while ( nodeIt->more() ) {
2693 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2694 if ( theNode != n && vol.IsLinked( theNode, n ))
2695 linkedNodes.insert( n );
2700 for ( int i = 0; nodeIt->more(); ++i ) {
2701 const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
2702 if ( n == theNode ) {
2703 int iBefore = i - 1;
2705 if ( elem->IsQuadratic() ) {
2706 int nb = elem->NbNodes() / 2;
2707 iAfter = SMESH_MesherHelper::WrapIndex( iAfter, nb );
2708 iBefore = SMESH_MesherHelper::WrapIndex( iBefore, nb );
2710 linkedNodes.insert( elem->GetNodeWrap( iAfter ));
2711 linkedNodes.insert( elem->GetNodeWrap( iBefore ));
2718 //=======================================================================
2719 //function : laplacianSmooth
2720 //purpose : pulls theNode toward the center of surrounding nodes directly
2721 // connected to that node along an element edge
2722 //=======================================================================
2724 void laplacianSmooth(const SMDS_MeshNode* theNode,
2725 const Handle(Geom_Surface)& theSurface,
2726 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2728 // find surrounding nodes
2730 TIDSortedElemSet nodeSet;
2731 SMESH_MeshEditor::GetLinkedNodes( theNode, nodeSet, SMDSAbs_Face );
2733 // compute new coodrs
2735 double coord[] = { 0., 0., 0. };
2736 TIDSortedElemSet::iterator nodeSetIt = nodeSet.begin();
2737 for ( ; nodeSetIt != nodeSet.end(); nodeSetIt++ ) {
2738 const SMDS_MeshNode* node = cast2Node(*nodeSetIt);
2739 if ( theSurface.IsNull() ) { // smooth in 3D
2740 coord[0] += node->X();
2741 coord[1] += node->Y();
2742 coord[2] += node->Z();
2744 else { // smooth in 2D
2745 ASSERT( theUVMap.find( node ) != theUVMap.end() );
2746 gp_XY* uv = theUVMap[ node ];
2747 coord[0] += uv->X();
2748 coord[1] += uv->Y();
2751 int nbNodes = nodeSet.size();
2754 coord[0] /= nbNodes;
2755 coord[1] /= nbNodes;
2757 if ( !theSurface.IsNull() ) {
2758 ASSERT( theUVMap.find( theNode ) != theUVMap.end() );
2759 theUVMap[ theNode ]->SetCoord( coord[0], coord[1] );
2760 gp_Pnt p3d = theSurface->Value( coord[0], coord[1] );
2766 coord[2] /= nbNodes;
2770 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(coord[0],coord[1],coord[2]);
2773 //=======================================================================
2774 //function : centroidalSmooth
2775 //purpose : pulls theNode toward the element-area-weighted centroid of the
2776 // surrounding elements
2777 //=======================================================================
2779 void centroidalSmooth(const SMDS_MeshNode* theNode,
2780 const Handle(Geom_Surface)& theSurface,
2781 map< const SMDS_MeshNode*, gp_XY* >& theUVMap)
2783 gp_XYZ aNewXYZ(0.,0.,0.);
2784 SMESH::Controls::Area anAreaFunc;
2785 double totalArea = 0.;
2790 SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator(SMDSAbs_Face);
2791 while ( elemIt->more() )
2793 const SMDS_MeshElement* elem = elemIt->next();
2796 gp_XYZ elemCenter(0.,0.,0.);
2797 SMESH::Controls::TSequenceOfXYZ aNodePoints;
2798 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2799 int nn = elem->NbNodes();
2800 if(elem->IsQuadratic()) nn = nn/2;
2802 //while ( itN->more() ) {
2804 const SMDS_MeshNode* aNode = static_cast<const SMDS_MeshNode*>( itN->next() );
2806 gp_XYZ aP( aNode->X(), aNode->Y(), aNode->Z() );
2807 aNodePoints.push_back( aP );
2808 if ( !theSurface.IsNull() ) { // smooth in 2D
2809 ASSERT( theUVMap.find( aNode ) != theUVMap.end() );
2810 gp_XY* uv = theUVMap[ aNode ];
2811 aP.SetCoord( uv->X(), uv->Y(), 0. );
2815 double elemArea = anAreaFunc.GetValue( aNodePoints );
2816 totalArea += elemArea;
2818 aNewXYZ += elemCenter * elemArea;
2820 aNewXYZ /= totalArea;
2821 if ( !theSurface.IsNull() ) {
2822 theUVMap[ theNode ]->SetCoord( aNewXYZ.X(), aNewXYZ.Y() );
2823 aNewXYZ = theSurface->Value( aNewXYZ.X(), aNewXYZ.Y() ).XYZ();
2828 const_cast< SMDS_MeshNode* >( theNode )->setXYZ(aNewXYZ.X(),aNewXYZ.Y(),aNewXYZ.Z());
2831 //=======================================================================
2832 //function : getClosestUV
2833 //purpose : return UV of closest projection
2834 //=======================================================================
2836 static bool getClosestUV (Extrema_GenExtPS& projector,
2837 const gp_Pnt& point,
2840 projector.Perform( point );
2841 if ( projector.IsDone() ) {
2842 double u, v, minVal = DBL_MAX;
2843 for ( int i = projector.NbExt(); i > 0; i-- )
2844 if ( projector.Value( i ) < minVal ) {
2845 minVal = projector.Value( i );
2846 projector.Point( i ).Parameter( u, v );
2848 result.SetCoord( u, v );
2854 //=======================================================================
2856 //purpose : Smooth theElements during theNbIterations or until a worst
2857 // element has aspect ratio <= theTgtAspectRatio.
2858 // Aspect Ratio varies in range [1.0, inf].
2859 // If theElements is empty, the whole mesh is smoothed.
2860 // theFixedNodes contains additionally fixed nodes. Nodes built
2861 // on edges and boundary nodes are always fixed.
2862 //=======================================================================
2864 void SMESH_MeshEditor::Smooth (TIDSortedElemSet & theElems,
2865 set<const SMDS_MeshNode*> & theFixedNodes,
2866 const SmoothMethod theSmoothMethod,
2867 const int theNbIterations,
2868 double theTgtAspectRatio,
2871 myLastCreatedElems.Clear();
2872 myLastCreatedNodes.Clear();
2874 MESSAGE((theSmoothMethod==LAPLACIAN ? "LAPLACIAN" : "CENTROIDAL") << "--::Smooth()");
2876 if ( theTgtAspectRatio < 1.0 )
2877 theTgtAspectRatio = 1.0;
2879 const double disttol = 1.e-16;
2881 SMESH::Controls::AspectRatio aQualityFunc;
2883 SMESHDS_Mesh* aMesh = GetMeshDS();
2885 if ( theElems.empty() ) {
2886 // add all faces to theElems
2887 SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
2888 while ( fIt->more() ) {
2889 const SMDS_MeshElement* face = fIt->next();
2890 theElems.insert( face );
2893 // get all face ids theElems are on
2894 set< int > faceIdSet;
2895 TIDSortedElemSet::iterator itElem;
2897 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
2898 int fId = FindShape( *itElem );
2899 // check that corresponding submesh exists and a shape is face
2901 faceIdSet.find( fId ) == faceIdSet.end() &&
2902 aMesh->MeshElements( fId )) {
2903 TopoDS_Shape F = aMesh->IndexToShape( fId );
2904 if ( !F.IsNull() && F.ShapeType() == TopAbs_FACE )
2905 faceIdSet.insert( fId );
2908 faceIdSet.insert( 0 ); // to smooth elements that are not on any TopoDS_Face
2910 // ===============================================
2911 // smooth elements on each TopoDS_Face separately
2912 // ===============================================
2914 set< int >::reverse_iterator fId = faceIdSet.rbegin(); // treate 0 fId at the end
2915 for ( ; fId != faceIdSet.rend(); ++fId ) {
2916 // get face surface and submesh
2917 Handle(Geom_Surface) surface;
2918 SMESHDS_SubMesh* faceSubMesh = 0;
2920 double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
2921 double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
2922 bool isUPeriodic = false, isVPeriodic = false;
2924 face = TopoDS::Face( aMesh->IndexToShape( *fId ));
2925 surface = BRep_Tool::Surface( face );
2926 faceSubMesh = aMesh->MeshElements( *fId );
2927 fToler2 = BRep_Tool::Tolerance( face );
2928 fToler2 *= fToler2 * 10.;
2929 isUPeriodic = surface->IsUPeriodic();
2931 vPeriod = surface->UPeriod();
2932 isVPeriodic = surface->IsVPeriodic();
2934 uPeriod = surface->VPeriod();
2935 surface->Bounds( u1, u2, v1, v2 );
2937 // ---------------------------------------------------------
2938 // for elements on a face, find movable and fixed nodes and
2939 // compute UV for them
2940 // ---------------------------------------------------------
2941 bool checkBoundaryNodes = false;
2942 bool isQuadratic = false;
2943 set<const SMDS_MeshNode*> setMovableNodes;
2944 map< const SMDS_MeshNode*, gp_XY* > uvMap, uvMap2;
2945 list< gp_XY > listUV; // uvs the 2 uvMaps refer to
2946 list< const SMDS_MeshElement* > elemsOnFace;
2948 Extrema_GenExtPS projector;
2949 GeomAdaptor_Surface surfAdaptor;
2950 if ( !surface.IsNull() ) {
2951 surfAdaptor.Load( surface );
2952 projector.Initialize( surfAdaptor, 20,20, 1e-5,1e-5 );
2954 int nbElemOnFace = 0;
2955 itElem = theElems.begin();
2956 // loop on not yet smoothed elements: look for elems on a face
2957 while ( itElem != theElems.end() ) {
2958 if ( faceSubMesh && nbElemOnFace == faceSubMesh->NbElements() )
2959 break; // all elements found
2961 const SMDS_MeshElement* elem = *itElem;
2962 if ( !elem || elem->GetType() != SMDSAbs_Face || elem->NbNodes() < 3 ||
2963 ( faceSubMesh && !faceSubMesh->Contains( elem ))) {
2967 elemsOnFace.push_back( elem );
2968 theElems.erase( itElem++ );
2972 isQuadratic = elem->IsQuadratic();
2974 // get movable nodes of elem
2975 const SMDS_MeshNode* node;
2976 SMDS_TypeOfPosition posType;
2977 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
2978 int nn = 0, nbn = elem->NbNodes();
2979 if(elem->IsQuadratic())
2981 while ( nn++ < nbn ) {
2982 node = static_cast<const SMDS_MeshNode*>( itN->next() );
2983 const SMDS_PositionPtr& pos = node->GetPosition();
2984 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
2985 if (posType != SMDS_TOP_EDGE &&
2986 posType != SMDS_TOP_VERTEX &&
2987 theFixedNodes.find( node ) == theFixedNodes.end())
2989 // check if all faces around the node are on faceSubMesh
2990 // because a node on edge may be bound to face
2991 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
2993 if ( faceSubMesh ) {
2994 while ( eIt->more() && all ) {
2995 const SMDS_MeshElement* e = eIt->next();
2996 all = faceSubMesh->Contains( e );
3000 setMovableNodes.insert( node );
3002 checkBoundaryNodes = true;
3004 if ( posType == SMDS_TOP_3DSPACE )
3005 checkBoundaryNodes = true;
3008 if ( surface.IsNull() )
3011 // get nodes to check UV
3012 list< const SMDS_MeshNode* > uvCheckNodes;
3013 itN = elem->nodesIterator();
3014 nn = 0; nbn = elem->NbNodes();
3015 if(elem->IsQuadratic())
3017 while ( nn++ < nbn ) {
3018 node = static_cast<const SMDS_MeshNode*>( itN->next() );
3019 if ( uvMap.find( node ) == uvMap.end() )
3020 uvCheckNodes.push_back( node );
3021 // add nodes of elems sharing node
3022 // SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator(SMDSAbs_Face);
3023 // while ( eIt->more() ) {
3024 // const SMDS_MeshElement* e = eIt->next();
3025 // if ( e != elem ) {
3026 // SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3027 // while ( nIt->more() ) {
3028 // const SMDS_MeshNode* n =
3029 // static_cast<const SMDS_MeshNode*>( nIt->next() );
3030 // if ( uvMap.find( n ) == uvMap.end() )
3031 // uvCheckNodes.push_back( n );
3037 list< const SMDS_MeshNode* >::iterator n = uvCheckNodes.begin();
3038 for ( ; n != uvCheckNodes.end(); ++n ) {
3041 const SMDS_PositionPtr& pos = node->GetPosition();
3042 posType = pos ? pos->GetTypeOfPosition() : SMDS_TOP_3DSPACE;
3044 switch ( posType ) {
3045 case SMDS_TOP_FACE: {
3046 SMDS_FacePosition* fPos = ( SMDS_FacePosition* ) pos;
3047 uv.SetCoord( fPos->GetUParameter(), fPos->GetVParameter() );
3050 case SMDS_TOP_EDGE: {
3051 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3052 Handle(Geom2d_Curve) pcurve;
3053 if ( !S.IsNull() && S.ShapeType() == TopAbs_EDGE )
3054 pcurve = BRep_Tool::CurveOnSurface( TopoDS::Edge( S ), face, f,l );
3055 if ( !pcurve.IsNull() ) {
3056 double u = (( SMDS_EdgePosition* ) pos )->GetUParameter();
3057 uv = pcurve->Value( u ).XY();
3061 case SMDS_TOP_VERTEX: {
3062 TopoDS_Shape S = aMesh->IndexToShape( node->getshapeId() );
3063 if ( !S.IsNull() && S.ShapeType() == TopAbs_VERTEX )
3064 uv = BRep_Tool::Parameters( TopoDS::Vertex( S ), face ).XY();
3069 // check existing UV
3070 bool project = true;
3071 gp_Pnt pNode ( node->X(), node->Y(), node->Z() );
3072 double dist1 = DBL_MAX, dist2 = 0;
3073 if ( posType != SMDS_TOP_3DSPACE ) {
3074 dist1 = pNode.SquareDistance( surface->Value( uv.X(), uv.Y() ));
3075 project = dist1 > fToler2;
3077 if ( project ) { // compute new UV
3079 if ( !getClosestUV( projector, pNode, newUV )) {
3080 MESSAGE("Node Projection Failed " << node);
3084 newUV.SetX( ElCLib::InPeriod( newUV.X(), u1, u2 ));
3086 newUV.SetY( ElCLib::InPeriod( newUV.Y(), v1, v2 ));
3088 if ( posType != SMDS_TOP_3DSPACE )
3089 dist2 = pNode.SquareDistance( surface->Value( newUV.X(), newUV.Y() ));
3090 if ( dist2 < dist1 )
3094 // store UV in the map
3095 listUV.push_back( uv );
3096 uvMap.insert( make_pair( node, &listUV.back() ));
3098 } // loop on not yet smoothed elements
3100 if ( !faceSubMesh || nbElemOnFace != faceSubMesh->NbElements() )
3101 checkBoundaryNodes = true;
3103 // fix nodes on mesh boundary
3105 if ( checkBoundaryNodes ) {
3106 map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
3107 map< NLink, int >::iterator link_nb;
3108 // put all elements links to linkNbMap
3109 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3110 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3111 const SMDS_MeshElement* elem = (*elemIt);
3112 int nbn = elem->NbNodes();
3113 if(elem->IsQuadratic())
3115 // loop on elem links: insert them in linkNbMap
3116 const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
3117 for ( int iN = 0; iN < nbn; ++iN ) {
3118 curNode = elem->GetNode( iN );
3120 if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
3121 else link = make_pair( prevNode , curNode );
3123 link_nb = linkNbMap.find( link );
3124 if ( link_nb == linkNbMap.end() )
3125 linkNbMap.insert( make_pair ( link, 1 ));
3130 // remove nodes that are in links encountered only once from setMovableNodes
3131 for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
3132 if ( link_nb->second == 1 ) {
3133 setMovableNodes.erase( link_nb->first.first );
3134 setMovableNodes.erase( link_nb->first.second );
3139 // -----------------------------------------------------
3140 // for nodes on seam edge, compute one more UV ( uvMap2 );
3141 // find movable nodes linked to nodes on seam and which
3142 // are to be smoothed using the second UV ( uvMap2 )
3143 // -----------------------------------------------------
3145 set<const SMDS_MeshNode*> nodesNearSeam; // to smooth using uvMap2
3146 if ( !surface.IsNull() ) {
3147 TopExp_Explorer eExp( face, TopAbs_EDGE );
3148 for ( ; eExp.More(); eExp.Next() ) {
3149 TopoDS_Edge edge = TopoDS::Edge( eExp.Current() );
3150 if ( !BRep_Tool::IsClosed( edge, face ))
3152 SMESHDS_SubMesh* sm = aMesh->MeshElements( edge );
3153 if ( !sm ) continue;
3154 // find out which parameter varies for a node on seam
3157 Handle(Geom2d_Curve) pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3158 if ( pcurve.IsNull() ) continue;
3159 uv1 = pcurve->Value( f );
3161 pcurve = BRep_Tool::CurveOnSurface( edge, face, f, l );
3162 if ( pcurve.IsNull() ) continue;
3163 uv2 = pcurve->Value( f );
3164 int iPar = Abs( uv1.X() - uv2.X() ) > Abs( uv1.Y() - uv2.Y() ) ? 1 : 2;
3166 if ( uv1.Coord( iPar ) > uv2.Coord( iPar )) {
3167 gp_Pnt2d tmp = uv1; uv1 = uv2; uv2 = tmp;
3169 // get nodes on seam and its vertices
3170 list< const SMDS_MeshNode* > seamNodes;
3171 SMDS_NodeIteratorPtr nSeamIt = sm->GetNodes();
3172 while ( nSeamIt->more() ) {
3173 const SMDS_MeshNode* node = nSeamIt->next();
3174 if ( !isQuadratic || !IsMedium( node ))
3175 seamNodes.push_back( node );
3177 TopExp_Explorer vExp( edge, TopAbs_VERTEX );
3178 for ( ; vExp.More(); vExp.Next() ) {
3179 sm = aMesh->MeshElements( vExp.Current() );
3181 nSeamIt = sm->GetNodes();
3182 while ( nSeamIt->more() )
3183 seamNodes.push_back( nSeamIt->next() );
3186 // loop on nodes on seam
3187 list< const SMDS_MeshNode* >::iterator noSeIt = seamNodes.begin();
3188 for ( ; noSeIt != seamNodes.end(); ++noSeIt ) {
3189 const SMDS_MeshNode* nSeam = *noSeIt;
3190 map< const SMDS_MeshNode*, gp_XY* >::iterator n_uv = uvMap.find( nSeam );
3191 if ( n_uv == uvMap.end() )
3194 n_uv->second->SetCoord( iPar, uv1.Coord( iPar ));
3195 // set the second UV
3196 listUV.push_back( *n_uv->second );
3197 listUV.back().SetCoord( iPar, uv2.Coord( iPar ));
3198 if ( uvMap2.empty() )
3199 uvMap2 = uvMap; // copy the uvMap contents
3200 uvMap2[ nSeam ] = &listUV.back();
3202 // collect movable nodes linked to ones on seam in nodesNearSeam
3203 SMDS_ElemIteratorPtr eIt = nSeam->GetInverseElementIterator(SMDSAbs_Face);
3204 while ( eIt->more() ) {
3205 const SMDS_MeshElement* e = eIt->next();
3206 int nbUseMap1 = 0, nbUseMap2 = 0;
3207 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3208 int nn = 0, nbn = e->NbNodes();
3209 if(e->IsQuadratic()) nbn = nbn/2;
3210 while ( nn++ < nbn )
3212 const SMDS_MeshNode* n =
3213 static_cast<const SMDS_MeshNode*>( nIt->next() );
3215 setMovableNodes.find( n ) == setMovableNodes.end() )
3217 // add only nodes being closer to uv2 than to uv1
3218 gp_Pnt pMid (0.5 * ( n->X() + nSeam->X() ),
3219 0.5 * ( n->Y() + nSeam->Y() ),
3220 0.5 * ( n->Z() + nSeam->Z() ));
3222 getClosestUV( projector, pMid, uv );
3223 if ( uv.Coord( iPar ) > uvMap[ n ]->Coord( iPar ) ) {
3224 nodesNearSeam.insert( n );
3230 // for centroidalSmooth all element nodes must
3231 // be on one side of a seam
3232 if ( theSmoothMethod == CENTROIDAL && nbUseMap1 && nbUseMap2 ) {
3233 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
3235 while ( nn++ < nbn ) {
3236 const SMDS_MeshNode* n =
3237 static_cast<const SMDS_MeshNode*>( nIt->next() );
3238 setMovableNodes.erase( n );
3242 } // loop on nodes on seam
3243 } // loop on edge of a face
3244 } // if ( !face.IsNull() )
3246 if ( setMovableNodes.empty() ) {
3247 MESSAGE( "Face id : " << *fId << " - NO SMOOTHING: no nodes to move!!!");
3248 continue; // goto next face
3256 double maxRatio = -1., maxDisplacement = -1.;
3257 set<const SMDS_MeshNode*>::iterator nodeToMove;
3258 for ( it = 0; it < theNbIterations; it++ ) {
3259 maxDisplacement = 0.;
3260 nodeToMove = setMovableNodes.begin();
3261 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3262 const SMDS_MeshNode* node = (*nodeToMove);
3263 gp_XYZ aPrevPos ( node->X(), node->Y(), node->Z() );
3266 bool map2 = ( nodesNearSeam.find( node ) != nodesNearSeam.end() );
3267 if ( theSmoothMethod == LAPLACIAN )
3268 laplacianSmooth( node, surface, map2 ? uvMap2 : uvMap );
3270 centroidalSmooth( node, surface, map2 ? uvMap2 : uvMap );
3272 // node displacement
3273 gp_XYZ aNewPos ( node->X(), node->Y(), node->Z() );
3274 Standard_Real aDispl = (aPrevPos - aNewPos).SquareModulus();
3275 if ( aDispl > maxDisplacement )
3276 maxDisplacement = aDispl;
3278 // no node movement => exit
3279 //if ( maxDisplacement < 1.e-16 ) {
3280 if ( maxDisplacement < disttol ) {
3281 MESSAGE("-- no node movement --");
3285 // check elements quality
3287 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3288 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3289 const SMDS_MeshElement* elem = (*elemIt);
3290 if ( !elem || elem->GetType() != SMDSAbs_Face )
3292 SMESH::Controls::TSequenceOfXYZ aPoints;
3293 if ( aQualityFunc.GetPoints( elem, aPoints )) {
3294 double aValue = aQualityFunc.GetValue( aPoints );
3295 if ( aValue > maxRatio )
3299 if ( maxRatio <= theTgtAspectRatio ) {
3300 MESSAGE("-- quality achived --");
3303 if (it+1 == theNbIterations) {
3304 MESSAGE("-- Iteration limit exceeded --");
3306 } // smoothing iterations
3308 MESSAGE(" Face id: " << *fId <<
3309 " Nb iterstions: " << it <<
3310 " Displacement: " << maxDisplacement <<
3311 " Aspect Ratio " << maxRatio);
3313 // ---------------------------------------
3314 // new nodes positions are computed,
3315 // record movement in DS and set new UV
3316 // ---------------------------------------
3317 nodeToMove = setMovableNodes.begin();
3318 for ( ; nodeToMove != setMovableNodes.end(); nodeToMove++ ) {
3319 SMDS_MeshNode* node = const_cast< SMDS_MeshNode* > (*nodeToMove);
3320 aMesh->MoveNode( node, node->X(), node->Y(), node->Z() );
3321 map< const SMDS_MeshNode*, gp_XY* >::iterator node_uv = uvMap.find( node );
3322 if ( node_uv != uvMap.end() ) {
3323 gp_XY* uv = node_uv->second;
3325 ( SMDS_PositionPtr( new SMDS_FacePosition( uv->X(), uv->Y() )));
3329 // move medium nodes of quadratic elements
3332 SMESH_MesherHelper helper( *GetMesh() );
3333 if ( !face.IsNull() )
3334 helper.SetSubShape( face );
3335 list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
3336 for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
3337 const SMDS_VtkFace* QF =
3338 dynamic_cast<const SMDS_VtkFace*> (*elemIt);
3339 if(QF && QF->IsQuadratic()) {
3340 vector<const SMDS_MeshNode*> Ns;
3341 Ns.reserve(QF->NbNodes()+1);
3342 SMDS_ElemIteratorPtr anIter = QF->interlacedNodesElemIterator();
3343 while ( anIter->more() )
3344 Ns.push_back( cast2Node(anIter->next()) );
3345 Ns.push_back( Ns[0] );
3347 for(int i=0; i<QF->NbNodes(); i=i+2) {
3348 if ( !surface.IsNull() ) {
3349 gp_XY uv1 = helper.GetNodeUV( face, Ns[i], Ns[i+2] );
3350 gp_XY uv2 = helper.GetNodeUV( face, Ns[i+2], Ns[i] );
3351 gp_XY uv = ( uv1 + uv2 ) / 2.;
3352 gp_Pnt xyz = surface->Value( uv.X(), uv.Y() );
3353 x = xyz.X(); y = xyz.Y(); z = xyz.Z();
3356 x = (Ns[i]->X() + Ns[i+2]->X())/2;
3357 y = (Ns[i]->Y() + Ns[i+2]->Y())/2;
3358 z = (Ns[i]->Z() + Ns[i+2]->Z())/2;
3360 if( fabs( Ns[i+1]->X() - x ) > disttol ||
3361 fabs( Ns[i+1]->Y() - y ) > disttol ||
3362 fabs( Ns[i+1]->Z() - z ) > disttol ) {
3363 // we have to move i+1 node
3364 aMesh->MoveNode( Ns[i+1], x, y, z );
3371 } // loop on face ids
3375 //=======================================================================
3376 //function : isReverse
3377 //purpose : Return true if normal of prevNodes is not co-directied with
3378 // gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
3379 // iNotSame is where prevNodes and nextNodes are different
3380 //=======================================================================
3382 static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
3383 vector<const SMDS_MeshNode*> nextNodes,
3387 int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
3388 int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
3390 const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
3391 const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
3392 const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
3393 const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
3395 gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
3396 gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
3397 gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
3398 gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
3400 gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
3402 return (vA ^ vB) * vN < 0.0;
3405 //=======================================================================
3407 * \brief Create elements by sweeping an element
3408 * \param elem - element to sweep
3409 * \param newNodesItVec - nodes generated from each node of the element
3410 * \param newElems - generated elements
3411 * \param nbSteps - number of sweeping steps
3412 * \param srcElements - to append elem for each generated element
3414 //=======================================================================
3416 void SMESH_MeshEditor::sweepElement(const SMDS_MeshElement* elem,
3417 const vector<TNodeOfNodeListMapItr> & newNodesItVec,
3418 list<const SMDS_MeshElement*>& newElems,
3420 SMESH_SequenceOfElemPtr& srcElements)
3422 //MESSAGE("sweepElement " << nbSteps);
3423 SMESHDS_Mesh* aMesh = GetMeshDS();
3425 // Loop on elem nodes:
3426 // find new nodes and detect same nodes indices
3427 int nbNodes = elem->NbNodes();
3428 vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
3429 vector<const SMDS_MeshNode*> prevNod( nbNodes );
3430 vector<const SMDS_MeshNode*> nextNod( nbNodes );
3431 vector<const SMDS_MeshNode*> midlNod( nbNodes );
3433 int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
3434 vector<int> sames(nbNodes);
3435 vector<bool> issimple(nbNodes);
3437 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3438 TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
3439 const SMDS_MeshNode* node = nnIt->first;
3440 const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
3441 if ( listNewNodes.empty() ) {
3445 issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
3447 itNN[ iNode ] = listNewNodes.begin();
3448 prevNod[ iNode ] = node;
3449 nextNod[ iNode ] = listNewNodes.front();
3450 if( !elem->IsQuadratic() || !issimple[iNode] ) {
3451 if ( prevNod[ iNode ] != nextNod [ iNode ])
3452 iNotSameNode = iNode;
3456 sames[nbSame++] = iNode;
3461 //cerr<<" nbSame = "<<nbSame<<endl;
3462 if ( nbSame == nbNodes || nbSame > 2) {
3463 MESSAGE( " Too many same nodes of element " << elem->GetID() );
3464 //INFOS( " Too many same nodes of element " << elem->GetID() );
3468 // if( elem->IsQuadratic() && nbSame>0 ) {
3469 // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
3473 int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
3474 int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
3476 iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
3477 iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
3478 iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
3482 //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
3483 // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
3484 // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
3485 // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
3487 // check element orientation
3489 if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
3490 //MESSAGE("Reversed elem " << elem );
3494 std::swap( iBeforeSame, iAfterSame );
3497 // make new elements
3498 const SMDS_MeshElement* lastElem = elem;
3499 for (int iStep = 0; iStep < nbSteps; iStep++ ) {
3501 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3502 if(issimple[iNode]) {
3503 nextNod[ iNode ] = *itNN[ iNode ];
3507 if( elem->GetType()==SMDSAbs_Node ) {
3508 // we have to use two nodes
3509 midlNod[ iNode ] = *itNN[ iNode ];
3511 nextNod[ iNode ] = *itNN[ iNode ];
3514 else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
3515 // we have to use each second node
3517 nextNod[ iNode ] = *itNN[ iNode ];
3521 // we have to use two nodes
3522 midlNod[ iNode ] = *itNN[ iNode ];
3524 nextNod[ iNode ] = *itNN[ iNode ];
3529 SMDS_MeshElement* aNewElem = 0;
3530 if(!elem->IsPoly()) {
3531 switch ( nbNodes ) {
3535 if ( nbSame == 0 ) {
3537 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
3539 aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
3545 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3546 nextNod[ 1 ], nextNod[ 0 ] );
3548 aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
3549 nextNod[ iNotSameNode ] );
3553 case 3: { // TRIANGLE or quadratic edge
3554 if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
3556 if ( nbSame == 0 ) // --- pentahedron
3557 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3558 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
3560 else if ( nbSame == 1 ) // --- pyramid
3561 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3562 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3563 nextNod[ iSameNode ]);
3565 else // 2 same nodes: --- tetrahedron
3566 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
3567 nextNod[ iNotSameNode ]);
3569 else { // quadratic edge
3570 if(nbSame==0) { // quadratic quadrangle
3571 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
3572 midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
3574 else if(nbSame==1) { // quadratic triangle
3576 return; // medium node on axis
3578 else if(sames[0]==0) {
3579 aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
3580 nextNod[2], midlNod[1], prevNod[2]);
3582 else { // sames[0]==1
3583 aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
3584 midlNod[0], nextNod[2], prevNod[2]);
3593 case 4: { // QUADRANGLE
3595 if ( nbSame == 0 ) // --- hexahedron
3596 aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
3597 nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
3599 else if ( nbSame == 1 ) { // --- pyramid + pentahedron
3600 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
3601 nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
3602 nextNod[ iSameNode ]);
3603 newElems.push_back( aNewElem );
3604 aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
3605 prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
3606 nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
3608 else if ( nbSame == 2 ) { // pentahedron
3609 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
3610 // iBeforeSame is same too
3611 aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
3612 nextNod[ iOpposSame ], prevNod[ iSameNode ],
3613 prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
3615 // iAfterSame is same too
3616 aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
3617 nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
3618 prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
3622 case 6: { // quadratic triangle
3623 // create pentahedron with 15 nodes
3625 if(i0>0) { // reversed case
3626 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
3627 nextNod[0], nextNod[2], nextNod[1],
3628 prevNod[5], prevNod[4], prevNod[3],
3629 nextNod[5], nextNod[4], nextNod[3],
3630 midlNod[0], midlNod[2], midlNod[1]);
3632 else { // not reversed case
3633 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
3634 nextNod[0], nextNod[1], nextNod[2],
3635 prevNod[3], prevNod[4], prevNod[5],
3636 nextNod[3], nextNod[4], nextNod[5],
3637 midlNod[0], midlNod[1], midlNod[2]);
3640 else if(nbSame==1) {
3641 // 2d order pyramid of 13 nodes
3642 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
3643 // int n12,int n23,int n34,int n41,
3644 // int n15,int n25,int n35,int n45, int ID);
3646 int n1,n4,n41,n15,n45;
3647 if(i0>0) { // reversed case
3648 n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3649 n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3655 n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
3656 n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
3661 aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
3662 nextNod[n4], prevNod[n4], prevNod[n5],
3663 midlNod[n1], nextNod[n41],
3664 midlNod[n4], prevNod[n41],
3665 prevNod[n15], nextNod[n15],
3666 nextNod[n45], prevNod[n45]);
3668 else if(nbSame==2) {
3669 // 2d order tetrahedron of 10 nodes
3670 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
3671 // int n12,int n23,int n31,
3672 // int n14,int n24,int n34, int ID);
3673 int n1 = iNotSameNode;
3674 int n2,n3,n12,n23,n31;
3675 if(i0>0) { // reversed case
3676 n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3677 n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3683 n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
3684 n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
3689 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
3690 prevNod[n12], prevNod[n23], prevNod[n31],
3691 midlNod[n1], nextNod[n12], nextNod[n31]);
3695 case 8: { // quadratic quadrangle
3697 // create hexahedron with 20 nodes
3698 if(i0>0) { // reversed case
3699 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
3700 nextNod[0], nextNod[3], nextNod[2], nextNod[1],
3701 prevNod[7], prevNod[6], prevNod[5], prevNod[4],
3702 nextNod[7], nextNod[6], nextNod[5], nextNod[4],
3703 midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
3705 else { // not reversed case
3706 aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
3707 nextNod[0], nextNod[1], nextNod[2], nextNod[3],
3708 prevNod[4], prevNod[5], prevNod[6], prevNod[7],
3709 nextNod[4], nextNod[5], nextNod[6], nextNod[7],
3710 midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
3713 else if(nbSame==1) {
3714 // --- pyramid + pentahedron - can not be created since it is needed
3715 // additional middle node ot the center of face
3716 INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
3719 else if(nbSame==2) {
3720 // 2d order Pentahedron with 15 nodes
3721 //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
3722 // int n12,int n23,int n31,int n45,int n56,int n64,
3723 // int n14,int n25,int n36, int ID);
3725 if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
3726 // iBeforeSame is same too
3733 // iAfterSame is same too
3739 int n12,n45,n14,n25;
3740 if(i0>0) { //reversed case
3752 aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
3753 prevNod[n4], prevNod[n5], nextNod[n5],
3754 prevNod[n12], midlNod[n2], nextNod[n12],
3755 prevNod[n45], midlNod[n5], nextNod[n45],
3756 prevNod[n14], prevNod[n25], nextNod[n25]);
3761 // realized for extrusion only
3762 //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3763 //vector<int> quantities (nbNodes + 2);
3765 //quantities[0] = nbNodes; // bottom of prism
3766 //for (int inode = 0; inode < nbNodes; inode++) {
3767 // polyedre_nodes[inode] = prevNod[inode];
3770 //quantities[1] = nbNodes; // top of prism
3771 //for (int inode = 0; inode < nbNodes; inode++) {
3772 // polyedre_nodes[nbNodes + inode] = nextNod[inode];
3775 //for (int iface = 0; iface < nbNodes; iface++) {
3776 // quantities[iface + 2] = 4;
3777 // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3778 // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3779 // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3780 // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3781 // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3783 //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3790 // realized for extrusion only
3791 vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
3792 vector<int> quantities (nbNodes + 2);
3794 quantities[0] = nbNodes; // bottom of prism
3795 for (int inode = 0; inode < nbNodes; inode++) {
3796 polyedre_nodes[inode] = prevNod[inode];
3799 quantities[1] = nbNodes; // top of prism
3800 for (int inode = 0; inode < nbNodes; inode++) {
3801 polyedre_nodes[nbNodes + inode] = nextNod[inode];
3804 for (int iface = 0; iface < nbNodes; iface++) {
3805 quantities[iface + 2] = 4;
3806 int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
3807 polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
3808 polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
3809 polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
3810 polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
3812 aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
3816 newElems.push_back( aNewElem );
3817 myLastCreatedElems.Append(aNewElem);
3818 srcElements.Append( elem );
3819 lastElem = aNewElem;
3822 // set new prev nodes
3823 for ( iNode = 0; iNode < nbNodes; iNode++ )
3824 prevNod[ iNode ] = nextNod[ iNode ];
3829 //=======================================================================
3831 * \brief Create 1D and 2D elements around swept elements
3832 * \param mapNewNodes - source nodes and ones generated from them
3833 * \param newElemsMap - source elements and ones generated from them
3834 * \param elemNewNodesMap - nodes generated from each node of each element
3835 * \param elemSet - all swept elements
3836 * \param nbSteps - number of sweeping steps
3837 * \param srcElements - to append elem for each generated element
3839 //=======================================================================
3841 void SMESH_MeshEditor::makeWalls (TNodeOfNodeListMap & mapNewNodes,
3842 TElemOfElemListMap & newElemsMap,
3843 TElemOfVecOfNnlmiMap & elemNewNodesMap,
3844 TIDSortedElemSet& elemSet,
3846 SMESH_SequenceOfElemPtr& srcElements)
3848 MESSAGE("makeWalls");
3849 ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
3850 SMESHDS_Mesh* aMesh = GetMeshDS();
3852 // Find nodes belonging to only one initial element - sweep them to get edges.
3854 TNodeOfNodeListMapItr nList = mapNewNodes.begin();
3855 for ( ; nList != mapNewNodes.end(); nList++ ) {
3856 const SMDS_MeshNode* node =
3857 static_cast<const SMDS_MeshNode*>( nList->first );
3858 SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
3859 int nbInitElems = 0;
3860 const SMDS_MeshElement* el = 0;
3861 SMDSAbs_ElementType highType = SMDSAbs_Edge; // count most complex elements only
3862 while ( eIt->more() && nbInitElems < 2 ) {
3864 SMDSAbs_ElementType type = el->GetType();
3865 if ( type == SMDSAbs_Volume || type < highType ) continue;
3866 if ( type > highType ) {
3870 if ( elemSet.find(el) != elemSet.end() )
3873 if ( nbInitElems < 2 ) {
3874 bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
3875 if(!NotCreateEdge) {
3876 vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
3877 list<const SMDS_MeshElement*> newEdges;
3878 sweepElement( node, newNodesItVec, newEdges, nbSteps, srcElements );
3883 // Make a ceiling for each element ie an equal element of last new nodes.
3884 // Find free links of faces - make edges and sweep them into faces.
3886 TElemOfElemListMap::iterator itElem = newElemsMap.begin();
3887 TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
3888 for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
3889 const SMDS_MeshElement* elem = itElem->first;
3890 vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
3892 if(itElem->second.size()==0) continue;
3894 if ( elem->GetType() == SMDSAbs_Edge ) {
3895 // create a ceiling edge
3896 if (!elem->IsQuadratic()) {
3897 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3898 vecNewNodes[ 1 ]->second.back())) {
3899 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3900 vecNewNodes[ 1 ]->second.back()));
3901 srcElements.Append( myLastCreatedElems.Last() );
3905 if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
3906 vecNewNodes[ 1 ]->second.back(),
3907 vecNewNodes[ 2 ]->second.back())) {
3908 myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
3909 vecNewNodes[ 1 ]->second.back(),
3910 vecNewNodes[ 2 ]->second.back()));
3911 srcElements.Append( myLastCreatedElems.Last() );
3915 if ( elem->GetType() != SMDSAbs_Face )
3918 bool hasFreeLinks = false;
3920 TIDSortedElemSet avoidSet;
3921 avoidSet.insert( elem );
3923 set<const SMDS_MeshNode*> aFaceLastNodes;
3924 int iNode, nbNodes = vecNewNodes.size();
3925 if(!elem->IsQuadratic()) {
3926 // loop on the face nodes
3927 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3928 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3929 // look for free links of the face
3930 int iNext = ( iNode + 1 == nbNodes ) ? 0 : iNode + 1;
3931 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3932 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3933 // check if a link is free
3934 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3935 hasFreeLinks = true;
3936 // make an edge and a ceiling for a new edge
3937 if ( !aMesh->FindEdge( n1, n2 )) {
3938 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // free link edge
3939 srcElements.Append( myLastCreatedElems.Last() );
3941 n1 = vecNewNodes[ iNode ]->second.back();
3942 n2 = vecNewNodes[ iNext ]->second.back();
3943 if ( !aMesh->FindEdge( n1, n2 )) {
3944 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2 )); // ceiling edge
3945 srcElements.Append( myLastCreatedElems.Last() );
3950 else { // elem is quadratic face
3951 int nbn = nbNodes/2;
3952 for ( iNode = 0; iNode < nbn; iNode++ ) {
3953 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3954 int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
3955 const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
3956 const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
3957 // check if a link is free
3958 if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
3959 hasFreeLinks = true;
3960 // make an edge and a ceiling for a new edge
3962 const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
3963 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3964 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
3965 srcElements.Append( myLastCreatedElems.Last() );
3967 n1 = vecNewNodes[ iNode ]->second.back();
3968 n2 = vecNewNodes[ iNext ]->second.back();
3969 n3 = vecNewNodes[ iNode+nbn ]->second.back();
3970 if ( !aMesh->FindEdge( n1, n2, n3 )) {
3971 myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // ceiling edge
3972 srcElements.Append( myLastCreatedElems.Last() );
3976 for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
3977 aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
3981 // sweep free links into faces
3983 if ( hasFreeLinks ) {
3984 list<const SMDS_MeshElement*> & newVolumes = itElem->second;
3985 int iVol, volNb, nbVolumesByStep = newVolumes.size() / nbSteps;
3987 set<const SMDS_MeshNode*> initNodeSet, topNodeSet, faceNodeSet;
3988 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
3989 initNodeSet.insert( vecNewNodes[ iNode ]->first );
3990 topNodeSet .insert( vecNewNodes[ iNode ]->second.back() );
3992 for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
3993 list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
3995 while ( iVol++ < volNb ) v++;
3996 // find indices of free faces of a volume and their source edges
3997 list< int > freeInd;
3998 list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
3999 SMDS_VolumeTool vTool( *v );
4000 int iF, nbF = vTool.NbFaces();
4001 for ( iF = 0; iF < nbF; iF ++ ) {
4002 if (vTool.IsFreeFace( iF ) &&
4003 vTool.GetFaceNodes( iF, faceNodeSet ) &&
4004 initNodeSet != faceNodeSet) // except an initial face
4006 if ( nbSteps == 1 && faceNodeSet == topNodeSet )
4008 freeInd.push_back( iF );
4009 // find source edge of a free face iF
4010 vector<const SMDS_MeshNode*> commonNodes; // shared by the initial and free faces
4011 commonNodes.resize( initNodeSet.size(), NULL ); // avoid spoiling memory
4012 std::set_intersection( faceNodeSet.begin(), faceNodeSet.end(),
4013 initNodeSet.begin(), initNodeSet.end(),
4014 commonNodes.begin());
4015 if ( (*v)->IsQuadratic() )
4016 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1],commonNodes[2]));
4018 srcEdges.push_back(aMesh->FindEdge (commonNodes[0],commonNodes[1]));
4020 if ( !srcEdges.back() )
4022 cout << "SMESH_MeshEditor::makeWalls(), no source edge found for a free face #"
4023 << iF << " of volume #" << vTool.ID() << endl;
4028 if ( freeInd.empty() )
4031 // create faces for all steps;
4032 // if such a face has been already created by sweep of edge,
4033 // assure that its orientation is OK
4034 for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
4036 vTool.SetExternalNormal();
4037 list< int >::iterator ind = freeInd.begin();
4038 list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
4039 for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
4041 const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
4042 int nbn = vTool.NbFaceNodes( *ind );
4044 case 3: { ///// triangle
4045 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
4047 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4048 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4050 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4051 aMesh->RemoveElement(f);
4055 case 4: { ///// quadrangle
4056 const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
4058 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4059 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4061 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4062 aMesh->RemoveElement(f);
4067 if( (*v)->IsQuadratic() ) {
4068 if(nbn==6) { /////// quadratic triangle
4069 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
4070 nodes[1], nodes[3], nodes[5] );
4072 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4073 nodes[1], nodes[3], nodes[5]));
4075 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4076 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
4077 tmpnodes[0] = nodes[0];
4078 tmpnodes[1] = nodes[2];
4079 tmpnodes[2] = nodes[4];
4080 tmpnodes[3] = nodes[1];
4081 tmpnodes[4] = nodes[3];
4082 tmpnodes[5] = nodes[5];
4083 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4084 nodes[1], nodes[3], nodes[5]));
4085 aMesh->RemoveElement(f);
4088 else { /////// quadratic quadrangle
4089 const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
4090 nodes[1], nodes[3], nodes[5], nodes[7] );
4092 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4093 nodes[1], nodes[3], nodes[5], nodes[7]));
4095 else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
4096 const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
4097 tmpnodes[0] = nodes[0];
4098 tmpnodes[1] = nodes[2];
4099 tmpnodes[2] = nodes[4];
4100 tmpnodes[3] = nodes[6];
4101 tmpnodes[4] = nodes[1];
4102 tmpnodes[5] = nodes[3];
4103 tmpnodes[6] = nodes[5];
4104 tmpnodes[7] = nodes[7];
4105 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4106 nodes[1], nodes[3], nodes[5], nodes[7]));
4107 aMesh->RemoveElement(f);
4111 else { //////// polygon
4112 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4113 const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
4115 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4116 else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
4118 // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
4119 MESSAGE("ChangeElementNodes");
4120 aMesh->ChangeElementNodes( f, nodes, nbn );
4124 while ( srcElements.Length() < myLastCreatedElems.Length() )
4125 srcElements.Append( *srcEdge );
4127 } // loop on free faces
4129 // go to the next volume
4131 while ( iVol++ < nbVolumesByStep ) v++;
4134 } // sweep free links into faces
4136 // Make a ceiling face with a normal external to a volume
4138 SMDS_VolumeTool lastVol( itElem->second.back() );
4140 int iF = lastVol.GetFaceIndex( aFaceLastNodes );
4142 lastVol.SetExternalNormal();
4143 const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
4144 int nbn = lastVol.NbFaceNodes( iF );
4147 if (!hasFreeLinks ||
4148 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
4149 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
4152 if (!hasFreeLinks ||
4153 !aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
4154 myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
4157 if(itElem->second.back()->IsQuadratic()) {
4159 if (!hasFreeLinks ||
4160 !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
4161 nodes[1], nodes[3], nodes[5]) ) {
4162 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
4163 nodes[1], nodes[3], nodes[5]));
4167 if (!hasFreeLinks ||
4168 !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
4169 nodes[1], nodes[3], nodes[5], nodes[7]) )
4170 myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
4171 nodes[1], nodes[3], nodes[5], nodes[7]));
4175 vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
4176 if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
4177 myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
4181 while ( srcElements.Length() < myLastCreatedElems.Length() )
4182 srcElements.Append( myLastCreatedElems.Last() );
4184 } // loop on swept elements
4187 //=======================================================================
4188 //function : RotationSweep
4190 //=======================================================================
4192 SMESH_MeshEditor::PGroupIDs
4193 SMESH_MeshEditor::RotationSweep(TIDSortedElemSet & theElems,
4194 const gp_Ax1& theAxis,
4195 const double theAngle,
4196 const int theNbSteps,
4197 const double theTol,
4198 const bool theMakeGroups,
4199 const bool theMakeWalls)
4201 myLastCreatedElems.Clear();
4202 myLastCreatedNodes.Clear();
4204 // source elements for each generated one
4205 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4207 MESSAGE( "RotationSweep()");
4209 aTrsf.SetRotation( theAxis, theAngle );
4211 aTrsf2.SetRotation( theAxis, theAngle/2. );
4213 gp_Lin aLine( theAxis );
4214 double aSqTol = theTol * theTol;
4216 SMESHDS_Mesh* aMesh = GetMeshDS();
4218 TNodeOfNodeListMap mapNewNodes;
4219 TElemOfVecOfNnlmiMap mapElemNewNodes;
4220 TElemOfElemListMap newElemsMap;
4223 TIDSortedElemSet::iterator itElem;
4224 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4225 const SMDS_MeshElement* elem = *itElem;
4226 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4228 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4229 newNodesItVec.reserve( elem->NbNodes() );
4231 // loop on elem nodes
4232 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4233 while ( itN->more() ) {
4234 // check if a node has been already sweeped
4235 const SMDS_MeshNode* node = cast2Node( itN->next() );
4237 gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4239 aXYZ.Coord( coord[0], coord[1], coord[2] );
4240 bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4242 TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
4243 if ( nIt == mapNewNodes.end() ) {
4244 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4245 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4248 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4250 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4251 //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
4252 const SMDS_MeshNode * newNode = node;
4253 for ( int i = 0; i < theNbSteps; i++ ) {
4255 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4257 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4258 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4259 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4260 myLastCreatedNodes.Append(newNode);
4261 srcNodes.Append( node );
4262 listNewNodes.push_back( newNode );
4263 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4264 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4267 aTrsf.Transforms( coord[0], coord[1], coord[2] );
4269 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4270 myLastCreatedNodes.Append(newNode);
4271 srcNodes.Append( node );
4272 listNewNodes.push_back( newNode );
4275 listNewNodes.push_back( newNode );
4276 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4277 listNewNodes.push_back( newNode );
4284 // if current elem is quadratic and current node is not medium
4285 // we have to check - may be it is needed to insert additional nodes
4286 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4287 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4288 if(listNewNodes.size()==theNbSteps) {
4289 listNewNodes.clear();
4291 //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
4293 //aXYZ.Coord( coord[0], coord[1], coord[2] );
4294 const SMDS_MeshNode * newNode = node;
4296 for(int i = 0; i<theNbSteps; i++) {
4297 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4298 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4299 cout<<" 3 AddNode: "<<newNode;
4300 myLastCreatedNodes.Append(newNode);
4301 listNewNodes.push_back( newNode );
4302 srcNodes.Append( node );
4303 aTrsf2.Transforms( coord[0], coord[1], coord[2] );
4304 newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4305 cout<<" 4 AddNode: "<<newNode;
4306 myLastCreatedNodes.Append(newNode);
4307 srcNodes.Append( node );
4308 listNewNodes.push_back( newNode );
4312 listNewNodes.push_back( newNode );
4318 newNodesItVec.push_back( nIt );
4320 // make new elements
4321 sweepElement( elem, newNodesItVec, newElemsMap[elem], theNbSteps, srcElems );
4325 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, theNbSteps, srcElems );
4327 PGroupIDs newGroupIDs;
4328 if ( theMakeGroups )
4329 newGroupIDs = generateGroups( srcNodes, srcElems, "rotated");
4335 //=======================================================================
4336 //function : CreateNode
4338 //=======================================================================
4339 const SMDS_MeshNode* SMESH_MeshEditor::CreateNode(const double x,
4342 const double tolnode,
4343 SMESH_SequenceOfNode& aNodes)
4345 myLastCreatedElems.Clear();
4346 myLastCreatedNodes.Clear();
4349 SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
4351 // try to search in sequence of existing nodes
4352 // if aNodes.Length()>0 we 'nave to use given sequence
4353 // else - use all nodes of mesh
4354 if(aNodes.Length()>0) {
4356 for(i=1; i<=aNodes.Length(); i++) {
4357 gp_Pnt P2(aNodes.Value(i)->X(),aNodes.Value(i)->Y(),aNodes.Value(i)->Z());
4358 if(P1.Distance(P2)<tolnode)
4359 return aNodes.Value(i);
4363 SMDS_NodeIteratorPtr itn = aMesh->nodesIterator();
4364 while(itn->more()) {
4365 const SMDS_MeshNode* aN = static_cast<const SMDS_MeshNode*> (itn->next());
4366 gp_Pnt P2(aN->X(),aN->Y(),aN->Z());
4367 if(P1.Distance(P2)<tolnode)
4372 // create new node and return it
4373 const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
4374 myLastCreatedNodes.Append(NewNode);
4379 //=======================================================================
4380 //function : ExtrusionSweep
4382 //=======================================================================
4384 SMESH_MeshEditor::PGroupIDs
4385 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4386 const gp_Vec& theStep,
4387 const int theNbSteps,
4388 TElemOfElemListMap& newElemsMap,
4389 const bool theMakeGroups,
4391 const double theTolerance)
4393 ExtrusParam aParams;
4394 aParams.myDir = gp_Dir(theStep);
4395 aParams.myNodes.Clear();
4396 aParams.mySteps = new TColStd_HSequenceOfReal;
4398 for(i=1; i<=theNbSteps; i++)
4399 aParams.mySteps->Append(theStep.Magnitude());
4402 ExtrusionSweep(theElems,aParams,newElemsMap,theMakeGroups,theFlags,theTolerance);
4406 //=======================================================================
4407 //function : ExtrusionSweep
4409 //=======================================================================
4411 SMESH_MeshEditor::PGroupIDs
4412 SMESH_MeshEditor::ExtrusionSweep (TIDSortedElemSet & theElems,
4413 ExtrusParam& theParams,
4414 TElemOfElemListMap& newElemsMap,
4415 const bool theMakeGroups,
4417 const double theTolerance)
4419 MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
4420 myLastCreatedElems.Clear();
4421 myLastCreatedNodes.Clear();
4423 // source elements for each generated one
4424 SMESH_SequenceOfElemPtr srcElems, srcNodes;
4426 SMESHDS_Mesh* aMesh = GetMeshDS();
4428 int nbsteps = theParams.mySteps->Length();
4430 TNodeOfNodeListMap mapNewNodes;
4431 //TNodeOfNodeVecMap mapNewNodes;
4432 TElemOfVecOfNnlmiMap mapElemNewNodes;
4433 //TElemOfVecOfMapNodesMap mapElemNewNodes;
4436 TIDSortedElemSet::iterator itElem;
4437 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
4438 // check element type
4439 const SMDS_MeshElement* elem = *itElem;
4440 if ( !elem || elem->GetType() == SMDSAbs_Volume )
4443 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4444 //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
4445 newNodesItVec.reserve( elem->NbNodes() );
4447 // loop on elem nodes
4448 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
4449 while ( itN->more() )
4451 // check if a node has been already sweeped
4452 const SMDS_MeshNode* node = cast2Node( itN->next() );
4453 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
4454 //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
4455 if ( nIt == mapNewNodes.end() ) {
4456 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
4457 //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
4458 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
4459 //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
4460 //vecNewNodes.reserve(nbsteps);
4463 double coord[] = { node->X(), node->Y(), node->Z() };
4464 //int nbsteps = theParams.mySteps->Length();
4465 for ( int i = 0; i < nbsteps; i++ ) {
4466 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4467 // create additional node
4468 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
4469 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
4470 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
4471 if( theFlags & EXTRUSION_FLAG_SEW ) {
4472 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4473 theTolerance, theParams.myNodes);
4474 listNewNodes.push_back( newNode );
4477 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4478 myLastCreatedNodes.Append(newNode);
4479 srcNodes.Append( node );
4480 listNewNodes.push_back( newNode );
4483 //aTrsf.Transforms( coord[0], coord[1], coord[2] );
4484 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4485 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4486 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4487 if( theFlags & EXTRUSION_FLAG_SEW ) {
4488 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4489 theTolerance, theParams.myNodes);
4490 listNewNodes.push_back( newNode );
4491 //vecNewNodes[i]=newNode;
4494 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4495 myLastCreatedNodes.Append(newNode);
4496 srcNodes.Append( node );
4497 listNewNodes.push_back( newNode );
4498 //vecNewNodes[i]=newNode;
4503 // if current elem is quadratic and current node is not medium
4504 // we have to check - may be it is needed to insert additional nodes
4505 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
4506 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
4507 if(listNewNodes.size()==nbsteps) {
4508 listNewNodes.clear();
4509 double coord[] = { node->X(), node->Y(), node->Z() };
4510 for ( int i = 0; i < nbsteps; i++ ) {
4511 double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4512 double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4513 double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4514 if( theFlags & EXTRUSION_FLAG_SEW ) {
4515 const SMDS_MeshNode * newNode = CreateNode(x, y, z,
4516 theTolerance, theParams.myNodes);
4517 listNewNodes.push_back( newNode );
4520 const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
4521 myLastCreatedNodes.Append(newNode);
4522 srcNodes.Append( node );
4523 listNewNodes.push_back( newNode );
4525 coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
4526 coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
4527 coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
4528 if( theFlags & EXTRUSION_FLAG_SEW ) {
4529 const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
4530 theTolerance, theParams.myNodes);
4531 listNewNodes.push_back( newNode );
4534 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
4535 myLastCreatedNodes.Append(newNode);
4536 srcNodes.Append( node );
4537 listNewNodes.push_back( newNode );
4543 newNodesItVec.push_back( nIt );
4545 // make new elements
4546 sweepElement( elem, newNodesItVec, newElemsMap[elem], nbsteps, srcElems );
4549 if( theFlags & EXTRUSION_FLAG_BOUNDARY ) {
4550 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElems, nbsteps, srcElems );
4552 PGroupIDs newGroupIDs;
4553 if ( theMakeGroups )
4554 newGroupIDs = generateGroups( srcNodes, srcElems, "extruded");
4560 //=======================================================================
4561 //class : SMESH_MeshEditor_PathPoint
4562 //purpose : auxiliary class
4563 //=======================================================================
4564 class SMESH_MeshEditor_PathPoint {
4566 SMESH_MeshEditor_PathPoint() {
4567 myPnt.SetCoord(99., 99., 99.);
4568 myTgt.SetCoord(1.,0.,0.);
4572 void SetPnt(const gp_Pnt& aP3D){
4575 void SetTangent(const gp_Dir& aTgt){
4578 void SetAngle(const double& aBeta){
4581 void SetParameter(const double& aPrm){
4584 const gp_Pnt& Pnt()const{
4587 const gp_Dir& Tangent()const{
4590 double Angle()const{
4593 double Parameter()const{
4605 //=======================================================================
4606 //function : ExtrusionAlongTrack
4608 //=======================================================================
4609 SMESH_MeshEditor::Extrusion_Error
4610 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4611 SMESH_subMesh* theTrack,
4612 const SMDS_MeshNode* theN1,
4613 const bool theHasAngles,
4614 list<double>& theAngles,
4615 const bool theLinearVariation,
4616 const bool theHasRefPoint,
4617 const gp_Pnt& theRefPoint,
4618 const bool theMakeGroups)
4620 MESSAGE("ExtrusionAlongTrack");
4621 myLastCreatedElems.Clear();
4622 myLastCreatedNodes.Clear();
4625 std::list<double> aPrms;
4626 TIDSortedElemSet::iterator itElem;
4629 TopoDS_Edge aTrackEdge;
4630 TopoDS_Vertex aV1, aV2;
4632 SMDS_ElemIteratorPtr aItE;
4633 SMDS_NodeIteratorPtr aItN;
4634 SMDSAbs_ElementType aTypeE;
4636 TNodeOfNodeListMap mapNewNodes;
4639 aNbE = theElements.size();
4642 return EXTR_NO_ELEMENTS;
4644 // 1.1 Track Pattern
4647 SMESHDS_SubMesh* pSubMeshDS = theTrack->GetSubMeshDS();
4649 aItE = pSubMeshDS->GetElements();
4650 while ( aItE->more() ) {
4651 const SMDS_MeshElement* pE = aItE->next();
4652 aTypeE = pE->GetType();
4653 // Pattern must contain links only
4654 if ( aTypeE != SMDSAbs_Edge )
4655 return EXTR_PATH_NOT_EDGE;
4658 list<SMESH_MeshEditor_PathPoint> fullList;
4660 const TopoDS_Shape& aS = theTrack->GetSubShape();
4661 // Sub shape for the Pattern must be an Edge or Wire
4662 if( aS.ShapeType() == TopAbs_EDGE ) {
4663 aTrackEdge = TopoDS::Edge( aS );
4664 // the Edge must not be degenerated
4665 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4666 return EXTR_BAD_PATH_SHAPE;
4667 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4668 aItN = theTrack->GetFather()->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4669 const SMDS_MeshNode* aN1 = aItN->next();
4670 aItN = theTrack->GetFather()->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4671 const SMDS_MeshNode* aN2 = aItN->next();
4672 // starting node must be aN1 or aN2
4673 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4674 return EXTR_BAD_STARTING_NODE;
4675 aItN = pSubMeshDS->GetNodes();
4676 while ( aItN->more() ) {
4677 const SMDS_MeshNode* pNode = aItN->next();
4678 const SMDS_EdgePosition* pEPos =
4679 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4680 double aT = pEPos->GetUParameter();
4681 aPrms.push_back( aT );
4683 //Extrusion_Error err =
4684 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4686 else if( aS.ShapeType() == TopAbs_WIRE ) {
4687 list< SMESH_subMesh* > LSM;
4688 TopTools_SequenceOfShape Edges;
4689 SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
4690 while(itSM->more()) {
4691 SMESH_subMesh* SM = itSM->next();
4693 const TopoDS_Shape& aS = SM->GetSubShape();
4696 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4697 int startNid = theN1->GetID();
4698 TColStd_MapOfInteger UsedNums;
4699 int NbEdges = Edges.Length();
4701 for(; i<=NbEdges; i++) {
4703 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4704 for(; itLSM!=LSM.end(); itLSM++) {
4706 if(UsedNums.Contains(k)) continue;
4707 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4708 SMESH_subMesh* locTrack = *itLSM;
4709 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4710 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4711 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4712 const SMDS_MeshNode* aN1 = aItN->next();
4713 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4714 const SMDS_MeshNode* aN2 = aItN->next();
4715 // starting node must be aN1 or aN2
4716 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4717 // 2. Collect parameters on the track edge
4719 aItN = locMeshDS->GetNodes();
4720 while ( aItN->more() ) {
4721 const SMDS_MeshNode* pNode = aItN->next();
4722 const SMDS_EdgePosition* pEPos =
4723 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4724 double aT = pEPos->GetUParameter();
4725 aPrms.push_back( aT );
4727 list<SMESH_MeshEditor_PathPoint> LPP;
4728 //Extrusion_Error err =
4729 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4730 LLPPs.push_back(LPP);
4732 // update startN for search following egde
4733 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4734 else startNid = aN1->GetID();
4738 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4739 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4740 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4741 for(; itPP!=firstList.end(); itPP++) {
4742 fullList.push_back( *itPP );
4744 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4745 fullList.pop_back();
4747 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4748 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4749 itPP = currList.begin();
4750 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4751 gp_Dir D1 = PP1.Tangent();
4752 gp_Dir D2 = PP2.Tangent();
4753 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4754 (D1.Z()+D2.Z())/2 ) );
4755 PP1.SetTangent(Dnew);
4756 fullList.push_back(PP1);
4758 for(; itPP!=firstList.end(); itPP++) {
4759 fullList.push_back( *itPP );
4761 PP1 = fullList.back();
4762 fullList.pop_back();
4764 // if wire not closed
4765 fullList.push_back(PP1);
4769 return EXTR_BAD_PATH_SHAPE;
4772 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4773 theHasRefPoint, theRefPoint, theMakeGroups);
4777 //=======================================================================
4778 //function : ExtrusionAlongTrack
4780 //=======================================================================
4781 SMESH_MeshEditor::Extrusion_Error
4782 SMESH_MeshEditor::ExtrusionAlongTrack (TIDSortedElemSet & theElements,
4783 SMESH_Mesh* theTrack,
4784 const SMDS_MeshNode* theN1,
4785 const bool theHasAngles,
4786 list<double>& theAngles,
4787 const bool theLinearVariation,
4788 const bool theHasRefPoint,
4789 const gp_Pnt& theRefPoint,
4790 const bool theMakeGroups)
4792 myLastCreatedElems.Clear();
4793 myLastCreatedNodes.Clear();
4796 std::list<double> aPrms;
4797 TIDSortedElemSet::iterator itElem;
4800 TopoDS_Edge aTrackEdge;
4801 TopoDS_Vertex aV1, aV2;
4803 SMDS_ElemIteratorPtr aItE;
4804 SMDS_NodeIteratorPtr aItN;
4805 SMDSAbs_ElementType aTypeE;
4807 TNodeOfNodeListMap mapNewNodes;
4810 aNbE = theElements.size();
4813 return EXTR_NO_ELEMENTS;
4815 // 1.1 Track Pattern
4818 SMESHDS_Mesh* pMeshDS = theTrack->GetMeshDS();
4820 aItE = pMeshDS->elementsIterator();
4821 while ( aItE->more() ) {
4822 const SMDS_MeshElement* pE = aItE->next();
4823 aTypeE = pE->GetType();
4824 // Pattern must contain links only
4825 if ( aTypeE != SMDSAbs_Edge )
4826 return EXTR_PATH_NOT_EDGE;
4829 list<SMESH_MeshEditor_PathPoint> fullList;
4831 const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
4832 // Sub shape for the Pattern must be an Edge or Wire
4833 if( aS.ShapeType() == TopAbs_EDGE ) {
4834 aTrackEdge = TopoDS::Edge( aS );
4835 // the Edge must not be degenerated
4836 if ( BRep_Tool::Degenerated( aTrackEdge ) )
4837 return EXTR_BAD_PATH_SHAPE;
4838 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4839 aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
4840 const SMDS_MeshNode* aN1 = aItN->next();
4841 aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
4842 const SMDS_MeshNode* aN2 = aItN->next();
4843 // starting node must be aN1 or aN2
4844 if ( !( aN1 == theN1 || aN2 == theN1 ) )
4845 return EXTR_BAD_STARTING_NODE;
4846 aItN = pMeshDS->nodesIterator();
4847 while ( aItN->more() ) {
4848 const SMDS_MeshNode* pNode = aItN->next();
4849 if( pNode==aN1 || pNode==aN2 ) continue;
4850 const SMDS_EdgePosition* pEPos =
4851 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4852 double aT = pEPos->GetUParameter();
4853 aPrms.push_back( aT );
4855 //Extrusion_Error err =
4856 MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
4858 else if( aS.ShapeType() == TopAbs_WIRE ) {
4859 list< SMESH_subMesh* > LSM;
4860 TopTools_SequenceOfShape Edges;
4861 TopExp_Explorer eExp(aS, TopAbs_EDGE);
4862 for(; eExp.More(); eExp.Next()) {
4863 TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
4864 if( BRep_Tool::Degenerated(E) ) continue;
4865 SMESH_subMesh* SM = theTrack->GetSubMesh(E);
4871 list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
4872 int startNid = theN1->GetID();
4873 TColStd_MapOfInteger UsedNums;
4874 int NbEdges = Edges.Length();
4876 for(; i<=NbEdges; i++) {
4878 list< SMESH_subMesh* >::iterator itLSM = LSM.begin();
4879 for(; itLSM!=LSM.end(); itLSM++) {
4881 if(UsedNums.Contains(k)) continue;
4882 aTrackEdge = TopoDS::Edge( Edges.Value(k) );
4883 SMESH_subMesh* locTrack = *itLSM;
4884 SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
4885 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4886 aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
4887 const SMDS_MeshNode* aN1 = aItN->next();
4888 aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
4889 const SMDS_MeshNode* aN2 = aItN->next();
4890 // starting node must be aN1 or aN2
4891 if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
4892 // 2. Collect parameters on the track edge
4894 aItN = locMeshDS->GetNodes();
4895 while ( aItN->more() ) {
4896 const SMDS_MeshNode* pNode = aItN->next();
4897 const SMDS_EdgePosition* pEPos =
4898 static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
4899 double aT = pEPos->GetUParameter();
4900 aPrms.push_back( aT );
4902 list<SMESH_MeshEditor_PathPoint> LPP;
4903 //Extrusion_Error err =
4904 MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
4905 LLPPs.push_back(LPP);
4907 // update startN for search following egde
4908 if( aN1->GetID() == startNid ) startNid = aN2->GetID();
4909 else startNid = aN1->GetID();
4913 list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
4914 list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
4915 list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
4916 for(; itPP!=firstList.end(); itPP++) {
4917 fullList.push_back( *itPP );
4919 SMESH_MeshEditor_PathPoint PP1 = fullList.back();
4920 fullList.pop_back();
4922 for(; itLLPP!=LLPPs.end(); itLLPP++) {
4923 list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
4924 itPP = currList.begin();
4925 SMESH_MeshEditor_PathPoint PP2 = currList.front();
4926 gp_Pnt P1 = PP1.Pnt();
4927 //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
4928 gp_Pnt P2 = PP2.Pnt();
4929 gp_Dir D1 = PP1.Tangent();
4930 gp_Dir D2 = PP2.Tangent();
4931 gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
4932 (D1.Z()+D2.Z())/2 ) );
4933 PP1.SetTangent(Dnew);
4934 fullList.push_back(PP1);
4936 for(; itPP!=currList.end(); itPP++) {
4937 fullList.push_back( *itPP );
4939 PP1 = fullList.back();
4940 fullList.pop_back();
4942 // if wire not closed
4943 fullList.push_back(PP1);
4947 return EXTR_BAD_PATH_SHAPE;
4950 return MakeExtrElements(theElements, fullList, theHasAngles, theAngles, theLinearVariation,
4951 theHasRefPoint, theRefPoint, theMakeGroups);
4955 //=======================================================================
4956 //function : MakeEdgePathPoints
4957 //purpose : auxilary for ExtrusionAlongTrack
4958 //=======================================================================
4959 SMESH_MeshEditor::Extrusion_Error
4960 SMESH_MeshEditor::MakeEdgePathPoints(std::list<double>& aPrms,
4961 const TopoDS_Edge& aTrackEdge,
4963 list<SMESH_MeshEditor_PathPoint>& LPP)
4965 Standard_Real aTx1, aTx2, aL2, aTolVec, aTolVec2;
4967 aTolVec2=aTolVec*aTolVec;
4969 TopoDS_Vertex aV1, aV2;
4970 TopExp::Vertices( aTrackEdge, aV1, aV2 );
4971 aT1=BRep_Tool::Parameter( aV1, aTrackEdge );
4972 aT2=BRep_Tool::Parameter( aV2, aTrackEdge );
4973 // 2. Collect parameters on the track edge
4974 aPrms.push_front( aT1 );
4975 aPrms.push_back( aT2 );
4978 if( FirstIsStart ) {
4989 SMESH_MeshEditor_PathPoint aPP;
4990 Handle(Geom_Curve) aC3D = BRep_Tool::Curve( aTrackEdge, aTx1, aTx2 );
4991 std::list<double>::iterator aItD = aPrms.begin();
4992 for(; aItD != aPrms.end(); ++aItD) {
4996 aC3D->D1( aT, aP3D, aVec );
4997 aL2 = aVec.SquareMagnitude();
4998 if ( aL2 < aTolVec2 )
4999 return EXTR_CANT_GET_TANGENT;
5000 gp_Dir aTgt( aVec );
5002 aPP.SetTangent( aTgt );
5003 aPP.SetParameter( aT );
5010 //=======================================================================
5011 //function : MakeExtrElements
5012 //purpose : auxilary for ExtrusionAlongTrack
5013 //=======================================================================
5014 SMESH_MeshEditor::Extrusion_Error
5015 SMESH_MeshEditor::MakeExtrElements(TIDSortedElemSet& theElements,
5016 list<SMESH_MeshEditor_PathPoint>& fullList,
5017 const bool theHasAngles,
5018 list<double>& theAngles,
5019 const bool theLinearVariation,
5020 const bool theHasRefPoint,
5021 const gp_Pnt& theRefPoint,
5022 const bool theMakeGroups)
5024 MESSAGE("MakeExtrElements");
5025 //cout<<"MakeExtrElements fullList.size() = "<<fullList.size()<<endl;
5026 int aNbTP = fullList.size();
5027 vector<SMESH_MeshEditor_PathPoint> aPPs(aNbTP);
5029 if( theHasAngles && theAngles.size()>0 && theLinearVariation ) {
5030 LinearAngleVariation(aNbTP-1, theAngles);
5032 vector<double> aAngles( aNbTP );
5034 for(; j<aNbTP; ++j) {
5037 if ( theHasAngles ) {
5039 std::list<double>::iterator aItD = theAngles.begin();
5040 for ( j=1; (aItD != theAngles.end()) && (j<aNbTP); ++aItD, ++j ) {
5042 aAngles[j] = anAngle;
5045 // fill vector of path points with angles
5046 //aPPs.resize(fullList.size());
5048 list<SMESH_MeshEditor_PathPoint>::iterator itPP = fullList.begin();
5049 for(; itPP!=fullList.end(); itPP++) {
5051 SMESH_MeshEditor_PathPoint PP = *itPP;
5052 PP.SetAngle(aAngles[j]);
5056 TNodeOfNodeListMap mapNewNodes;
5057 TElemOfVecOfNnlmiMap mapElemNewNodes;
5058 TElemOfElemListMap newElemsMap;
5059 TIDSortedElemSet::iterator itElem;
5062 SMDSAbs_ElementType aTypeE;
5063 // source elements for each generated one
5064 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5066 // 3. Center of rotation aV0
5067 gp_Pnt aV0 = theRefPoint;
5069 if ( !theHasRefPoint ) {
5071 aGC.SetCoord( 0.,0.,0. );
5073 itElem = theElements.begin();
5074 for ( ; itElem != theElements.end(); itElem++ ) {
5075 const SMDS_MeshElement* elem = *itElem;
5077 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5078 while ( itN->more() ) {
5079 const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( itN->next() );
5084 if ( mapNewNodes.find( node ) == mapNewNodes.end() ) {
5085 list<const SMDS_MeshNode*> aLNx;
5086 mapNewNodes[node] = aLNx;
5088 gp_XYZ aXYZ( aX, aY, aZ );
5096 } // if (!theHasRefPoint) {
5097 mapNewNodes.clear();
5099 // 4. Processing the elements
5100 SMESHDS_Mesh* aMesh = GetMeshDS();
5102 for ( itElem = theElements.begin(); itElem != theElements.end(); itElem++ ) {
5103 // check element type
5104 const SMDS_MeshElement* elem = *itElem;
5105 aTypeE = elem->GetType();
5106 if ( !elem || ( aTypeE != SMDSAbs_Face && aTypeE != SMDSAbs_Edge ) )
5109 vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
5110 newNodesItVec.reserve( elem->NbNodes() );
5112 // loop on elem nodes
5114 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5115 while ( itN->more() )
5118 // check if a node has been already processed
5119 const SMDS_MeshNode* node =
5120 static_cast<const SMDS_MeshNode*>( itN->next() );
5121 TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
5122 if ( nIt == mapNewNodes.end() ) {
5123 nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
5124 list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
5127 aX = node->X(); aY = node->Y(); aZ = node->Z();
5129 Standard_Real aAngle1x, aAngleT1T0, aTolAng;
5130 gp_Pnt aP0x, aP1x, aPN0, aPN1, aV0x, aV1x;
5131 gp_Ax1 anAx1, anAxT1T0;
5132 gp_Dir aDT1x, aDT0x, aDT1T0;
5137 aPN0.SetCoord(aX, aY, aZ);
5139 const SMESH_MeshEditor_PathPoint& aPP0 = aPPs[0];
5141 aDT0x= aPP0.Tangent();
5142 //cout<<"j = 0 PP: Pnt("<<aP0x.X()<<","<<aP0x.Y()<<","<<aP0x.Z()<<")"<<endl;
5144 for ( j = 1; j < aNbTP; ++j ) {
5145 const SMESH_MeshEditor_PathPoint& aPP1 = aPPs[j];
5147 aDT1x = aPP1.Tangent();
5148 aAngle1x = aPP1.Angle();
5150 gp_Trsf aTrsf, aTrsfRot, aTrsfRotT1T0;
5152 gp_Vec aV01x( aP0x, aP1x );
5153 aTrsf.SetTranslation( aV01x );
5156 aV1x = aV0x.Transformed( aTrsf );
5157 aPN1 = aPN0.Transformed( aTrsf );
5159 // rotation 1 [ T1,T0 ]
5160 aAngleT1T0=-aDT1x.Angle( aDT0x );
5161 if (fabs(aAngleT1T0) > aTolAng) {
5163 anAxT1T0.SetLocation( aV1x );
5164 anAxT1T0.SetDirection( aDT1T0 );
5165 aTrsfRotT1T0.SetRotation( anAxT1T0, aAngleT1T0 );
5167 aPN1 = aPN1.Transformed( aTrsfRotT1T0 );
5171 if ( theHasAngles ) {
5172 anAx1.SetLocation( aV1x );
5173 anAx1.SetDirection( aDT1x );
5174 aTrsfRot.SetRotation( anAx1, aAngle1x );
5176 aPN1 = aPN1.Transformed( aTrsfRot );
5180 //MESSAGE("elem->IsQuadratic " << elem->IsQuadratic() << " " << elem->IsMediumNode(node));
5181 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5182 // create additional node
5183 double x = ( aPN1.X() + aPN0.X() )/2.;
5184 double y = ( aPN1.Y() + aPN0.Y() )/2.;
5185 double z = ( aPN1.Z() + aPN0.Z() )/2.;
5186 const SMDS_MeshNode* newNode = aMesh->AddNode(x,y,z);
5187 myLastCreatedNodes.Append(newNode);
5188 srcNodes.Append( node );
5189 listNewNodes.push_back( newNode );
5194 const SMDS_MeshNode* newNode = aMesh->AddNode( aX, aY, aZ );
5195 myLastCreatedNodes.Append(newNode);
5196 srcNodes.Append( node );
5197 listNewNodes.push_back( newNode );
5207 // if current elem is quadratic and current node is not medium
5208 // we have to check - may be it is needed to insert additional nodes
5209 if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
5210 list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
5211 if(listNewNodes.size()==aNbTP-1) {
5212 vector<const SMDS_MeshNode*> aNodes(2*(aNbTP-1));
5213 gp_XYZ P(node->X(), node->Y(), node->Z());
5214 list< const SMDS_MeshNode* >::iterator it = listNewNodes.begin();
5216 for(i=0; i<aNbTP-1; i++) {
5217 const SMDS_MeshNode* N = *it;
5218 double x = ( N->X() + P.X() )/2.;
5219 double y = ( N->Y() + P.Y() )/2.;
5220 double z = ( N->Z() + P.Z() )/2.;
5221 const SMDS_MeshNode* newN = aMesh->AddNode(x,y,z);
5222 srcNodes.Append( node );
5223 myLastCreatedNodes.Append(newN);
5226 P = gp_XYZ(N->X(),N->Y(),N->Z());
5228 listNewNodes.clear();
5229 for(i=0; i<2*(aNbTP-1); i++) {
5230 listNewNodes.push_back(aNodes[i]);
5236 newNodesItVec.push_back( nIt );
5238 // make new elements
5239 //sweepElement( aMesh, elem, newNodesItVec, newElemsMap[elem],
5240 // newNodesItVec[0]->second.size(), myLastCreatedElems );
5241 sweepElement( elem, newNodesItVec, newElemsMap[elem], aNbTP-1, srcElems );
5244 makeWalls( mapNewNodes, newElemsMap, mapElemNewNodes, theElements, aNbTP-1, srcElems );
5246 if ( theMakeGroups )
5247 generateGroups( srcNodes, srcElems, "extruded");
5253 //=======================================================================
5254 //function : LinearAngleVariation
5255 //purpose : auxilary for ExtrusionAlongTrack
5256 //=======================================================================
5257 void SMESH_MeshEditor::LinearAngleVariation(const int nbSteps,
5258 list<double>& Angles)
5260 int nbAngles = Angles.size();
5261 if( nbSteps > nbAngles ) {
5262 vector<double> theAngles(nbAngles);
5263 list<double>::iterator it = Angles.begin();
5265 for(; it!=Angles.end(); it++) {
5267 theAngles[i] = (*it);
5270 double rAn2St = double( nbAngles ) / double( nbSteps );
5271 double angPrev = 0, angle;
5272 for ( int iSt = 0; iSt < nbSteps; ++iSt ) {
5273 double angCur = rAn2St * ( iSt+1 );
5274 double angCurFloor = floor( angCur );
5275 double angPrevFloor = floor( angPrev );
5276 if ( angPrevFloor == angCurFloor )
5277 angle = rAn2St * theAngles[ int( angCurFloor ) ];
5279 int iP = int( angPrevFloor );
5280 double angPrevCeil = ceil(angPrev);
5281 angle = ( angPrevCeil - angPrev ) * theAngles[ iP ];
5283 int iC = int( angCurFloor );
5284 if ( iC < nbAngles )
5285 angle += ( angCur - angCurFloor ) * theAngles[ iC ];
5287 iP = int( angPrevCeil );
5289 angle += theAngles[ iC ];
5291 res.push_back(angle);
5296 for(; it!=res.end(); it++)
5297 Angles.push_back( *it );
5302 //================================================================================
5304 * \brief Move or copy theElements applying theTrsf to their nodes
5305 * \param theElems - elements to transform, if theElems is empty then apply to all mesh nodes
5306 * \param theTrsf - transformation to apply
5307 * \param theCopy - if true, create translated copies of theElems
5308 * \param theMakeGroups - if true and theCopy, create translated groups
5309 * \param theTargetMesh - mesh to copy translated elements into
5310 * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
5312 //================================================================================
5314 SMESH_MeshEditor::PGroupIDs
5315 SMESH_MeshEditor::Transform (TIDSortedElemSet & theElems,
5316 const gp_Trsf& theTrsf,
5318 const bool theMakeGroups,
5319 SMESH_Mesh* theTargetMesh)
5321 myLastCreatedElems.Clear();
5322 myLastCreatedNodes.Clear();
5324 bool needReverse = false;
5325 string groupPostfix;
5326 switch ( theTrsf.Form() ) {
5328 MESSAGE("gp_PntMirror");
5330 groupPostfix = "mirrored";
5333 MESSAGE("gp_Ax1Mirror");
5334 groupPostfix = "mirrored";
5337 MESSAGE("gp_Ax2Mirror");
5339 groupPostfix = "mirrored";
5342 MESSAGE("gp_Rotation");
5343 groupPostfix = "rotated";
5345 case gp_Translation:
5346 MESSAGE("gp_Translation");
5347 groupPostfix = "translated";
5350 MESSAGE("gp_Scale");
5351 groupPostfix = "scaled";
5353 case gp_CompoundTrsf: // different scale by axis
5354 MESSAGE("gp_CompoundTrsf");
5355 groupPostfix = "scaled";
5359 needReverse = false;
5360 groupPostfix = "transformed";
5363 SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5364 SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5365 SMESHDS_Mesh* aMesh = GetMeshDS();
5368 // map old node to new one
5369 TNodeNodeMap nodeMap;
5371 // elements sharing moved nodes; those of them which have all
5372 // nodes mirrored but are not in theElems are to be reversed
5373 TIDSortedElemSet inverseElemSet;
5375 // source elements for each generated one
5376 SMESH_SequenceOfElemPtr srcElems, srcNodes;
5378 // issue 021015: EDF 1578 SMESH: Free nodes are removed when translating a mesh
5379 TIDSortedElemSet orphanNode;
5381 if ( theElems.empty() ) // transform the whole mesh
5384 SMDS_ElemIteratorPtr eIt = aMesh->elementsIterator();
5385 while ( eIt->more() ) theElems.insert( eIt->next() );
5387 SMDS_NodeIteratorPtr nIt = aMesh->nodesIterator();
5388 while ( nIt->more() )
5390 const SMDS_MeshNode* node = nIt->next();
5391 if ( node->NbInverseElements() == 0)
5392 orphanNode.insert( node );
5396 // loop on elements to transform nodes : first orphan nodes then elems
5397 TIDSortedElemSet::iterator itElem;
5398 TIDSortedElemSet *elements[] = {&orphanNode, &theElems };
5399 for (int i=0; i<2; i++)
5400 for ( itElem = elements[i]->begin(); itElem != elements[i]->end(); itElem++ ) {
5401 const SMDS_MeshElement* elem = *itElem;
5405 // loop on elem nodes
5406 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5407 while ( itN->more() ) {
5409 const SMDS_MeshNode* node = cast2Node( itN->next() );
5410 // check if a node has been already transformed
5411 pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5412 nodeMap.insert( make_pair ( node, node ));
5413 if ( !n2n_isnew.second )
5417 coord[0] = node->X();
5418 coord[1] = node->Y();
5419 coord[2] = node->Z();
5420 theTrsf.Transforms( coord[0], coord[1], coord[2] );
5421 if ( theTargetMesh ) {
5422 const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5423 n2n_isnew.first->second = newNode;
5424 myLastCreatedNodes.Append(newNode);
5425 srcNodes.Append( node );
5427 else if ( theCopy ) {
5428 const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5429 n2n_isnew.first->second = newNode;
5430 myLastCreatedNodes.Append(newNode);
5431 srcNodes.Append( node );
5434 aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5435 // node position on shape becomes invalid
5436 const_cast< SMDS_MeshNode* > ( node )->SetPosition
5437 ( SMDS_SpacePosition::originSpacePosition() );
5440 // keep inverse elements
5441 if ( !theCopy && !theTargetMesh && needReverse ) {
5442 SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5443 while ( invElemIt->more() ) {
5444 const SMDS_MeshElement* iel = invElemIt->next();
5445 inverseElemSet.insert( iel );
5451 // either create new elements or reverse mirrored ones
5452 if ( !theCopy && !needReverse && !theTargetMesh )
5455 TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5456 for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5457 theElems.insert( *invElemIt );
5459 // replicate or reverse elements
5460 // TODO revoir ordre reverse vtk
5462 REV_TETRA = 0, // = nbNodes - 4
5463 REV_PYRAMID = 1, // = nbNodes - 4
5464 REV_PENTA = 2, // = nbNodes - 4
5466 REV_HEXA = 4, // = nbNodes - 4
5470 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5471 { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5472 { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5473 { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5474 { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5475 { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5478 for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5480 const SMDS_MeshElement* elem = *itElem;
5481 if ( !elem || elem->GetType() == SMDSAbs_Node )
5484 int nbNodes = elem->NbNodes();
5485 int elemType = elem->GetType();
5487 if (elem->IsPoly()) {
5488 // Polygon or Polyhedral Volume
5489 switch ( elemType ) {
5492 vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5494 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5495 while (itN->more()) {
5496 const SMDS_MeshNode* node =
5497 static_cast<const SMDS_MeshNode*>(itN->next());
5498 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5499 if (nodeMapIt == nodeMap.end())
5500 break; // not all nodes transformed
5502 // reverse mirrored faces and volumes
5503 poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5505 poly_nodes[iNode] = (*nodeMapIt).second;
5509 if ( iNode != nbNodes )
5510 continue; // not all nodes transformed
5512 if ( theTargetMesh ) {
5513 myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5514 srcElems.Append( elem );
5516 else if ( theCopy ) {
5517 myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5518 srcElems.Append( elem );
5521 aMesh->ChangePolygonNodes(elem, poly_nodes);
5525 case SMDSAbs_Volume:
5527 // ATTENTION: Reversing is not yet done!!!
5528 const SMDS_VtkVolume* aPolyedre =
5529 dynamic_cast<const SMDS_VtkVolume*>( elem );
5531 MESSAGE("Warning: bad volumic element");
5535 vector<const SMDS_MeshNode*> poly_nodes;
5536 vector<int> quantities;
5538 bool allTransformed = true;
5539 int nbFaces = aPolyedre->NbFaces();
5540 for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5541 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5542 for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5543 const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5544 TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5545 if (nodeMapIt == nodeMap.end()) {
5546 allTransformed = false; // not all nodes transformed
5548 poly_nodes.push_back((*nodeMapIt).second);
5551 quantities.push_back(nbFaceNodes);
5553 if ( !allTransformed )
5554 continue; // not all nodes transformed
5556 if ( theTargetMesh ) {
5557 myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5558 srcElems.Append( elem );
5560 else if ( theCopy ) {
5561 myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5562 srcElems.Append( elem );
5565 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5575 int* i = index[ FORWARD ];
5576 if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
5577 if ( elemType == SMDSAbs_Face )
5578 i = index[ REV_FACE ];
5580 i = index[ nbNodes - 4 ];
5582 if(elem->IsQuadratic()) {
5583 static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5586 if(nbNodes==3) { // quadratic edge
5587 static int anIds[] = {1,0,2};
5590 else if(nbNodes==6) { // quadratic triangle
5591 static int anIds[] = {0,2,1,5,4,3};
5594 else if(nbNodes==8) { // quadratic quadrangle
5595 static int anIds[] = {0,3,2,1,7,6,5,4};
5598 else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5599 static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5602 else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5603 static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5606 else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5607 static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5610 else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5611 static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5617 // find transformed nodes
5618 vector<const SMDS_MeshNode*> nodes(nbNodes);
5620 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5621 while ( itN->more() ) {
5622 const SMDS_MeshNode* node =
5623 static_cast<const SMDS_MeshNode*>( itN->next() );
5624 TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5625 if ( nodeMapIt == nodeMap.end() )
5626 break; // not all nodes transformed
5627 nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5629 if ( iNode != nbNodes )
5630 continue; // not all nodes transformed
5632 if ( theTargetMesh ) {
5633 if ( SMDS_MeshElement* copy =
5634 targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5635 myLastCreatedElems.Append( copy );
5636 srcElems.Append( elem );
5639 else if ( theCopy ) {
5640 if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
5641 srcElems.Append( elem );
5644 // reverse element as it was reversed by transformation
5646 aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5650 PGroupIDs newGroupIDs;
5652 if ( theMakeGroups && theCopy ||
5653 theMakeGroups && theTargetMesh )
5654 newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5660 ////=======================================================================
5661 ////function : Scale
5663 ////=======================================================================
5665 //SMESH_MeshEditor::PGroupIDs
5666 //SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
5667 // const gp_Pnt& thePoint,
5668 // const std::list<double>& theScaleFact,
5669 // const bool theCopy,
5670 // const bool theMakeGroups,
5671 // SMESH_Mesh* theTargetMesh)
5673 // MESSAGE("Scale");
5674 // myLastCreatedElems.Clear();
5675 // myLastCreatedNodes.Clear();
5677 // SMESH_MeshEditor targetMeshEditor( theTargetMesh );
5678 // SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
5679 // SMESHDS_Mesh* aMesh = GetMeshDS();
5681 // double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
5682 // std::list<double>::const_iterator itS = theScaleFact.begin();
5684 // if(theScaleFact.size()==1) {
5688 // if(theScaleFact.size()==2) {
5693 // if(theScaleFact.size()>2) {
5700 // // map old node to new one
5701 // TNodeNodeMap nodeMap;
5703 // // elements sharing moved nodes; those of them which have all
5704 // // nodes mirrored but are not in theElems are to be reversed
5705 // TIDSortedElemSet inverseElemSet;
5707 // // source elements for each generated one
5708 // SMESH_SequenceOfElemPtr srcElems, srcNodes;
5710 // // loop on theElems
5711 // TIDSortedElemSet::iterator itElem;
5712 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
5713 // const SMDS_MeshElement* elem = *itElem;
5717 // // loop on elem nodes
5718 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5719 // while ( itN->more() ) {
5721 // // check if a node has been already transformed
5722 // const SMDS_MeshNode* node = cast2Node( itN->next() );
5723 // pair<TNodeNodeMap::iterator,bool> n2n_isnew =
5724 // nodeMap.insert( make_pair ( node, node ));
5725 // if ( !n2n_isnew.second )
5728 // //double coord[3];
5729 // //coord[0] = node->X();
5730 // //coord[1] = node->Y();
5731 // //coord[2] = node->Z();
5732 // //theTrsf.Transforms( coord[0], coord[1], coord[2] );
5733 // double dx = (node->X() - thePoint.X()) * scaleX;
5734 // double dy = (node->Y() - thePoint.Y()) * scaleY;
5735 // double dz = (node->Z() - thePoint.Z()) * scaleZ;
5736 // if ( theTargetMesh ) {
5737 // //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
5738 // const SMDS_MeshNode * newNode =
5739 // aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5740 // n2n_isnew.first->second = newNode;
5741 // myLastCreatedNodes.Append(newNode);
5742 // srcNodes.Append( node );
5744 // else if ( theCopy ) {
5745 // //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
5746 // const SMDS_MeshNode * newNode =
5747 // aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5748 // n2n_isnew.first->second = newNode;
5749 // myLastCreatedNodes.Append(newNode);
5750 // srcNodes.Append( node );
5753 // //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
5754 // aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
5755 // // node position on shape becomes invalid
5756 // const_cast< SMDS_MeshNode* > ( node )->SetPosition
5757 // ( SMDS_SpacePosition::originSpacePosition() );
5760 // // keep inverse elements
5761 // //if ( !theCopy && !theTargetMesh && needReverse ) {
5762 // // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
5763 // // while ( invElemIt->more() ) {
5764 // // const SMDS_MeshElement* iel = invElemIt->next();
5765 // // inverseElemSet.insert( iel );
5771 // // either create new elements or reverse mirrored ones
5772 // //if ( !theCopy && !needReverse && !theTargetMesh )
5773 // if ( !theCopy && !theTargetMesh )
5774 // return PGroupIDs();
5776 // TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
5777 // for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
5778 // theElems.insert( *invElemIt );
5780 // // replicate or reverse elements
5783 // REV_TETRA = 0, // = nbNodes - 4
5784 // REV_PYRAMID = 1, // = nbNodes - 4
5785 // REV_PENTA = 2, // = nbNodes - 4
5787 // REV_HEXA = 4, // = nbNodes - 4
5790 // int index[][8] = {
5791 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
5792 // { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
5793 // { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
5794 // { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
5795 // { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
5796 // { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
5799 // for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
5801 // const SMDS_MeshElement* elem = *itElem;
5802 // if ( !elem || elem->GetType() == SMDSAbs_Node )
5805 // int nbNodes = elem->NbNodes();
5806 // int elemType = elem->GetType();
5808 // if (elem->IsPoly()) {
5809 // // Polygon or Polyhedral Volume
5810 // switch ( elemType ) {
5811 // case SMDSAbs_Face:
5813 // vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
5815 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5816 // while (itN->more()) {
5817 // const SMDS_MeshNode* node =
5818 // static_cast<const SMDS_MeshNode*>(itN->next());
5819 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5820 // if (nodeMapIt == nodeMap.end())
5821 // break; // not all nodes transformed
5822 // //if (needReverse) {
5823 // // // reverse mirrored faces and volumes
5824 // // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
5826 // poly_nodes[iNode] = (*nodeMapIt).second;
5830 // if ( iNode != nbNodes )
5831 // continue; // not all nodes transformed
5833 // if ( theTargetMesh ) {
5834 // myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
5835 // srcElems.Append( elem );
5837 // else if ( theCopy ) {
5838 // myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
5839 // srcElems.Append( elem );
5842 // aMesh->ChangePolygonNodes(elem, poly_nodes);
5846 // case SMDSAbs_Volume:
5848 // // ATTENTION: Reversing is not yet done!!!
5849 // const SMDS_VtkVolume* aPolyedre =
5850 // dynamic_cast<const SMDS_VtkVolume*>( elem );
5851 // if (!aPolyedre) {
5852 // MESSAGE("Warning: bad volumic element");
5856 // vector<const SMDS_MeshNode*> poly_nodes;
5857 // vector<int> quantities;
5859 // bool allTransformed = true;
5860 // int nbFaces = aPolyedre->NbFaces();
5861 // for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
5862 // int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
5863 // for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
5864 // const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
5865 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
5866 // if (nodeMapIt == nodeMap.end()) {
5867 // allTransformed = false; // not all nodes transformed
5869 // poly_nodes.push_back((*nodeMapIt).second);
5872 // quantities.push_back(nbFaceNodes);
5874 // if ( !allTransformed )
5875 // continue; // not all nodes transformed
5877 // if ( theTargetMesh ) {
5878 // myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
5879 // srcElems.Append( elem );
5881 // else if ( theCopy ) {
5882 // myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
5883 // srcElems.Append( elem );
5886 // aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
5895 // // Regular elements
5896 // int* i = index[ FORWARD ];
5897 // //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
5898 // // if ( elemType == SMDSAbs_Face )
5899 // // i = index[ REV_FACE ];
5901 // // i = index[ nbNodes - 4 ];
5903 // if(elem->IsQuadratic()) {
5904 // static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
5906 // //if(needReverse) {
5907 // // if(nbNodes==3) { // quadratic edge
5908 // // static int anIds[] = {1,0,2};
5911 // // else if(nbNodes==6) { // quadratic triangle
5912 // // static int anIds[] = {0,2,1,5,4,3};
5915 // // else if(nbNodes==8) { // quadratic quadrangle
5916 // // static int anIds[] = {0,3,2,1,7,6,5,4};
5919 // // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
5920 // // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
5923 // // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
5924 // // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
5927 // // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
5928 // // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
5931 // // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
5932 // // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
5938 // // find transformed nodes
5939 // vector<const SMDS_MeshNode*> nodes(nbNodes);
5941 // SMDS_ElemIteratorPtr itN = elem->nodesIterator();
5942 // while ( itN->more() ) {
5943 // const SMDS_MeshNode* node =
5944 // static_cast<const SMDS_MeshNode*>( itN->next() );
5945 // TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
5946 // if ( nodeMapIt == nodeMap.end() )
5947 // break; // not all nodes transformed
5948 // nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
5950 // if ( iNode != nbNodes )
5951 // continue; // not all nodes transformed
5953 // if ( theTargetMesh ) {
5954 // if ( SMDS_MeshElement* copy =
5955 // targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5956 // myLastCreatedElems.Append( copy );
5957 // srcElems.Append( elem );
5960 // else if ( theCopy ) {
5961 // if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
5962 // myLastCreatedElems.Append( copy );
5963 // srcElems.Append( elem );
5967 // // reverse element as it was reversed by transformation
5968 // if ( nbNodes > 2 )
5969 // aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
5973 // PGroupIDs newGroupIDs;
5975 // if ( theMakeGroups && theCopy ||
5976 // theMakeGroups && theTargetMesh ) {
5977 // string groupPostfix = "scaled";
5978 // newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
5981 // return newGroupIDs;
5985 //=======================================================================
5987 * \brief Create groups of elements made during transformation
5988 * \param nodeGens - nodes making corresponding myLastCreatedNodes
5989 * \param elemGens - elements making corresponding myLastCreatedElems
5990 * \param postfix - to append to names of new groups
5992 //=======================================================================
5994 SMESH_MeshEditor::PGroupIDs
5995 SMESH_MeshEditor::generateGroups(const SMESH_SequenceOfElemPtr& nodeGens,
5996 const SMESH_SequenceOfElemPtr& elemGens,
5997 const std::string& postfix,
5998 SMESH_Mesh* targetMesh)
6000 PGroupIDs newGroupIDs( new list<int> );
6001 SMESH_Mesh* mesh = targetMesh ? targetMesh : GetMesh();
6003 // Sort existing groups by types and collect their names
6005 // to store an old group and a generated new one
6006 typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
6007 vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
6009 set< string > groupNames;
6011 SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
6012 SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
6013 while ( groupIt->more() ) {
6014 SMESH_Group * group = groupIt->next();
6015 if ( !group ) continue;
6016 SMESHDS_GroupBase* groupDS = group->GetGroupDS();
6017 if ( !groupDS || groupDS->IsEmpty() ) continue;
6018 groupNames.insert( group->GetName() );
6019 groupDS->SetStoreName( group->GetName() );
6020 groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
6025 // loop on nodes and elements
6026 for ( int isNodes = 0; isNodes < 2; ++isNodes )
6028 const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
6029 const SMESH_SequenceOfElemPtr& elems = isNodes ? myLastCreatedNodes : myLastCreatedElems;
6030 if ( gens.Length() != elems.Length() )
6031 throw SALOME_Exception(LOCALIZED("invalid args"));
6033 // loop on created elements
6034 for (int iElem = 1; iElem <= elems.Length(); ++iElem )
6036 const SMDS_MeshElement* sourceElem = gens( iElem );
6037 if ( !sourceElem ) {
6038 MESSAGE("generateGroups(): NULL source element");
6041 list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
6042 if ( groupsOldNew.empty() ) {
6043 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6044 ++iElem; // skip all elements made by sourceElem
6047 // collect all elements made by sourceElem
6048 list< const SMDS_MeshElement* > resultElems;
6049 if ( const SMDS_MeshElement* resElem = elems( iElem ))
6050 if ( resElem != sourceElem )
6051 resultElems.push_back( resElem );
6052 while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
6053 if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
6054 if ( resElem != sourceElem )
6055 resultElems.push_back( resElem );
6056 // do not generate element groups from node ones
6057 if ( sourceElem->GetType() == SMDSAbs_Node &&
6058 elems( iElem )->GetType() != SMDSAbs_Node )
6061 // add resultElems to groups made by ones the sourceElem belongs to
6062 list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
6063 for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
6065 SMESHDS_GroupBase* oldGroup = gOldNew->first;
6066 if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
6068 SMDS_MeshGroup* & newGroup = gOldNew->second;
6069 if ( !newGroup )// create a new group
6072 string name = oldGroup->GetStoreName();
6073 if ( !targetMesh ) {
6077 while ( !groupNames.insert( name ).second ) // name exists
6083 TCollection_AsciiString nbStr(nb+1);
6084 name.resize( name.rfind('_')+1 );
6085 name += nbStr.ToCString();
6092 SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
6094 SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
6095 newGroup = & groupDS->SMDSGroup();
6096 newGroupIDs->push_back( id );
6099 // fill in a new group
6100 list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
6101 for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
6102 newGroup->Add( *resElemIt );
6105 } // loop on created elements
6106 }// loop on nodes and elements
6111 //================================================================================
6113 * \brief Return list of group of nodes close to each other within theTolerance
6114 * Search among theNodes or in the whole mesh if theNodes is empty using
6115 * an Octree algorithm
6117 //================================================================================
6119 void SMESH_MeshEditor::FindCoincidentNodes (TIDSortedNodeSet & theNodes,
6120 const double theTolerance,
6121 TListOfListOfNodes & theGroupsOfNodes)
6123 myLastCreatedElems.Clear();
6124 myLastCreatedNodes.Clear();
6126 if ( theNodes.empty() )
6127 { // get all nodes in the mesh
6128 SMDS_NodeIteratorPtr nIt = GetMeshDS()->nodesIterator(/*idInceasingOrder=*/true);
6129 while ( nIt->more() )
6130 theNodes.insert( theNodes.end(),nIt->next());
6133 SMESH_OctreeNode::FindCoincidentNodes ( theNodes, &theGroupsOfNodes, theTolerance);
6137 //=======================================================================
6139 * \brief Implementation of search for the node closest to point
6141 //=======================================================================
6143 struct SMESH_NodeSearcherImpl: public SMESH_NodeSearcher
6145 //---------------------------------------------------------------------
6147 * \brief Constructor
6149 SMESH_NodeSearcherImpl( const SMESHDS_Mesh* theMesh )
6151 myMesh = ( SMESHDS_Mesh* ) theMesh;
6153 TIDSortedNodeSet nodes;
6155 SMDS_NodeIteratorPtr nIt = theMesh->nodesIterator(/*idInceasingOrder=*/true);
6156 while ( nIt->more() )
6157 nodes.insert( nodes.end(), nIt->next() );
6159 myOctreeNode = new SMESH_OctreeNode(nodes) ;
6161 // get max size of a leaf box
6162 SMESH_OctreeNode* tree = myOctreeNode;
6163 while ( !tree->isLeaf() )
6165 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6169 myHalfLeafSize = tree->maxSize() / 2.;
6172 //---------------------------------------------------------------------
6174 * \brief Move node and update myOctreeNode accordingly
6176 void MoveNode( const SMDS_MeshNode* node, const gp_Pnt& toPnt )
6178 myOctreeNode->UpdateByMoveNode( node, toPnt );
6179 myMesh->MoveNode( node, toPnt.X(), toPnt.Y(), toPnt.Z() );
6182 //---------------------------------------------------------------------
6184 * \brief Do it's job
6186 const SMDS_MeshNode* FindClosestTo( const gp_Pnt& thePnt )
6188 map<double, const SMDS_MeshNode*> dist2Nodes;
6189 myOctreeNode->NodesAround( thePnt.Coord(), dist2Nodes, myHalfLeafSize );
6190 if ( !dist2Nodes.empty() )
6191 return dist2Nodes.begin()->second;
6192 list<const SMDS_MeshNode*> nodes;
6193 //myOctreeNode->NodesAround( &tgtNode, &nodes, myHalfLeafSize );
6195 double minSqDist = DBL_MAX;
6196 if ( nodes.empty() ) // get all nodes of OctreeNode's closest to thePnt
6198 // sort leafs by their distance from thePnt
6199 typedef map< double, SMESH_OctreeNode* > TDistTreeMap;
6200 TDistTreeMap treeMap;
6201 list< SMESH_OctreeNode* > treeList;
6202 list< SMESH_OctreeNode* >::iterator trIt;
6203 treeList.push_back( myOctreeNode );
6205 gp_XYZ pointNode( thePnt.X(), thePnt.Y(), thePnt.Z() );
6206 bool pointInside = myOctreeNode->isInside( pointNode, myHalfLeafSize );
6207 for ( trIt = treeList.begin(); trIt != treeList.end(); ++trIt)
6209 SMESH_OctreeNode* tree = *trIt;
6210 if ( !tree->isLeaf() ) // put children to the queue
6212 if ( pointInside && !tree->isInside( pointNode, myHalfLeafSize )) continue;
6213 SMESH_OctreeNodeIteratorPtr cIt = tree->GetChildrenIterator();
6214 while ( cIt->more() )
6215 treeList.push_back( cIt->next() );
6217 else if ( tree->NbNodes() ) // put a tree to the treeMap
6219 const Bnd_B3d& box = tree->getBox();
6220 double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
6221 pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
6222 if ( !it_in.second ) // not unique distance to box center
6223 treeMap.insert( it_in.first, make_pair( sqDist + 1e-13*treeMap.size(), tree ));
6226 // find distance after which there is no sense to check tree's
6227 double sqLimit = DBL_MAX;
6228 TDistTreeMap::iterator sqDist_tree = treeMap.begin();
6229 if ( treeMap.size() > 5 ) {
6230 SMESH_OctreeNode* closestTree = sqDist_tree->second;
6231 const Bnd_B3d& box = closestTree->getBox();
6232 double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
6233 sqLimit = limit * limit;
6235 // get all nodes from trees
6236 for ( ; sqDist_tree != treeMap.end(); ++sqDist_tree) {
6237 if ( sqDist_tree->first > sqLimit )
6239 SMESH_OctreeNode* tree = sqDist_tree->second;
6240 tree->NodesAround( tree->GetNodeIterator()->next(), &nodes );
6243 // find closest among nodes
6244 minSqDist = DBL_MAX;
6245 const SMDS_MeshNode* closestNode = 0;
6246 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
6247 for ( ; nIt != nodes.end(); ++nIt ) {
6248 double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
6249 if ( minSqDist > sqDist ) {
6257 //---------------------------------------------------------------------
6261 ~SMESH_NodeSearcherImpl() { delete myOctreeNode; }
6263 //---------------------------------------------------------------------
6265 * \brief Return the node tree
6267 const SMESH_OctreeNode* getTree() const { return myOctreeNode; }
6270 SMESH_OctreeNode* myOctreeNode;
6271 SMESHDS_Mesh* myMesh;
6272 double myHalfLeafSize; // max size of a leaf box
6275 //=======================================================================
6277 * \brief Return SMESH_NodeSearcher
6279 //=======================================================================
6281 SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
6283 return new SMESH_NodeSearcherImpl( GetMeshDS() );
6286 // ========================================================================
6287 namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
6289 const int MaxNbElemsInLeaf = 10; // maximal number of elements in a leaf of tree
6290 const int MaxLevel = 7; // maximal tree height -> nb terminal boxes: 8^7 = 2097152
6291 const double NodeRadius = 1e-9; // to enlarge bnd box of element
6293 //=======================================================================
6295 * \brief Octal tree of bounding boxes of elements
6297 //=======================================================================
6299 class ElementBndBoxTree : public SMESH_Octree
6303 ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
6304 void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
6305 void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
6306 ~ElementBndBoxTree();
6309 ElementBndBoxTree() {}
6310 SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
6311 void buildChildrenData();
6312 Bnd_B3d* buildRootBox();
6314 //!< Bounding box of element
6315 struct ElementBox : public Bnd_B3d
6317 const SMDS_MeshElement* _element;
6318 int _refCount; // an ElementBox can be included in several tree branches
6319 ElementBox(const SMDS_MeshElement* elem, double tolerance);
6321 vector< ElementBox* > _elements;
6324 //================================================================================
6326 * \brief ElementBndBoxTree creation
6328 //================================================================================
6330 ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
6331 :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
6333 int nbElems = mesh.GetMeshInfo().NbElements( elemType );
6334 _elements.reserve( nbElems );
6336 SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
6337 while ( elemIt->more() )
6338 _elements.push_back( new ElementBox( elemIt->next(),tolerance ));
6340 if ( _elements.size() > MaxNbElemsInLeaf )
6346 //================================================================================
6350 //================================================================================
6352 ElementBndBoxTree::~ElementBndBoxTree()
6354 for ( int i = 0; i < _elements.size(); ++i )
6355 if ( --_elements[i]->_refCount <= 0 )
6356 delete _elements[i];
6359 //================================================================================
6361 * \brief Return the maximal box
6363 //================================================================================
6365 Bnd_B3d* ElementBndBoxTree::buildRootBox()
6367 Bnd_B3d* box = new Bnd_B3d;
6368 for ( int i = 0; i < _elements.size(); ++i )
6369 box->Add( *_elements[i] );
6373 //================================================================================
6375 * \brief Redistrubute element boxes among children
6377 //================================================================================
6379 void ElementBndBoxTree::buildChildrenData()
6381 for ( int i = 0; i < _elements.size(); ++i )
6383 for (int j = 0; j < 8; j++)
6385 if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
6387 _elements[i]->_refCount++;
6388 ((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
6391 _elements[i]->_refCount--;
6395 for (int j = 0; j < 8; j++)
6397 ElementBndBoxTree* child = static_cast<ElementBndBoxTree*>( myChildren[j]);
6398 if ( child->_elements.size() <= MaxNbElemsInLeaf )
6399 child->myIsLeaf = true;
6401 if ( child->_elements.capacity() - child->_elements.size() > 1000 )
6402 child->_elements.resize( child->_elements.size() ); // compact
6406 //================================================================================
6408 * \brief Return elements which can include the point
6410 //================================================================================
6412 void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
6413 TIDSortedElemSet& foundElems)
6415 if ( level() && getBox().IsOut( point.XYZ() ))
6420 for ( int i = 0; i < _elements.size(); ++i )
6421 if ( !_elements[i]->IsOut( point.XYZ() ))
6422 foundElems.insert( _elements[i]->_element );
6426 for (int i = 0; i < 8; i++)
6427 ((ElementBndBoxTree*) myChildren[i])->getElementsNearPoint( point, foundElems );
6431 //================================================================================
6433 * \brief Return elements which can be intersected by the line
6435 //================================================================================
6437 void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
6438 TIDSortedElemSet& foundElems)
6440 if ( level() && getBox().IsOut( line ))
6445 for ( int i = 0; i < _elements.size(); ++i )
6446 if ( !_elements[i]->IsOut( line ))
6447 foundElems.insert( _elements[i]->_element );
6451 for (int i = 0; i < 8; i++)
6452 ((ElementBndBoxTree*) myChildren[i])->getElementsNearLine( line, foundElems );
6456 //================================================================================
6458 * \brief Construct the element box
6460 //================================================================================
6462 ElementBndBoxTree::ElementBox::ElementBox(const SMDS_MeshElement* elem, double tolerance)
6466 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
6467 while ( nIt->more() )
6468 Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
6469 Enlarge( tolerance );
6474 //=======================================================================
6476 * \brief Implementation of search for the elements by point and
6477 * of classification of point in 2D mesh
6479 //=======================================================================
6481 struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
6483 SMESHDS_Mesh* _mesh;
6484 SMDS_ElemIteratorPtr _meshPartIt;
6485 ElementBndBoxTree* _ebbTree;
6486 SMESH_NodeSearcherImpl* _nodeSearcher;
6487 SMDSAbs_ElementType _elementType;
6489 bool _outerFacesFound;
6490 set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
6492 SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
6493 : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
6494 ~SMESH_ElementSearcherImpl()
6496 if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
6497 if ( _nodeSearcher ) delete _nodeSearcher; _nodeSearcher = 0;
6499 virtual int FindElementsByPoint(const gp_Pnt& point,
6500 SMDSAbs_ElementType type,
6501 vector< const SMDS_MeshElement* >& foundElements);
6502 virtual TopAbs_State GetPointState(const gp_Pnt& point);
6504 void GetElementsNearLine( const gp_Ax1& line,
6505 SMDSAbs_ElementType type,
6506 vector< const SMDS_MeshElement* >& foundElems);
6507 double getTolerance();
6508 bool getIntersParamOnLine(const gp_Lin& line, const SMDS_MeshElement* face,
6509 const double tolerance, double & param);
6510 void findOuterBoundary(const SMDS_MeshElement* anyOuterFace);
6511 bool isOuterBoundary(const SMDS_MeshElement* face) const
6513 return _outerFaces.empty() || _outerFaces.count(face);
6515 struct TInters //!< data of intersection of the line and the mesh face (used in GetPointState())
6517 const SMDS_MeshElement* _face;
6519 bool _coincides; //!< the line lays in face plane
6520 TInters(const SMDS_MeshElement* face, const gp_Vec& faceNorm, bool coinc=false)
6521 : _face(face), _faceNorm( faceNorm ), _coincides( coinc ) {}
6523 struct TFaceLink //!< link and faces sharing it (used in findOuterBoundary())
6526 TIDSortedElemSet _faces;
6527 TFaceLink( const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshElement* face)
6528 : _link( n1, n2 ), _faces( &face, &face + 1) {}
6532 ostream& operator<< (ostream& out, const SMESH_ElementSearcherImpl::TInters& i)
6534 return out << "TInters(face=" << ( i._face ? i._face->GetID() : 0)
6535 << ", _coincides="<<i._coincides << ")";
6538 //=======================================================================
6540 * \brief define tolerance for search
6542 //=======================================================================
6544 double SMESH_ElementSearcherImpl::getTolerance()
6546 if ( _tolerance < 0 )
6548 const SMDS_MeshInfo& meshInfo = _mesh->GetMeshInfo();
6551 if ( _nodeSearcher && meshInfo.NbNodes() > 1 )
6553 double boxSize = _nodeSearcher->getTree()->maxSize();
6554 _tolerance = 1e-8 * boxSize/* / meshInfo.NbNodes()*/;
6556 else if ( _ebbTree && meshInfo.NbElements() > 0 )
6558 double boxSize = _ebbTree->maxSize();
6559 _tolerance = 1e-8 * boxSize/* / meshInfo.NbElements()*/;
6561 if ( _tolerance == 0 )
6563 // define tolerance by size of a most complex element
6564 int complexType = SMDSAbs_Volume;
6565 while ( complexType > SMDSAbs_All &&
6566 meshInfo.NbElements( SMDSAbs_ElementType( complexType )) < 1 )
6568 if ( complexType == SMDSAbs_All ) return 0; // empty mesh
6570 if ( complexType == int( SMDSAbs_Node ))
6572 SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
6574 if ( meshInfo.NbNodes() > 2 )
6575 elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
6579 SMDS_ElemIteratorPtr elemIt =
6580 _mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
6581 const SMDS_MeshElement* elem = elemIt->next();
6582 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
6583 SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
6585 while ( nodeIt->more() )
6587 double dist = n1.Distance( cast2Node( nodeIt->next() ));
6588 elemSize = max( dist, elemSize );
6591 _tolerance = 1e-4 * elemSize;
6597 //================================================================================
6599 * \brief Find intersection of the line and an edge of face and return parameter on line
6601 //================================================================================
6603 bool SMESH_ElementSearcherImpl::getIntersParamOnLine(const gp_Lin& line,
6604 const SMDS_MeshElement* face,
6611 GeomAPI_ExtremaCurveCurve anExtCC;
6612 Handle(Geom_Curve) lineCurve = new Geom_Line( line );
6614 int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
6615 for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
6617 GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
6618 SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
6619 anExtCC.Init( lineCurve, edge);
6620 if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
6622 Quantity_Parameter pl, pe;
6623 anExtCC.LowerDistanceParameters( pl, pe );
6625 if ( ++nbInts == 2 )
6629 if ( nbInts > 0 ) param /= nbInts;
6632 //================================================================================
6634 * \brief Find all faces belonging to the outer boundary of mesh
6636 //================================================================================
6638 void SMESH_ElementSearcherImpl::findOuterBoundary(const SMDS_MeshElement* outerFace)
6640 if ( _outerFacesFound ) return;
6642 // Collect all outer faces by passing from one outer face to another via their links
6643 // and BTW find out if there are internal faces at all.
6645 // checked links and links where outer boundary meets internal one
6646 set< SMESH_TLink > visitedLinks, seamLinks;
6648 // links to treat with already visited faces sharing them
6649 list < TFaceLink > startLinks;
6651 // load startLinks with the first outerFace
6652 startLinks.push_back( TFaceLink( outerFace->GetNode(0), outerFace->GetNode(1), outerFace));
6653 _outerFaces.insert( outerFace );
6655 TIDSortedElemSet emptySet;
6656 while ( !startLinks.empty() )
6658 const SMESH_TLink& link = startLinks.front()._link;
6659 TIDSortedElemSet& faces = startLinks.front()._faces;
6661 outerFace = *faces.begin();
6662 // find other faces sharing the link
6663 const SMDS_MeshElement* f;
6664 while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
6667 // select another outer face among the found
6668 const SMDS_MeshElement* outerFace2 = 0;
6669 if ( faces.size() == 2 )
6671 outerFace2 = (outerFace == *faces.begin() ? *faces.rbegin() : *faces.begin());
6673 else if ( faces.size() > 2 )
6675 seamLinks.insert( link );
6677 // link direction within the outerFace
6678 gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
6679 SMESH_TNodeXYZ( link.node2()));
6680 int i1 = outerFace->GetNodeIndex( link.node1() );
6681 int i2 = outerFace->GetNodeIndex( link.node2() );
6682 bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
6683 if ( rev ) n1n2.Reverse();
6685 gp_XYZ ofNorm, fNorm;
6686 if ( SMESH_Algo::FaceNormal( outerFace, ofNorm, /*normalized=*/false ))
6688 // direction from the link inside outerFace
6689 gp_Vec dirInOF = gp_Vec( ofNorm ) ^ n1n2;
6690 // sort all other faces by angle with the dirInOF
6691 map< double, const SMDS_MeshElement* > angle2Face;
6692 set< const SMDS_MeshElement*, TIDCompare >::const_iterator face = faces.begin();
6693 for ( ; face != faces.end(); ++face )
6695 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false ))
6697 gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
6698 double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
6699 if ( angle < 0 ) angle += 2*PI;
6700 angle2Face.insert( make_pair( angle, *face ));
6702 if ( !angle2Face.empty() )
6703 outerFace2 = angle2Face.begin()->second;
6706 // store the found outer face and add its links to continue seaching from
6709 _outerFaces.insert( outerFace );
6710 int nbNodes = outerFace2->NbNodes()/( outerFace2->IsQuadratic() ? 2 : 1 );
6711 for ( int i = 0; i < nbNodes; ++i )
6713 SMESH_TLink link2( outerFace2->GetNode(i), outerFace2->GetNode((i+1)%nbNodes));
6714 if ( visitedLinks.insert( link2 ).second )
6715 startLinks.push_back( TFaceLink( link2.node1(), link2.node2(), outerFace2 ));
6718 startLinks.pop_front();
6720 _outerFacesFound = true;
6722 if ( !seamLinks.empty() )
6724 // There are internal boundaries touching the outher one,
6725 // find all faces of internal boundaries in order to find
6726 // faces of boundaries of holes, if any.
6731 _outerFaces.clear();
6735 //=======================================================================
6737 * \brief Find elements of given type where the given point is IN or ON.
6738 * Returns nb of found elements and elements them-selves.
6740 * 'ALL' type means elements of any type excluding nodes and 0D elements
6742 //=======================================================================
6744 int SMESH_ElementSearcherImpl::
6745 FindElementsByPoint(const gp_Pnt& point,
6746 SMDSAbs_ElementType type,
6747 vector< const SMDS_MeshElement* >& foundElements)
6749 foundElements.clear();
6751 double tolerance = getTolerance();
6753 // =================================================================================
6754 if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
6756 if ( !_nodeSearcher )
6757 _nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
6759 const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
6760 if ( !closeNode ) return foundElements.size();
6762 if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
6763 return foundElements.size(); // to far from any node
6765 if ( type == SMDSAbs_Node )
6767 foundElements.push_back( closeNode );
6771 SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
6772 while ( elemIt->more() )
6773 foundElements.push_back( elemIt->next() );
6776 // =================================================================================
6777 else // elements more complex than 0D
6779 if ( !_ebbTree || _elementType != type )
6781 if ( _ebbTree ) delete _ebbTree;
6782 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
6784 TIDSortedElemSet suspectElems;
6785 _ebbTree->getElementsNearPoint( point, suspectElems );
6786 TIDSortedElemSet::iterator elem = suspectElems.begin();
6787 for ( ; elem != suspectElems.end(); ++elem )
6788 if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
6789 foundElements.push_back( *elem );
6791 return foundElements.size();
6794 //================================================================================
6796 * \brief Classify the given point in the closed 2D mesh
6798 //================================================================================
6800 TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
6802 double tolerance = getTolerance();
6803 if ( !_ebbTree || _elementType != SMDSAbs_Face )
6805 if ( _ebbTree ) delete _ebbTree;
6806 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
6808 // Algo: analyse transition of a line starting at the point through mesh boundary;
6809 // try three lines parallel to axis of the coordinate system and perform rough
6810 // analysis. If solution is not clear perform thorough analysis.
6812 const int nbAxes = 3;
6813 gp_Dir axisDir[ nbAxes ] = { gp::DX(), gp::DY(), gp::DZ() };
6814 map< double, TInters > paramOnLine2TInters[ nbAxes ];
6815 list< TInters > tangentInters[ nbAxes ]; // of faces whose plane includes the line
6816 multimap< int, int > nbInt2Axis; // to find the simplest case
6817 for ( int axis = 0; axis < nbAxes; ++axis )
6819 gp_Ax1 lineAxis( point, axisDir[axis]);
6820 gp_Lin line ( lineAxis );
6822 TIDSortedElemSet suspectFaces; // faces possibly intersecting the line
6823 _ebbTree->getElementsNearLine( lineAxis, suspectFaces );
6825 // Intersect faces with the line
6827 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6828 TIDSortedElemSet::iterator face = suspectFaces.begin();
6829 for ( ; face != suspectFaces.end(); ++face )
6833 if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
6834 gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
6836 // perform intersection
6837 IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
6838 if ( !intersection.IsDone() )
6840 if ( intersection.IsInQuadric() )
6842 tangentInters[ axis ].push_back( TInters( *face, fNorm, true ));
6844 else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
6846 gp_Pnt intersectionPoint = intersection.Point(1);
6847 if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
6848 u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
6851 // Analyse intersections roughly
6853 int nbInter = u2inters.size();
6857 double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
6858 if ( nbInter == 1 ) // not closed mesh
6859 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6861 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6864 if ( (f<0) == (l<0) )
6867 int nbIntBeforePoint = std::distance( u2inters.begin(), u2inters.lower_bound(0));
6868 int nbIntAfterPoint = nbInter - nbIntBeforePoint;
6869 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6872 nbInt2Axis.insert( make_pair( min( nbIntBeforePoint, nbIntAfterPoint ), axis ));
6874 if ( _outerFacesFound ) break; // pass to thorough analysis
6876 } // three attempts - loop on CS axes
6878 // Analyse intersections thoroughly.
6879 // We make two loops maximum, on the first one we only exclude touching intersections,
6880 // on the second, if situation is still unclear, we gather and use information on
6881 // position of faces (internal or outer). If faces position is already gathered,
6882 // we make the second loop right away.
6884 for ( int hasPositionInfo = _outerFacesFound; hasPositionInfo < 2; ++hasPositionInfo )
6886 multimap< int, int >::const_iterator nb_axis = nbInt2Axis.begin();
6887 for ( ; nb_axis != nbInt2Axis.end(); ++nb_axis )
6889 int axis = nb_axis->second;
6890 map< double, TInters > & u2inters = paramOnLine2TInters[ axis ];
6892 gp_Ax1 lineAxis( point, axisDir[axis]);
6893 gp_Lin line ( lineAxis );
6895 // add tangent intersections to u2inters
6897 list< TInters >::const_iterator tgtInt = tangentInters[ axis ].begin();
6898 for ( ; tgtInt != tangentInters[ axis ].end(); ++tgtInt )
6899 if ( getIntersParamOnLine( line, tgtInt->_face, tolerance, param ))
6900 u2inters.insert(make_pair( param, *tgtInt ));
6901 tangentInters[ axis ].clear();
6903 // Count intersections before and after the point excluding touching ones.
6904 // If hasPositionInfo we count intersections of outer boundary only
6906 int nbIntBeforePoint = 0, nbIntAfterPoint = 0;
6907 double f = numeric_limits<double>::max(), l = -numeric_limits<double>::max();
6908 map< double, TInters >::iterator u_int1 = u2inters.begin(), u_int2 = u_int1;
6909 bool ok = ! u_int1->second._coincides;
6910 while ( ok && u_int1 != u2inters.end() )
6912 double u = u_int1->first;
6913 bool touchingInt = false;
6914 if ( ++u_int2 != u2inters.end() )
6916 // skip intersections at the same point (if the line passes through edge or node)
6918 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u ) < tolerance )
6924 // skip tangent intersections
6926 const SMDS_MeshElement* prevFace = u_int1->second._face;
6927 while ( ok && u_int2->second._coincides )
6929 if ( SMESH_Algo::GetCommonNodes(prevFace , u_int2->second._face).empty() )
6935 ok = ( u_int2 != u2inters.end() );
6940 // skip intersections at the same point after tangent intersections
6943 double u2 = u_int2->first;
6945 while ( u_int2 != u2inters.end() && fabs( u_int2->first - u2 ) < tolerance )
6951 // decide if we skipped a touching intersection
6952 if ( nbSamePnt + nbTgt > 0 )
6954 double minDot = numeric_limits<double>::max(), maxDot = -numeric_limits<double>::max();
6955 map< double, TInters >::iterator u_int = u_int1;
6956 for ( ; u_int != u_int2; ++u_int )
6958 if ( u_int->second._coincides ) continue;
6959 double dot = u_int->second._faceNorm * line.Direction();
6960 if ( dot > maxDot ) maxDot = dot;
6961 if ( dot < minDot ) minDot = dot;
6963 touchingInt = ( minDot*maxDot < 0 );
6968 if ( !hasPositionInfo || isOuterBoundary( u_int1->second._face ))
6979 u_int1 = u_int2; // to next intersection
6981 } // loop on intersections with one line
6985 if ( fabs( f ) < tolerance || fabs( l ) < tolerance )
6988 if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
6991 if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
6992 return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
6994 if ( nbIntBeforePoint == 1 || nbIntAfterPoint == 1 )
6997 if ( (f<0) == (l<0) )
7000 if ( hasPositionInfo )
7001 return nbIntBeforePoint % 2 ? TopAbs_IN : TopAbs_OUT;
7003 } // loop on intersections of the tree lines - thorough analysis
7005 if ( !hasPositionInfo )
7007 // gather info on faces position - is face in the outer boundary or not
7008 map< double, TInters > & u2inters = paramOnLine2TInters[ 0 ];
7009 findOuterBoundary( u2inters.begin()->second._face );
7012 } // two attempts - with and w/o faces position info in the mesh
7014 return TopAbs_UNKNOWN;
7017 //=======================================================================
7019 * \brief Return elements possibly intersecting the line
7021 //=======================================================================
7023 void SMESH_ElementSearcherImpl::GetElementsNearLine( const gp_Ax1& line,
7024 SMDSAbs_ElementType type,
7025 vector< const SMDS_MeshElement* >& foundElems)
7027 if ( !_ebbTree || _elementType != type )
7029 if ( _ebbTree ) delete _ebbTree;
7030 _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
7032 TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
7033 _ebbTree->getElementsNearLine( line, suspectFaces );
7034 foundElems.assign( suspectFaces.begin(), suspectFaces.end());
7037 //=======================================================================
7039 * \brief Return SMESH_ElementSearcher
7041 //=======================================================================
7043 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher()
7045 return new SMESH_ElementSearcherImpl( *GetMeshDS() );
7048 //=======================================================================
7050 * \brief Return SMESH_ElementSearcher
7052 //=======================================================================
7054 SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
7056 return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
7059 //=======================================================================
7061 * \brief Return true if the point is IN or ON of the element
7063 //=======================================================================
7065 bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
7067 if ( element->GetType() == SMDSAbs_Volume)
7069 return SMDS_VolumeTool( element ).IsOut( point.X(), point.Y(), point.Z(), tol );
7072 // get ordered nodes
7074 vector< gp_XYZ > xyz;
7075 vector<const SMDS_MeshNode*> nodeList;
7077 SMDS_ElemIteratorPtr nodeIt = element->nodesIterator();
7078 if ( element->IsQuadratic() ) {
7079 if (const SMDS_VtkFace* f=dynamic_cast<const SMDS_VtkFace*>(element))
7080 nodeIt = f->interlacedNodesElemIterator();
7081 else if (const SMDS_VtkEdge* e =dynamic_cast<const SMDS_VtkEdge*>(element))
7082 nodeIt = e->interlacedNodesElemIterator();
7084 while ( nodeIt->more() )
7086 const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
7087 xyz.push_back( SMESH_TNodeXYZ(node) );
7088 nodeList.push_back(node);
7091 int i, nbNodes = element->NbNodes();
7093 if ( element->GetType() == SMDSAbs_Face ) // --------------------------------------------------
7095 // compute face normal
7096 gp_Vec faceNorm(0,0,0);
7097 xyz.push_back( xyz.front() );
7098 nodeList.push_back( nodeList.front() );
7099 for ( i = 0; i < nbNodes; ++i )
7101 gp_Vec edge1( xyz[i+1], xyz[i]);
7102 gp_Vec edge2( xyz[i+1], xyz[(i+2)%nbNodes] );
7103 faceNorm += edge1 ^ edge2;
7105 double normSize = faceNorm.Magnitude();
7106 if ( normSize <= tol )
7108 // degenerated face: point is out if it is out of all face edges
7109 for ( i = 0; i < nbNodes; ++i )
7111 SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
7112 if ( !isOut( &edge, point, tol ))
7117 faceNorm /= normSize;
7119 // check if the point lays on face plane
7120 gp_Vec n2p( xyz[0], point );
7121 if ( fabs( n2p * faceNorm ) > tol )
7122 return true; // not on face plane
7124 // check if point is out of face boundary:
7125 // define it by closest transition of a ray point->infinity through face boundary
7126 // on the face plane.
7127 // First, find normal of a plane perpendicular to face plane, to be used as a cutting tool
7128 // to find intersections of the ray with the boundary.
7130 gp_Vec plnNorm = ray ^ faceNorm;
7131 normSize = plnNorm.Magnitude();
7132 if ( normSize <= tol ) return false; // point coincides with the first node
7133 plnNorm /= normSize;
7134 // for each node of the face, compute its signed distance to the plane
7135 vector<double> dist( nbNodes + 1);
7136 for ( i = 0; i < nbNodes; ++i )
7138 gp_Vec n2p( xyz[i], point );
7139 dist[i] = n2p * plnNorm;
7141 dist.back() = dist.front();
7142 // find the closest intersection
7144 double rClosest, distClosest = 1e100;;
7146 for ( i = 0; i < nbNodes; ++i )
7149 if ( fabs( dist[i]) < tol )
7151 else if ( fabs( dist[i+1]) < tol )
7153 else if ( dist[i] * dist[i+1] < 0 )
7154 r = dist[i] / ( dist[i] - dist[i+1] );
7156 continue; // no intersection
7157 gp_Pnt pInt = xyz[i] * (1.-r) + xyz[i+1] * r;
7158 gp_Vec p2int ( point, pInt);
7159 if ( p2int * ray > -tol ) // right half-space
7161 double intDist = p2int.SquareMagnitude();
7162 if ( intDist < distClosest )
7167 distClosest = intDist;
7172 return true; // no intesections - out
7174 // analyse transition
7175 gp_Vec edge( xyz[iClosest], xyz[iClosest+1] );
7176 gp_Vec edgeNorm = -( edge ^ faceNorm ); // normal to intersected edge pointing out of face
7177 gp_Vec p2int ( point, pClosest );
7178 bool out = (edgeNorm * p2int) < -tol;
7179 if ( rClosest > 0. && rClosest < 1. ) // not node intersection
7182 // ray pass through a face node; analyze transition through an adjacent edge
7183 gp_Pnt p1 = xyz[ (rClosest == 0.) ? ((iClosest+nbNodes-1) % nbNodes) : (iClosest+1) ];
7184 gp_Pnt p2 = xyz[ (rClosest == 0.) ? iClosest : ((iClosest+2) % nbNodes) ];
7185 gp_Vec edgeAdjacent( p1, p2 );
7186 gp_Vec edgeNorm2 = -( edgeAdjacent ^ faceNorm );
7187 bool out2 = (edgeNorm2 * p2int) < -tol;
7189 bool covexCorner = ( edgeNorm * edgeAdjacent * (rClosest==1. ? 1. : -1.)) < 0;
7190 return covexCorner ? (out || out2) : (out && out2);
7192 if ( element->GetType() == SMDSAbs_Edge ) // --------------------------------------------------
7194 // point is out of edge if it is NOT ON any straight part of edge
7195 // (we consider quadratic edge as being composed of two straight parts)
7196 for ( i = 1; i < nbNodes; ++i )
7198 gp_Vec edge( xyz[i-1], xyz[i]);
7199 gp_Vec n1p ( xyz[i-1], point);
7200 double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude();
7203 gp_Vec n2p( xyz[i], point );
7204 if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol )
7206 return false; // point is ON this part
7210 // Node or 0D element -------------------------------------------------------------------------
7212 gp_Vec n2p ( xyz[0], point );
7213 return n2p.Magnitude() <= tol;
7218 //=======================================================================
7219 //function : SimplifyFace
7221 //=======================================================================
7222 int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
7223 vector<const SMDS_MeshNode *>& poly_nodes,
7224 vector<int>& quantities) const
7226 int nbNodes = faceNodes.size();
7231 set<const SMDS_MeshNode*> nodeSet;
7233 // get simple seq of nodes
7234 //const SMDS_MeshNode* simpleNodes[ nbNodes ];
7235 vector<const SMDS_MeshNode*> simpleNodes( nbNodes );
7236 int iSimple = 0, nbUnique = 0;
7238 simpleNodes[iSimple++] = faceNodes[0];
7240 for (int iCur = 1; iCur < nbNodes; iCur++) {
7241 if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
7242 simpleNodes[iSimple++] = faceNodes[iCur];
7243 if (nodeSet.insert( faceNodes[iCur] ).second)
7247 int nbSimple = iSimple;
7248 if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
7258 bool foundLoop = (nbSimple > nbUnique);
7261 set<const SMDS_MeshNode*> loopSet;
7262 for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
7263 const SMDS_MeshNode* n = simpleNodes[iSimple];
7264 if (!loopSet.insert( n ).second) {
7268 int iC = 0, curLast = iSimple;
7269 for (; iC < curLast; iC++) {
7270 if (simpleNodes[iC] == n) break;
7272 int loopLen = curLast - iC;
7274 // create sub-element
7276 quantities.push_back(loopLen);
7277 for (; iC < curLast; iC++) {
7278 poly_nodes.push_back(simpleNodes[iC]);
7281 // shift the rest nodes (place from the first loop position)
7282 for (iC = curLast + 1; iC < nbSimple; iC++) {
7283 simpleNodes[iC - loopLen] = simpleNodes[iC];
7285 nbSimple -= loopLen;
7288 } // for (iSimple = 0; iSimple < nbSimple; iSimple++)
7289 } // while (foundLoop)
7293 quantities.push_back(iSimple);
7294 for (int i = 0; i < iSimple; i++)
7295 poly_nodes.push_back(simpleNodes[i]);
7301 //=======================================================================
7302 //function : MergeNodes
7303 //purpose : In each group, the cdr of nodes are substituted by the first one
7305 //=======================================================================
7307 void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
7309 MESSAGE("MergeNodes");
7310 myLastCreatedElems.Clear();
7311 myLastCreatedNodes.Clear();
7313 SMESHDS_Mesh* aMesh = GetMeshDS();
7315 TNodeNodeMap nodeNodeMap; // node to replace - new node
7316 set<const SMDS_MeshElement*> elems; // all elements with changed nodes
7317 list< int > rmElemIds, rmNodeIds;
7319 // Fill nodeNodeMap and elems
7321 TListOfListOfNodes::iterator grIt = theGroupsOfNodes.begin();
7322 for ( ; grIt != theGroupsOfNodes.end(); grIt++ ) {
7323 list<const SMDS_MeshNode*>& nodes = *grIt;
7324 list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
7325 const SMDS_MeshNode* nToKeep = *nIt;
7326 //MESSAGE("node to keep " << nToKeep->GetID());
7327 for ( ++nIt; nIt != nodes.end(); nIt++ ) {
7328 const SMDS_MeshNode* nToRemove = *nIt;
7329 nodeNodeMap.insert( TNodeNodeMap::value_type( nToRemove, nToKeep ));
7330 if ( nToRemove != nToKeep ) {
7331 //MESSAGE(" node to remove " << nToRemove->GetID());
7332 rmNodeIds.push_back( nToRemove->GetID() );
7333 AddToSameGroups( nToKeep, nToRemove, aMesh );
7336 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
7337 while ( invElemIt->more() ) {
7338 const SMDS_MeshElement* elem = invElemIt->next();
7343 // Change element nodes or remove an element
7345 set<const SMDS_MeshElement*>::iterator eIt = elems.begin();
7346 for ( ; eIt != elems.end(); eIt++ ) {
7347 const SMDS_MeshElement* elem = *eIt;
7348 //MESSAGE(" ---- inverse elem on node to remove " << elem->GetID());
7349 int nbNodes = elem->NbNodes();
7350 int aShapeId = FindShape( elem );
7352 set<const SMDS_MeshNode*> nodeSet;
7353 vector< const SMDS_MeshNode*> curNodes( nbNodes ), uniqueNodes( nbNodes );
7354 int iUnique = 0, iCur = 0, nbRepl = 0;
7355 vector<int> iRepl( nbNodes );
7357 // get new seq of nodes
7358 SMDS_ElemIteratorPtr itN = elem->nodesIterator();
7359 while ( itN->more() ) {
7360 const SMDS_MeshNode* n =
7361 static_cast<const SMDS_MeshNode*>( itN->next() );
7363 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( n );
7364 if ( nnIt != nodeNodeMap.end() ) { // n sticks
7366 // BUG 0020185: begin
7368 bool stopRecur = false;
7369 set<const SMDS_MeshNode*> nodesRecur;
7370 nodesRecur.insert(n);
7371 while (!stopRecur) {
7372 TNodeNodeMap::iterator nnIt_i = nodeNodeMap.find( n );
7373 if ( nnIt_i != nodeNodeMap.end() ) { // n sticks
7374 n = (*nnIt_i).second;
7375 if (!nodesRecur.insert(n).second) {
7376 // error: recursive dependancy
7385 iRepl[ nbRepl++ ] = iCur;
7387 curNodes[ iCur ] = n;
7388 bool isUnique = nodeSet.insert( n ).second;
7390 uniqueNodes[ iUnique++ ] = n;
7394 // Analyse element topology after replacement
7397 int nbUniqueNodes = nodeSet.size();
7398 //MESSAGE("nbNodes nbUniqueNodes " << nbNodes << " " << nbUniqueNodes);
7399 if ( nbNodes != nbUniqueNodes ) { // some nodes stick
7400 // Polygons and Polyhedral volumes
7401 if (elem->IsPoly()) {
7403 if (elem->GetType() == SMDSAbs_Face) {
7405 vector<const SMDS_MeshNode *> face_nodes (nbNodes);
7407 for (; inode < nbNodes; inode++) {
7408 face_nodes[inode] = curNodes[inode];
7411 vector<const SMDS_MeshNode *> polygons_nodes;
7412 vector<int> quantities;
7413 int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
7416 for (int iface = 0; iface < nbNew; iface++) {
7417 int nbNodes = quantities[iface];
7418 vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
7419 for (int ii = 0; ii < nbNodes; ii++, inode++) {
7420 poly_nodes[ii] = polygons_nodes[inode];
7422 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
7423 myLastCreatedElems.Append(newElem);
7425 aMesh->SetMeshElementOnShape(newElem, aShapeId);
7428 MESSAGE("ChangeElementNodes MergeNodes Polygon");
7429 //aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
7430 vector<const SMDS_MeshNode *> polynodes(polygons_nodes.begin()+inode,polygons_nodes.end());
7432 if (nbNew > 0) quid = nbNew - 1;
7433 vector<int> newquant(quantities.begin()+quid, quantities.end());
7434 const SMDS_MeshElement* newElem = 0;
7435 newElem = aMesh->AddPolyhedralVolume(polynodes, newquant);
7436 myLastCreatedElems.Append(newElem);
7437 if ( aShapeId && newElem )
7438 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7439 rmElemIds.push_back(elem->GetID());
7442 rmElemIds.push_back(elem->GetID());
7446 else if (elem->GetType() == SMDSAbs_Volume) {
7447 // Polyhedral volume
7448 if (nbUniqueNodes < 4) {
7449 rmElemIds.push_back(elem->GetID());
7452 // each face has to be analyzed in order to check volume validity
7453 const SMDS_VtkVolume* aPolyedre =
7454 dynamic_cast<const SMDS_VtkVolume*>( elem );
7456 int nbFaces = aPolyedre->NbFaces();
7458 vector<const SMDS_MeshNode *> poly_nodes;
7459 vector<int> quantities;
7461 for (int iface = 1; iface <= nbFaces; iface++) {
7462 int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7463 vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
7465 for (int inode = 1; inode <= nbFaceNodes; inode++) {
7466 const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
7467 TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
7468 if (nnIt != nodeNodeMap.end()) { // faceNode sticks
7469 faceNode = (*nnIt).second;
7471 faceNodes[inode - 1] = faceNode;
7474 SimplifyFace(faceNodes, poly_nodes, quantities);
7477 if (quantities.size() > 3) {
7478 // to be done: remove coincident faces
7481 if (quantities.size() > 3)
7483 MESSAGE("ChangeElementNodes MergeNodes Polyhedron");
7484 //aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
7485 const SMDS_MeshElement* newElem = 0;
7486 newElem = aMesh->AddPolyhedralVolume(poly_nodes, quantities);
7487 myLastCreatedElems.Append(newElem);
7488 if ( aShapeId && newElem )
7489 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7490 rmElemIds.push_back(elem->GetID());
7494 rmElemIds.push_back(elem->GetID());
7505 // TODO not all the possible cases are solved. Find something more generic?
7506 switch ( nbNodes ) {
7507 case 2: ///////////////////////////////////// EDGE
7508 isOk = false; break;
7509 case 3: ///////////////////////////////////// TRIANGLE
7510 isOk = false; break;
7512 if ( elem->GetType() == SMDSAbs_Volume ) // TETRAHEDRON
7514 else { //////////////////////////////////// QUADRANGLE
7515 if ( nbUniqueNodes < 3 )
7517 else if ( nbRepl == 2 && iRepl[ 1 ] - iRepl[ 0 ] == 2 )
7518 isOk = false; // opposite nodes stick
7519 //MESSAGE("isOk " << isOk);
7522 case 6: ///////////////////////////////////// PENTAHEDRON
7523 if ( nbUniqueNodes == 4 ) {
7524 // ---------------------------------> tetrahedron
7526 iRepl[ 0 ] > 2 && iRepl[ 1 ] > 2 && iRepl[ 2 ] > 2 ) {
7527 // all top nodes stick: reverse a bottom
7528 uniqueNodes[ 0 ] = curNodes [ 1 ];
7529 uniqueNodes[ 1 ] = curNodes [ 0 ];
7531 else if (nbRepl == 3 &&
7532 iRepl[ 0 ] < 3 && iRepl[ 1 ] < 3 && iRepl[ 2 ] < 3 ) {
7533 // all bottom nodes stick: set a top before
7534 uniqueNodes[ 3 ] = uniqueNodes [ 0 ];
7535 uniqueNodes[ 0 ] = curNodes [ 3 ];
7536 uniqueNodes[ 1 ] = curNodes [ 4 ];
7537 uniqueNodes[ 2 ] = curNodes [ 5 ];
7539 else if (nbRepl == 4 &&
7540 iRepl[ 2 ] - iRepl [ 0 ] == 3 && iRepl[ 3 ] - iRepl [ 1 ] == 3 ) {
7541 // a lateral face turns into a line: reverse a bottom
7542 uniqueNodes[ 0 ] = curNodes [ 1 ];
7543 uniqueNodes[ 1 ] = curNodes [ 0 ];
7548 else if ( nbUniqueNodes == 5 ) {
7549 // PENTAHEDRON --------------------> 2 tetrahedrons
7550 if ( nbRepl == 2 && iRepl[ 1 ] - iRepl [ 0 ] == 3 ) {
7551 // a bottom node sticks with a linked top one
7553 SMDS_MeshElement* newElem =
7554 aMesh->AddVolume(curNodes[ 3 ],
7557 curNodes[ iRepl[ 0 ] == 2 ? 1 : 2 ]);
7558 myLastCreatedElems.Append(newElem);
7560 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7561 // 2. : reverse a bottom
7562 uniqueNodes[ 0 ] = curNodes [ 1 ];
7563 uniqueNodes[ 1 ] = curNodes [ 0 ];
7573 if(elem->IsQuadratic()) { // Quadratic quadrangle
7585 MESSAGE("nbRepl=2: " << iRepl[0] << " " << iRepl[1]);
7588 MESSAGE("nbRepl=3: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2]);
7590 if( iRepl[0]==0 && iRepl[1]==1 && iRepl[2]==4 ) {
7591 uniqueNodes[0] = curNodes[0];
7592 uniqueNodes[1] = curNodes[2];
7593 uniqueNodes[2] = curNodes[3];
7594 uniqueNodes[3] = curNodes[5];
7595 uniqueNodes[4] = curNodes[6];
7596 uniqueNodes[5] = curNodes[7];
7599 if( iRepl[0]==0 && iRepl[1]==3 && iRepl[2]==7 ) {
7600 uniqueNodes[0] = curNodes[0];
7601 uniqueNodes[1] = curNodes[1];
7602 uniqueNodes[2] = curNodes[2];
7603 uniqueNodes[3] = curNodes[4];
7604 uniqueNodes[4] = curNodes[5];
7605 uniqueNodes[5] = curNodes[6];
7608 if( iRepl[0]==0 && iRepl[1]==4 && iRepl[2]==7 ) {
7609 uniqueNodes[0] = curNodes[1];
7610 uniqueNodes[1] = curNodes[2];
7611 uniqueNodes[2] = curNodes[3];
7612 uniqueNodes[3] = curNodes[5];
7613 uniqueNodes[4] = curNodes[6];
7614 uniqueNodes[5] = curNodes[0];
7617 if( iRepl[0]==1 && iRepl[1]==2 && iRepl[2]==5 ) {
7618 uniqueNodes[0] = curNodes[0];
7619 uniqueNodes[1] = curNodes[1];
7620 uniqueNodes[2] = curNodes[3];
7621 uniqueNodes[3] = curNodes[4];
7622 uniqueNodes[4] = curNodes[6];
7623 uniqueNodes[5] = curNodes[7];
7626 if( iRepl[0]==1 && iRepl[1]==4 && iRepl[2]==5 ) {
7627 uniqueNodes[0] = curNodes[0];
7628 uniqueNodes[1] = curNodes[2];
7629 uniqueNodes[2] = curNodes[3];
7630 uniqueNodes[3] = curNodes[1];
7631 uniqueNodes[4] = curNodes[6];
7632 uniqueNodes[5] = curNodes[7];
7635 if( iRepl[0]==2 && iRepl[1]==3 && iRepl[2]==6 ) {
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[7];
7644 if( iRepl[0]==2 && iRepl[1]==5 && iRepl[2]==6 ) {
7645 uniqueNodes[0] = curNodes[0];
7646 uniqueNodes[1] = curNodes[1];
7647 uniqueNodes[2] = curNodes[3];
7648 uniqueNodes[3] = curNodes[4];
7649 uniqueNodes[4] = curNodes[2];
7650 uniqueNodes[5] = curNodes[7];
7653 if( iRepl[0]==3 && iRepl[1]==6 && iRepl[2]==7 ) {
7654 uniqueNodes[0] = curNodes[0];
7655 uniqueNodes[1] = curNodes[1];
7656 uniqueNodes[2] = curNodes[2];
7657 uniqueNodes[3] = curNodes[4];
7658 uniqueNodes[4] = curNodes[5];
7659 uniqueNodes[5] = curNodes[3];
7664 MESSAGE("nbRepl=4: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3]);
7667 MESSAGE("nbRepl=5: " << iRepl[0] << " " << iRepl[1] << " " << iRepl[2] << " " << iRepl[3] << " " << iRepl[4]);
7671 //////////////////////////////////// HEXAHEDRON
7673 SMDS_VolumeTool hexa (elem);
7674 hexa.SetExternalNormal();
7675 if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
7676 //////////////////////// ---> tetrahedron
7677 for ( int iFace = 0; iFace < 6; iFace++ ) {
7678 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7679 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7680 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7681 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7682 // one face turns into a point ...
7683 int iOppFace = hexa.GetOppFaceIndex( iFace );
7684 ind = hexa.GetFaceNodesIndices( iOppFace );
7686 iUnique = 2; // reverse a tetrahedron bottom
7687 for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
7688 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7690 else if ( iUnique >= 0 )
7691 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7693 if ( nbStick == 1 ) {
7694 // ... and the opposite one - into a triangle.
7696 ind = hexa.GetFaceNodesIndices( iFace );
7697 uniqueNodes[ 3 ] = curNodes[ind[ 0 ]];
7704 else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
7705 //////////////////// HEXAHEDRON ---> 2 tetrahedrons
7706 for ( int iFace = 0; iFace < 6; iFace++ ) {
7707 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7708 if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
7709 curNodes[ind[ 0 ]] == curNodes[ind[ 2 ]] &&
7710 curNodes[ind[ 0 ]] == curNodes[ind[ 3 ]] ) {
7711 // one face turns into a point ...
7712 int iOppFace = hexa.GetOppFaceIndex( iFace );
7713 ind = hexa.GetFaceNodesIndices( iOppFace );
7715 iUnique = 2; // reverse a tetrahedron 1 bottom
7716 for ( iCur = 0; iCur < 4 && nbStick == 0; iCur++ ) {
7717 if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
7719 else if ( iUnique >= 0 )
7720 uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
7722 if ( nbStick == 0 ) {
7723 // ... and the opposite one is a quadrangle
7725 const int* indTop = hexa.GetFaceNodesIndices( iFace );
7726 uniqueNodes[ 3 ] = curNodes[indTop[ 0 ]];
7729 SMDS_MeshElement* newElem =
7730 aMesh->AddVolume(curNodes[ind[ 0 ]],
7733 curNodes[indTop[ 0 ]]);
7734 myLastCreatedElems.Append(newElem);
7736 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7743 else if ( nbUniqueNodes == 6 && nbRepl == 4 ) {
7744 ////////////////// HEXAHEDRON ---> 2 tetrahedrons or 1 prism
7745 // find indices of quad and tri faces
7746 int iQuadFace[ 6 ], iTriFace[ 6 ], nbQuad = 0, nbTri = 0, iFace;
7747 for ( iFace = 0; iFace < 6; iFace++ ) {
7748 const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
7750 for ( iCur = 0; iCur < 4; iCur++ )
7751 nodeSet.insert( curNodes[ind[ iCur ]] );
7752 nbUniqueNodes = nodeSet.size();
7753 if ( nbUniqueNodes == 3 )
7754 iTriFace[ nbTri++ ] = iFace;
7755 else if ( nbUniqueNodes == 4 )
7756 iQuadFace[ nbQuad++ ] = iFace;
7758 if (nbQuad == 2 && nbTri == 4 &&
7759 hexa.GetOppFaceIndex( iQuadFace[ 0 ] ) == iQuadFace[ 1 ]) {
7760 // 2 opposite quadrangles stuck with a diagonal;
7761 // sample groups of merged indices: (0-4)(2-6)
7762 // --------------------------------------------> 2 tetrahedrons
7763 const int *ind1 = hexa.GetFaceNodesIndices( iQuadFace[ 0 ]); // indices of quad1 nodes
7764 const int *ind2 = hexa.GetFaceNodesIndices( iQuadFace[ 1 ]);
7765 int i0, i1d, i2, i3d, i0t, i2t; // d-daigonal, t-top
7766 if (curNodes[ind1[ 0 ]] == curNodes[ind2[ 0 ]] &&
7767 curNodes[ind1[ 2 ]] == curNodes[ind2[ 2 ]]) {
7768 // stuck with 0-2 diagonal
7776 else if (curNodes[ind1[ 1 ]] == curNodes[ind2[ 3 ]] &&
7777 curNodes[ind1[ 3 ]] == curNodes[ind2[ 1 ]]) {
7778 // stuck with 1-3 diagonal
7790 uniqueNodes[ 0 ] = curNodes [ i0 ];
7791 uniqueNodes[ 1 ] = curNodes [ i1d ];
7792 uniqueNodes[ 2 ] = curNodes [ i3d ];
7793 uniqueNodes[ 3 ] = curNodes [ i0t ];
7796 SMDS_MeshElement* newElem = aMesh->AddVolume(curNodes[ i1d ],
7800 myLastCreatedElems.Append(newElem);
7802 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7805 else if (( nbTri == 2 && nbQuad == 3 ) || // merged (0-4)(1-5)
7806 ( nbTri == 4 && nbQuad == 2 )) { // merged (7-4)(1-5)
7807 // --------------------------------------------> prism
7808 // find 2 opposite triangles
7810 for ( iFace = 0; iFace + 1 < nbTri; iFace++ ) {
7811 if ( hexa.GetOppFaceIndex( iTriFace[ iFace ] ) == iTriFace[ iFace + 1 ]) {
7812 // find indices of kept and replaced nodes
7813 // and fill unique nodes of 2 opposite triangles
7814 const int *ind1 = hexa.GetFaceNodesIndices( iTriFace[ iFace ]);
7815 const int *ind2 = hexa.GetFaceNodesIndices( iTriFace[ iFace + 1 ]);
7816 const SMDS_MeshNode** hexanodes = hexa.GetNodes();
7817 // fill unique nodes
7820 for ( iCur = 0; iCur < 4 && isOk; iCur++ ) {
7821 const SMDS_MeshNode* n = curNodes[ind1[ iCur ]];
7822 const SMDS_MeshNode* nInit = hexanodes[ind1[ iCur ]];
7824 // iCur of a linked node of the opposite face (make normals co-directed):
7825 int iCurOpp = ( iCur == 1 || iCur == 3 ) ? 4 - iCur : iCur;
7826 // check that correspondent corners of triangles are linked
7827 if ( !hexa.IsLinked( ind1[ iCur ], ind2[ iCurOpp ] ))
7830 uniqueNodes[ iUnique ] = n;
7831 uniqueNodes[ iUnique + 3 ] = curNodes[ind2[ iCurOpp ]];
7840 } // if ( nbUniqueNodes == 6 && nbRepl == 4 )
7846 } // switch ( nbNodes )
7848 } // if ( nbNodes != nbUniqueNodes ) // some nodes stick
7851 if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
7852 // Change nodes of polyedre
7853 const SMDS_VtkVolume* aPolyedre =
7854 dynamic_cast<const SMDS_VtkVolume*>( elem );
7856 int nbFaces = aPolyedre->NbFaces();
7858 vector<const SMDS_MeshNode *> poly_nodes;
7859 vector<int> quantities (nbFaces);
7861 for (int iface = 1; iface <= nbFaces; iface++) {
7862 int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
7863 quantities[iface - 1] = nbFaceNodes;
7865 for (inode = 1; inode <= nbFaceNodes; inode++) {
7866 const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
7868 TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
7869 if (nnIt != nodeNodeMap.end()) { // curNode sticks
7870 curNode = (*nnIt).second;
7872 poly_nodes.push_back(curNode);
7875 aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
7879 //int elemId = elem->GetID();
7880 //MESSAGE("Change regular element or polygon " << elemId);
7881 SMDSAbs_ElementType etyp = elem->GetType();
7882 uniqueNodes.resize(nbUniqueNodes);
7883 SMDS_MeshElement* newElem = 0;
7884 if (elem->GetEntityType() == SMDSEntity_Polygon)
7885 newElem = this->AddElement(uniqueNodes, etyp, true);
7887 newElem = this->AddElement(uniqueNodes, etyp, false);
7890 myLastCreatedElems.Append(newElem);
7892 aMesh->SetMeshElementOnShape( newElem, aShapeId );
7894 aMesh->RemoveElement(elem);
7898 // Remove invalid regular element or invalid polygon
7899 //MESSAGE("Remove invalid " << elem->GetID());
7900 rmElemIds.push_back( elem->GetID() );
7903 } // loop on elements
7905 // Remove bad elements, then equal nodes (order important)
7907 Remove( rmElemIds, false );
7908 Remove( rmNodeIds, true );
7913 // ========================================================
7914 // class : SortableElement
7915 // purpose : allow sorting elements basing on their nodes
7916 // ========================================================
7917 class SortableElement : public set <const SMDS_MeshElement*>
7921 SortableElement( const SMDS_MeshElement* theElem )
7924 SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
7925 while ( nodeIt->more() )
7926 this->insert( nodeIt->next() );
7929 const SMDS_MeshElement* Get() const
7932 void Set(const SMDS_MeshElement* e) const
7937 mutable const SMDS_MeshElement* myElem;
7940 //=======================================================================
7941 //function : FindEqualElements
7942 //purpose : Return list of group of elements built on the same nodes.
7943 // Search among theElements or in the whole mesh if theElements is empty
7944 //=======================================================================
7945 void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
7946 TListOfListOfElementsID & theGroupsOfElementsID)
7948 myLastCreatedElems.Clear();
7949 myLastCreatedNodes.Clear();
7951 typedef set<const SMDS_MeshElement*> TElemsSet;
7952 typedef map< SortableElement, int > TMapOfNodeSet;
7953 typedef list<int> TGroupOfElems;
7956 if ( theElements.empty() )
7957 { // get all elements in the mesh
7958 SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
7959 while ( eIt->more() )
7960 elems.insert( elems.end(), eIt->next());
7963 elems = theElements;
7965 vector< TGroupOfElems > arrayOfGroups;
7966 TGroupOfElems groupOfElems;
7967 TMapOfNodeSet mapOfNodeSet;
7969 TElemsSet::iterator elemIt = elems.begin();
7970 for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
7971 const SMDS_MeshElement* curElem = *elemIt;
7972 SortableElement SE(curElem);
7975 pair< TMapOfNodeSet::iterator, bool> pp = mapOfNodeSet.insert(make_pair(SE, i));
7976 if( !(pp.second) ) {
7977 TMapOfNodeSet::iterator& itSE = pp.first;
7978 ind = (*itSE).second;
7979 arrayOfGroups[ind].push_back(curElem->GetID());
7982 groupOfElems.clear();
7983 groupOfElems.push_back(curElem->GetID());
7984 arrayOfGroups.push_back(groupOfElems);
7989 vector< TGroupOfElems >::iterator groupIt = arrayOfGroups.begin();
7990 for ( ; groupIt != arrayOfGroups.end(); ++groupIt ) {
7991 groupOfElems = *groupIt;
7992 if ( groupOfElems.size() > 1 ) {
7993 groupOfElems.sort();
7994 theGroupsOfElementsID.push_back(groupOfElems);
7999 //=======================================================================
8000 //function : MergeElements
8001 //purpose : In each given group, substitute all elements by the first one.
8002 //=======================================================================
8004 void SMESH_MeshEditor::MergeElements(TListOfListOfElementsID & theGroupsOfElementsID)
8006 myLastCreatedElems.Clear();
8007 myLastCreatedNodes.Clear();
8009 typedef list<int> TListOfIDs;
8010 TListOfIDs rmElemIds; // IDs of elems to remove
8012 SMESHDS_Mesh* aMesh = GetMeshDS();
8014 TListOfListOfElementsID::iterator groupsIt = theGroupsOfElementsID.begin();
8015 while ( groupsIt != theGroupsOfElementsID.end() ) {
8016 TListOfIDs& aGroupOfElemID = *groupsIt;
8017 aGroupOfElemID.sort();
8018 int elemIDToKeep = aGroupOfElemID.front();
8019 const SMDS_MeshElement* elemToKeep = aMesh->FindElement(elemIDToKeep);
8020 aGroupOfElemID.pop_front();
8021 TListOfIDs::iterator idIt = aGroupOfElemID.begin();
8022 while ( idIt != aGroupOfElemID.end() ) {
8023 int elemIDToRemove = *idIt;
8024 const SMDS_MeshElement* elemToRemove = aMesh->FindElement(elemIDToRemove);
8025 // add the kept element in groups of removed one (PAL15188)
8026 AddToSameGroups( elemToKeep, elemToRemove, aMesh );
8027 rmElemIds.push_back( elemIDToRemove );
8033 Remove( rmElemIds, false );
8036 //=======================================================================
8037 //function : MergeEqualElements
8038 //purpose : Remove all but one of elements built on the same nodes.
8039 //=======================================================================
8041 void SMESH_MeshEditor::MergeEqualElements()
8043 set<const SMDS_MeshElement*> aMeshElements; /* empty input -
8044 to merge equal elements in the whole mesh */
8045 TListOfListOfElementsID aGroupsOfElementsID;
8046 FindEqualElements(aMeshElements, aGroupsOfElementsID);
8047 MergeElements(aGroupsOfElementsID);
8050 //=======================================================================
8051 //function : FindFaceInSet
8052 //purpose : Return a face having linked nodes n1 and n2 and which is
8053 // - not in avoidSet,
8054 // - in elemSet provided that !elemSet.empty()
8055 // i1 and i2 optionally returns indices of n1 and n2
8056 //=======================================================================
8058 const SMDS_MeshElement*
8059 SMESH_MeshEditor::FindFaceInSet(const SMDS_MeshNode* n1,
8060 const SMDS_MeshNode* n2,
8061 const TIDSortedElemSet& elemSet,
8062 const TIDSortedElemSet& avoidSet,
8068 const SMDS_MeshElement* face = 0;
8070 SMDS_ElemIteratorPtr invElemIt = n1->GetInverseElementIterator(SMDSAbs_Face);
8071 //MESSAGE("n1->GetInverseElementIterator(SMDSAbs_Face) " << invElemIt);
8072 while ( invElemIt->more() && !face ) // loop on inverse faces of n1
8074 //MESSAGE("in while ( invElemIt->more() && !face )");
8075 const SMDS_MeshElement* elem = invElemIt->next();
8076 if (avoidSet.count( elem ))
8078 if ( !elemSet.empty() && !elemSet.count( elem ))
8081 i1 = elem->GetNodeIndex( n1 );
8082 // find a n2 linked to n1
8083 int nbN = elem->IsQuadratic() ? elem->NbNodes()/2 : elem->NbNodes();
8084 for ( int di = -1; di < 2 && !face; di += 2 )
8086 i2 = (i1+di+nbN) % nbN;
8087 if ( elem->GetNode( i2 ) == n2 )
8090 if ( !face && elem->IsQuadratic())
8092 // analysis for quadratic elements using all nodes
8093 const SMDS_VtkFace* F =
8094 dynamic_cast<const SMDS_VtkFace*>(elem);
8095 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8096 // use special nodes iterator
8097 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8098 const SMDS_MeshNode* prevN = cast2Node( anIter->next() );
8099 for ( i1 = -1, i2 = 0; anIter->more() && !face; i1++, i2++ )
8101 const SMDS_MeshNode* n = cast2Node( anIter->next() );
8102 if ( n1 == prevN && n2 == n )
8106 else if ( n2 == prevN && n1 == n )
8108 face = elem; swap( i1, i2 );
8114 if ( n1ind ) *n1ind = i1;
8115 if ( n2ind ) *n2ind = i2;
8119 //=======================================================================
8120 //function : findAdjacentFace
8122 //=======================================================================
8124 static const SMDS_MeshElement* findAdjacentFace(const SMDS_MeshNode* n1,
8125 const SMDS_MeshNode* n2,
8126 const SMDS_MeshElement* elem)
8128 TIDSortedElemSet elemSet, avoidSet;
8130 avoidSet.insert ( elem );
8131 return SMESH_MeshEditor::FindFaceInSet( n1, n2, elemSet, avoidSet );
8134 //=======================================================================
8135 //function : FindFreeBorder
8137 //=======================================================================
8139 #define ControlFreeBorder SMESH::Controls::FreeEdges::IsFreeEdge
8141 bool SMESH_MeshEditor::FindFreeBorder (const SMDS_MeshNode* theFirstNode,
8142 const SMDS_MeshNode* theSecondNode,
8143 const SMDS_MeshNode* theLastNode,
8144 list< const SMDS_MeshNode* > & theNodes,
8145 list< const SMDS_MeshElement* >& theFaces)
8147 if ( !theFirstNode || !theSecondNode )
8149 // find border face between theFirstNode and theSecondNode
8150 const SMDS_MeshElement* curElem = findAdjacentFace( theFirstNode, theSecondNode, 0 );
8154 theFaces.push_back( curElem );
8155 theNodes.push_back( theFirstNode );
8156 theNodes.push_back( theSecondNode );
8158 //vector<const SMDS_MeshNode*> nodes;
8159 const SMDS_MeshNode *nIgnore = theFirstNode, *nStart = theSecondNode;
8160 TIDSortedElemSet foundElems;
8161 bool needTheLast = ( theLastNode != 0 );
8163 while ( nStart != theLastNode ) {
8164 if ( nStart == theFirstNode )
8165 return !needTheLast;
8167 // find all free border faces sharing form nStart
8169 list< const SMDS_MeshElement* > curElemList;
8170 list< const SMDS_MeshNode* > nStartList;
8171 SMDS_ElemIteratorPtr invElemIt = nStart->GetInverseElementIterator(SMDSAbs_Face);
8172 while ( invElemIt->more() ) {
8173 const SMDS_MeshElement* e = invElemIt->next();
8174 if ( e == curElem || foundElems.insert( e ).second ) {
8176 int iNode = 0, nbNodes = e->NbNodes();
8177 //const SMDS_MeshNode* nodes[nbNodes+1];
8178 vector<const SMDS_MeshNode*> nodes(nbNodes+1);
8180 if(e->IsQuadratic()) {
8181 const SMDS_VtkFace* F =
8182 dynamic_cast<const SMDS_VtkFace*>(e);
8183 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8184 // use special nodes iterator
8185 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8186 while( anIter->more() ) {
8187 nodes[ iNode++ ] = cast2Node(anIter->next());
8191 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
8192 while ( nIt->more() )
8193 nodes[ iNode++ ] = static_cast<const SMDS_MeshNode*>( nIt->next() );
8195 nodes[ iNode ] = nodes[ 0 ];
8197 for ( iNode = 0; iNode < nbNodes; iNode++ )
8198 if (((nodes[ iNode ] == nStart && nodes[ iNode + 1] != nIgnore ) ||
8199 (nodes[ iNode + 1] == nStart && nodes[ iNode ] != nIgnore )) &&
8200 ControlFreeBorder( &nodes[ iNode ], e->GetID() ))
8202 nStartList.push_back( nodes[ iNode + ( nodes[ iNode ] == nStart ? 1 : 0 )]);
8203 curElemList.push_back( e );
8207 // analyse the found
8209 int nbNewBorders = curElemList.size();
8210 if ( nbNewBorders == 0 ) {
8211 // no free border furthermore
8212 return !needTheLast;
8214 else if ( nbNewBorders == 1 ) {
8215 // one more element found
8217 nStart = nStartList.front();
8218 curElem = curElemList.front();
8219 theFaces.push_back( curElem );
8220 theNodes.push_back( nStart );
8223 // several continuations found
8224 list< const SMDS_MeshElement* >::iterator curElemIt;
8225 list< const SMDS_MeshNode* >::iterator nStartIt;
8226 // check if one of them reached the last node
8227 if ( needTheLast ) {
8228 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8229 curElemIt!= curElemList.end();
8230 curElemIt++, nStartIt++ )
8231 if ( *nStartIt == theLastNode ) {
8232 theFaces.push_back( *curElemIt );
8233 theNodes.push_back( *nStartIt );
8237 // find the best free border by the continuations
8238 list<const SMDS_MeshNode*> contNodes[ 2 ], *cNL;
8239 list<const SMDS_MeshElement*> contFaces[ 2 ], *cFL;
8240 for (curElemIt = curElemList.begin(), nStartIt = nStartList.begin();
8241 curElemIt!= curElemList.end();
8242 curElemIt++, nStartIt++ )
8244 cNL = & contNodes[ contNodes[0].empty() ? 0 : 1 ];
8245 cFL = & contFaces[ contFaces[0].empty() ? 0 : 1 ];
8246 // find one more free border
8247 if ( ! FindFreeBorder( nStart, *nStartIt, theLastNode, *cNL, *cFL )) {
8251 else if ( !contNodes[0].empty() && !contNodes[1].empty() ) {
8252 // choice: clear a worse one
8253 int iLongest = ( contNodes[0].size() < contNodes[1].size() ? 1 : 0 );
8254 int iWorse = ( needTheLast ? 1 - iLongest : iLongest );
8255 contNodes[ iWorse ].clear();
8256 contFaces[ iWorse ].clear();
8259 if ( contNodes[0].empty() && contNodes[1].empty() )
8262 // append the best free border
8263 cNL = & contNodes[ contNodes[0].empty() ? 1 : 0 ];
8264 cFL = & contFaces[ contFaces[0].empty() ? 1 : 0 ];
8265 theNodes.pop_back(); // remove nIgnore
8266 theNodes.pop_back(); // remove nStart
8267 theFaces.pop_back(); // remove curElem
8268 list< const SMDS_MeshNode* >::iterator nIt = cNL->begin();
8269 list< const SMDS_MeshElement* >::iterator fIt = cFL->begin();
8270 for ( ; nIt != cNL->end(); nIt++ ) theNodes.push_back( *nIt );
8271 for ( ; fIt != cFL->end(); fIt++ ) theFaces.push_back( *fIt );
8274 } // several continuations found
8275 } // while ( nStart != theLastNode )
8280 //=======================================================================
8281 //function : CheckFreeBorderNodes
8282 //purpose : Return true if the tree nodes are on a free border
8283 //=======================================================================
8285 bool SMESH_MeshEditor::CheckFreeBorderNodes(const SMDS_MeshNode* theNode1,
8286 const SMDS_MeshNode* theNode2,
8287 const SMDS_MeshNode* theNode3)
8289 list< const SMDS_MeshNode* > nodes;
8290 list< const SMDS_MeshElement* > faces;
8291 return FindFreeBorder( theNode1, theNode2, theNode3, nodes, faces);
8294 //=======================================================================
8295 //function : SewFreeBorder
8297 //=======================================================================
8299 SMESH_MeshEditor::Sew_Error
8300 SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
8301 const SMDS_MeshNode* theBordSecondNode,
8302 const SMDS_MeshNode* theBordLastNode,
8303 const SMDS_MeshNode* theSideFirstNode,
8304 const SMDS_MeshNode* theSideSecondNode,
8305 const SMDS_MeshNode* theSideThirdNode,
8306 const bool theSideIsFreeBorder,
8307 const bool toCreatePolygons,
8308 const bool toCreatePolyedrs)
8310 myLastCreatedElems.Clear();
8311 myLastCreatedNodes.Clear();
8313 MESSAGE("::SewFreeBorder()");
8314 Sew_Error aResult = SEW_OK;
8316 // ====================================
8317 // find side nodes and elements
8318 // ====================================
8320 list< const SMDS_MeshNode* > nSide[ 2 ];
8321 list< const SMDS_MeshElement* > eSide[ 2 ];
8322 list< const SMDS_MeshNode* >::iterator nIt[ 2 ];
8323 list< const SMDS_MeshElement* >::iterator eIt[ 2 ];
8327 if (!FindFreeBorder(theBordFirstNode,theBordSecondNode,theBordLastNode,
8328 nSide[0], eSide[0])) {
8329 MESSAGE(" Free Border 1 not found " );
8330 aResult = SEW_BORDER1_NOT_FOUND;
8332 if (theSideIsFreeBorder) {
8335 if (!FindFreeBorder(theSideFirstNode, theSideSecondNode, theSideThirdNode,
8336 nSide[1], eSide[1])) {
8337 MESSAGE(" Free Border 2 not found " );
8338 aResult = ( aResult != SEW_OK ? SEW_BOTH_BORDERS_NOT_FOUND : SEW_BORDER2_NOT_FOUND );
8341 if ( aResult != SEW_OK )
8344 if (!theSideIsFreeBorder) {
8348 // -------------------------------------------------------------------------
8350 // 1. If nodes to merge are not coincident, move nodes of the free border
8351 // from the coord sys defined by the direction from the first to last
8352 // nodes of the border to the correspondent sys of the side 2
8353 // 2. On the side 2, find the links most co-directed with the correspondent
8354 // links of the free border
8355 // -------------------------------------------------------------------------
8357 // 1. Since sewing may break if there are volumes to split on the side 2,
8358 // we wont move nodes but just compute new coordinates for them
8359 typedef map<const SMDS_MeshNode*, gp_XYZ> TNodeXYZMap;
8360 TNodeXYZMap nBordXYZ;
8361 list< const SMDS_MeshNode* >& bordNodes = nSide[ 0 ];
8362 list< const SMDS_MeshNode* >::iterator nBordIt;
8364 gp_XYZ Pb1( theBordFirstNode->X(), theBordFirstNode->Y(), theBordFirstNode->Z() );
8365 gp_XYZ Pb2( theBordLastNode->X(), theBordLastNode->Y(), theBordLastNode->Z() );
8366 gp_XYZ Ps1( theSideFirstNode->X(), theSideFirstNode->Y(), theSideFirstNode->Z() );
8367 gp_XYZ Ps2( theSideSecondNode->X(), theSideSecondNode->Y(), theSideSecondNode->Z() );
8368 double tol2 = 1.e-8;
8369 gp_Vec Vbs1( Pb1 - Ps1 ),Vbs2( Pb2 - Ps2 );
8370 if ( Vbs1.SquareMagnitude() > tol2 || Vbs2.SquareMagnitude() > tol2 ) {
8371 // Need node movement.
8373 // find X and Z axes to create trsf
8374 gp_Vec Zb( Pb1 - Pb2 ), Zs( Ps1 - Ps2 );
8376 if ( X.SquareMagnitude() <= gp::Resolution() * gp::Resolution() )
8378 X = gp_Ax2( gp::Origin(), Zb ).XDirection();
8381 gp_Ax3 toBordAx( Pb1, Zb, X );
8382 gp_Ax3 fromSideAx( Ps1, Zs, X );
8383 gp_Ax3 toGlobalAx( gp::Origin(), gp::DZ(), gp::DX() );
8385 gp_Trsf toBordSys, fromSide2Sys;
8386 toBordSys.SetTransformation( toBordAx );
8387 fromSide2Sys.SetTransformation( fromSideAx, toGlobalAx );
8388 fromSide2Sys.SetScaleFactor( Zs.Magnitude() / Zb.Magnitude() );
8391 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8392 const SMDS_MeshNode* n = *nBordIt;
8393 gp_XYZ xyz( n->X(),n->Y(),n->Z() );
8394 toBordSys.Transforms( xyz );
8395 fromSide2Sys.Transforms( xyz );
8396 nBordXYZ.insert( TNodeXYZMap::value_type( n, xyz ));
8400 // just insert nodes XYZ in the nBordXYZ map
8401 for ( nBordIt = bordNodes.begin(); nBordIt != bordNodes.end(); nBordIt++ ) {
8402 const SMDS_MeshNode* n = *nBordIt;
8403 nBordXYZ.insert( TNodeXYZMap::value_type( n, gp_XYZ( n->X(),n->Y(),n->Z() )));
8407 // 2. On the side 2, find the links most co-directed with the correspondent
8408 // links of the free border
8410 list< const SMDS_MeshElement* >& sideElems = eSide[ 1 ];
8411 list< const SMDS_MeshNode* >& sideNodes = nSide[ 1 ];
8412 sideNodes.push_back( theSideFirstNode );
8414 bool hasVolumes = false;
8415 LinkID_Gen aLinkID_Gen( GetMeshDS() );
8416 set<long> foundSideLinkIDs, checkedLinkIDs;
8417 SMDS_VolumeTool volume;
8418 //const SMDS_MeshNode* faceNodes[ 4 ];
8420 const SMDS_MeshNode* sideNode;
8421 const SMDS_MeshElement* sideElem;
8422 const SMDS_MeshNode* prevSideNode = theSideFirstNode;
8423 const SMDS_MeshNode* prevBordNode = theBordFirstNode;
8424 nBordIt = bordNodes.begin();
8426 // border node position and border link direction to compare with
8427 gp_XYZ bordPos = nBordXYZ[ *nBordIt ];
8428 gp_XYZ bordDir = bordPos - nBordXYZ[ prevBordNode ];
8429 // choose next side node by link direction or by closeness to
8430 // the current border node:
8431 bool searchByDir = ( *nBordIt != theBordLastNode );
8433 // find the next node on the Side 2
8435 double maxDot = -DBL_MAX, minDist = DBL_MAX;
8437 checkedLinkIDs.clear();
8438 gp_XYZ prevXYZ( prevSideNode->X(), prevSideNode->Y(), prevSideNode->Z() );
8440 // loop on inverse elements of current node (prevSideNode) on the Side 2
8441 SMDS_ElemIteratorPtr invElemIt = prevSideNode->GetInverseElementIterator();
8442 while ( invElemIt->more() )
8444 const SMDS_MeshElement* elem = invElemIt->next();
8445 // prepare data for a loop on links coming to prevSideNode, of a face or a volume
8446 int iPrevNode, iNode = 0, nbNodes = elem->NbNodes();
8447 vector< const SMDS_MeshNode* > faceNodes( nbNodes, (const SMDS_MeshNode*)0 );
8448 bool isVolume = volume.Set( elem );
8449 const SMDS_MeshNode** nodes = isVolume ? volume.GetNodes() : & faceNodes[0];
8450 if ( isVolume ) // --volume
8452 else if ( elem->GetType()==SMDSAbs_Face ) { // --face
8453 // retrieve all face nodes and find iPrevNode - an index of the prevSideNode
8454 if(elem->IsQuadratic()) {
8455 const SMDS_VtkFace* F =
8456 dynamic_cast<const SMDS_VtkFace*>(elem);
8457 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8458 // use special nodes iterator
8459 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8460 while( anIter->more() ) {
8461 nodes[ iNode ] = cast2Node(anIter->next());
8462 if ( nodes[ iNode++ ] == prevSideNode )
8463 iPrevNode = iNode - 1;
8467 SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
8468 while ( nIt->more() ) {
8469 nodes[ iNode ] = cast2Node( nIt->next() );
8470 if ( nodes[ iNode++ ] == prevSideNode )
8471 iPrevNode = iNode - 1;
8474 // there are 2 links to check
8479 // loop on links, to be precise, on the second node of links
8480 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
8481 const SMDS_MeshNode* n = nodes[ iNode ];
8483 if ( !volume.IsLinked( n, prevSideNode ))
8487 if ( iNode ) // a node before prevSideNode
8488 n = nodes[ iPrevNode == 0 ? elem->NbNodes() - 1 : iPrevNode - 1 ];
8489 else // a node after prevSideNode
8490 n = nodes[ iPrevNode + 1 == elem->NbNodes() ? 0 : iPrevNode + 1 ];
8492 // check if this link was already used
8493 long iLink = aLinkID_Gen.GetLinkID( prevSideNode, n );
8494 bool isJustChecked = !checkedLinkIDs.insert( iLink ).second;
8495 if (!isJustChecked &&
8496 foundSideLinkIDs.find( iLink ) == foundSideLinkIDs.end() )
8498 // test a link geometrically
8499 gp_XYZ nextXYZ ( n->X(), n->Y(), n->Z() );
8500 bool linkIsBetter = false;
8501 double dot = 0.0, dist = 0.0;
8502 if ( searchByDir ) { // choose most co-directed link
8503 dot = bordDir * ( nextXYZ - prevXYZ ).Normalized();
8504 linkIsBetter = ( dot > maxDot );
8506 else { // choose link with the node closest to bordPos
8507 dist = ( nextXYZ - bordPos ).SquareModulus();
8508 linkIsBetter = ( dist < minDist );
8510 if ( linkIsBetter ) {
8519 } // loop on inverse elements of prevSideNode
8522 MESSAGE(" Cant find path by links of the Side 2 ");
8523 return SEW_BAD_SIDE_NODES;
8525 sideNodes.push_back( sideNode );
8526 sideElems.push_back( sideElem );
8527 foundSideLinkIDs.insert ( linkID );
8528 prevSideNode = sideNode;
8530 if ( *nBordIt == theBordLastNode )
8531 searchByDir = false;
8533 // find the next border link to compare with
8534 gp_XYZ sidePos( sideNode->X(), sideNode->Y(), sideNode->Z() );
8535 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8536 // move to next border node if sideNode is before forward border node (bordPos)
8537 while ( *nBordIt != theBordLastNode && !searchByDir ) {
8538 prevBordNode = *nBordIt;
8540 bordPos = nBordXYZ[ *nBordIt ];
8541 bordDir = bordPos - nBordXYZ[ prevBordNode ];
8542 searchByDir = ( bordDir * ( sidePos - bordPos ) <= 0 );
8546 while ( sideNode != theSideSecondNode );
8548 if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
8549 MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
8550 return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
8552 } // end nodes search on the side 2
8554 // ============================
8555 // sew the border to the side 2
8556 // ============================
8558 int nbNodes[] = { nSide[0].size(), nSide[1].size() };
8559 int maxNbNodes = Max( nbNodes[0], nbNodes[1] );
8561 TListOfListOfNodes nodeGroupsToMerge;
8562 if ( nbNodes[0] == nbNodes[1] ||
8563 ( theSideIsFreeBorder && !theSideThirdNode)) {
8565 // all nodes are to be merged
8567 for (nIt[0] = nSide[0].begin(), nIt[1] = nSide[1].begin();
8568 nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end();
8569 nIt[0]++, nIt[1]++ )
8571 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8572 nodeGroupsToMerge.back().push_back( *nIt[1] ); // to keep
8573 nodeGroupsToMerge.back().push_back( *nIt[0] ); // to remove
8578 // insert new nodes into the border and the side to get equal nb of segments
8580 // get normalized parameters of nodes on the borders
8581 //double param[ 2 ][ maxNbNodes ];
8583 param[0] = new double [ maxNbNodes ];
8584 param[1] = new double [ maxNbNodes ];
8586 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8587 list< const SMDS_MeshNode* >& nodes = nSide[ iBord ];
8588 list< const SMDS_MeshNode* >::iterator nIt = nodes.begin();
8589 const SMDS_MeshNode* nPrev = *nIt;
8590 double bordLength = 0;
8591 for ( iNode = 0; nIt != nodes.end(); nIt++, iNode++ ) { // loop on border nodes
8592 const SMDS_MeshNode* nCur = *nIt;
8593 gp_XYZ segment (nCur->X() - nPrev->X(),
8594 nCur->Y() - nPrev->Y(),
8595 nCur->Z() - nPrev->Z());
8596 double segmentLen = segment.Modulus();
8597 bordLength += segmentLen;
8598 param[ iBord ][ iNode ] = bordLength;
8601 // normalize within [0,1]
8602 for ( iNode = 0; iNode < nbNodes[ iBord ]; iNode++ ) {
8603 param[ iBord ][ iNode ] /= bordLength;
8607 // loop on border segments
8608 const SMDS_MeshNode *nPrev[ 2 ] = { 0, 0 };
8609 int i[ 2 ] = { 0, 0 };
8610 nIt[0] = nSide[0].begin(); eIt[0] = eSide[0].begin();
8611 nIt[1] = nSide[1].begin(); eIt[1] = eSide[1].begin();
8613 TElemOfNodeListMap insertMap;
8614 TElemOfNodeListMap::iterator insertMapIt;
8616 // key: elem to insert nodes into
8617 // value: 2 nodes to insert between + nodes to be inserted
8619 bool next[ 2 ] = { false, false };
8621 // find min adjacent segment length after sewing
8622 double nextParam = 10., prevParam = 0;
8623 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8624 if ( i[ iBord ] + 1 < nbNodes[ iBord ])
8625 nextParam = Min( nextParam, param[iBord][ i[iBord] + 1 ]);
8626 if ( i[ iBord ] > 0 )
8627 prevParam = Max( prevParam, param[iBord][ i[iBord] - 1 ]);
8629 double minParam = Min( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8630 double maxParam = Max( param[ 0 ][ i[0] ], param[ 1 ][ i[1] ]);
8631 double minSegLen = Min( nextParam - minParam, maxParam - prevParam );
8633 // choose to insert or to merge nodes
8634 double du = param[ 1 ][ i[1] ] - param[ 0 ][ i[0] ];
8635 if ( Abs( du ) <= minSegLen * 0.2 ) {
8638 nodeGroupsToMerge.push_back( list<const SMDS_MeshNode*>() );
8639 const SMDS_MeshNode* n0 = *nIt[0];
8640 const SMDS_MeshNode* n1 = *nIt[1];
8641 nodeGroupsToMerge.back().push_back( n1 );
8642 nodeGroupsToMerge.back().push_back( n0 );
8643 // position of node of the border changes due to merge
8644 param[ 0 ][ i[0] ] += du;
8645 // move n1 for the sake of elem shape evaluation during insertion.
8646 // n1 will be removed by MergeNodes() anyway
8647 const_cast<SMDS_MeshNode*>( n0 )->setXYZ( n1->X(), n1->Y(), n1->Z() );
8648 next[0] = next[1] = true;
8653 int intoBord = ( du < 0 ) ? 0 : 1;
8654 const SMDS_MeshElement* elem = *eIt[ intoBord ];
8655 const SMDS_MeshNode* n1 = nPrev[ intoBord ];
8656 const SMDS_MeshNode* n2 = *nIt[ intoBord ];
8657 const SMDS_MeshNode* nIns = *nIt[ 1 - intoBord ];
8658 if ( intoBord == 1 ) {
8659 // move node of the border to be on a link of elem of the side
8660 gp_XYZ p1 (n1->X(), n1->Y(), n1->Z());
8661 gp_XYZ p2 (n2->X(), n2->Y(), n2->Z());
8662 double ratio = du / ( param[ 1 ][ i[1] ] - param[ 1 ][ i[1]-1 ]);
8663 gp_XYZ p = p2 * ( 1 - ratio ) + p1 * ratio;
8664 GetMeshDS()->MoveNode( nIns, p.X(), p.Y(), p.Z() );
8666 insertMapIt = insertMap.find( elem );
8667 bool notFound = ( insertMapIt == insertMap.end() );
8668 bool otherLink = ( !notFound && (*insertMapIt).second.front() != n1 );
8670 // insert into another link of the same element:
8671 // 1. perform insertion into the other link of the elem
8672 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8673 const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
8674 const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
8675 InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
8676 // 2. perform insertion into the link of adjacent faces
8678 const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
8680 InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
8684 if (toCreatePolyedrs) {
8685 // perform insertion into the links of adjacent volumes
8686 UpdateVolumes(n12, n22, nodeList);
8688 // 3. find an element appeared on n1 and n2 after the insertion
8689 insertMap.erase( elem );
8690 elem = findAdjacentFace( n1, n2, 0 );
8692 if ( notFound || otherLink ) {
8693 // add element and nodes of the side into the insertMap
8694 insertMapIt = insertMap.insert
8695 ( TElemOfNodeListMap::value_type( elem, list<const SMDS_MeshNode*>() )).first;
8696 (*insertMapIt).second.push_back( n1 );
8697 (*insertMapIt).second.push_back( n2 );
8699 // add node to be inserted into elem
8700 (*insertMapIt).second.push_back( nIns );
8701 next[ 1 - intoBord ] = true;
8704 // go to the next segment
8705 for ( iBord = 0; iBord < 2; iBord++ ) { // loop on 2 borders
8706 if ( next[ iBord ] ) {
8707 if ( i[ iBord ] != 0 && eIt[ iBord ] != eSide[ iBord ].end())
8709 nPrev[ iBord ] = *nIt[ iBord ];
8710 nIt[ iBord ]++; i[ iBord ]++;
8714 while ( nIt[0] != nSide[0].end() && nIt[1] != nSide[1].end());
8716 // perform insertion of nodes into elements
8718 for (insertMapIt = insertMap.begin();
8719 insertMapIt != insertMap.end();
8722 const SMDS_MeshElement* elem = (*insertMapIt).first;
8723 list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
8724 const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
8725 const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
8727 InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
8729 if ( !theSideIsFreeBorder ) {
8730 // look for and insert nodes into the faces adjacent to elem
8732 const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
8734 InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
8739 if (toCreatePolyedrs) {
8740 // perform insertion into the links of adjacent volumes
8741 UpdateVolumes(n1, n2, nodeList);
8747 } // end: insert new nodes
8749 MergeNodes ( nodeGroupsToMerge );
8754 //=======================================================================
8755 //function : InsertNodesIntoLink
8756 //purpose : insert theNodesToInsert into theFace between theBetweenNode1
8757 // and theBetweenNode2 and split theElement
8758 //=======================================================================
8760 void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
8761 const SMDS_MeshNode* theBetweenNode1,
8762 const SMDS_MeshNode* theBetweenNode2,
8763 list<const SMDS_MeshNode*>& theNodesToInsert,
8764 const bool toCreatePoly)
8766 if ( theFace->GetType() != SMDSAbs_Face ) return;
8768 // find indices of 2 link nodes and of the rest nodes
8769 int iNode = 0, il1, il2, i3, i4;
8770 il1 = il2 = i3 = i4 = -1;
8771 //const SMDS_MeshNode* nodes[ theFace->NbNodes() ];
8772 vector<const SMDS_MeshNode*> nodes( theFace->NbNodes() );
8774 if(theFace->IsQuadratic()) {
8775 const SMDS_VtkFace* F =
8776 dynamic_cast<const SMDS_VtkFace*>(theFace);
8777 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8778 // use special nodes iterator
8779 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8780 while( anIter->more() ) {
8781 const SMDS_MeshNode* n = cast2Node(anIter->next());
8782 if ( n == theBetweenNode1 )
8784 else if ( n == theBetweenNode2 )
8790 nodes[ iNode++ ] = n;
8794 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8795 while ( nodeIt->more() ) {
8796 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8797 if ( n == theBetweenNode1 )
8799 else if ( n == theBetweenNode2 )
8805 nodes[ iNode++ ] = n;
8808 if ( il1 < 0 || il2 < 0 || i3 < 0 )
8811 // arrange link nodes to go one after another regarding the face orientation
8812 bool reverse = ( Abs( il2 - il1 ) == 1 ? il2 < il1 : il1 < il2 );
8813 list<const SMDS_MeshNode *> aNodesToInsert = theNodesToInsert;
8818 aNodesToInsert.reverse();
8820 // check that not link nodes of a quadrangles are in good order
8821 int nbFaceNodes = theFace->NbNodes();
8822 if ( nbFaceNodes == 4 && i4 - i3 != 1 ) {
8828 if (toCreatePoly || theFace->IsPoly()) {
8831 vector<const SMDS_MeshNode *> poly_nodes (nbFaceNodes + aNodesToInsert.size());
8833 // add nodes of face up to first node of link
8836 if(theFace->IsQuadratic()) {
8837 const SMDS_VtkFace* F =
8838 dynamic_cast<const SMDS_VtkFace*>(theFace);
8839 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
8840 // use special nodes iterator
8841 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
8842 while( anIter->more() && !isFLN ) {
8843 const SMDS_MeshNode* n = cast2Node(anIter->next());
8844 poly_nodes[iNode++] = n;
8845 if (n == nodes[il1]) {
8849 // add nodes to insert
8850 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8851 for (; nIt != aNodesToInsert.end(); nIt++) {
8852 poly_nodes[iNode++] = *nIt;
8854 // add nodes of face starting from last node of link
8855 while ( anIter->more() ) {
8856 poly_nodes[iNode++] = cast2Node(anIter->next());
8860 SMDS_ElemIteratorPtr nodeIt = theFace->nodesIterator();
8861 while ( nodeIt->more() && !isFLN ) {
8862 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8863 poly_nodes[iNode++] = n;
8864 if (n == nodes[il1]) {
8868 // add nodes to insert
8869 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8870 for (; nIt != aNodesToInsert.end(); nIt++) {
8871 poly_nodes[iNode++] = *nIt;
8873 // add nodes of face starting from last node of link
8874 while ( nodeIt->more() ) {
8875 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
8876 poly_nodes[iNode++] = n;
8880 // edit or replace the face
8881 SMESHDS_Mesh *aMesh = GetMeshDS();
8883 if (theFace->IsPoly()) {
8884 aMesh->ChangePolygonNodes(theFace, poly_nodes);
8887 int aShapeId = FindShape( theFace );
8889 SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
8890 myLastCreatedElems.Append(newElem);
8891 if ( aShapeId && newElem )
8892 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8894 aMesh->RemoveElement(theFace);
8899 SMESHDS_Mesh *aMesh = GetMeshDS();
8900 if( !theFace->IsQuadratic() ) {
8902 // put aNodesToInsert between theBetweenNode1 and theBetweenNode2
8903 int nbLinkNodes = 2 + aNodesToInsert.size();
8904 //const SMDS_MeshNode* linkNodes[ nbLinkNodes ];
8905 vector<const SMDS_MeshNode*> linkNodes( nbLinkNodes );
8906 linkNodes[ 0 ] = nodes[ il1 ];
8907 linkNodes[ nbLinkNodes - 1 ] = nodes[ il2 ];
8908 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
8909 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
8910 linkNodes[ iNode++ ] = *nIt;
8912 // decide how to split a quadrangle: compare possible variants
8913 // and choose which of splits to be a quadrangle
8914 int i1, i2, iSplit, nbSplits = nbLinkNodes - 1, iBestQuad;
8915 if ( nbFaceNodes == 3 ) {
8916 iBestQuad = nbSplits;
8919 else if ( nbFaceNodes == 4 ) {
8920 SMESH::Controls::NumericalFunctorPtr aCrit( new SMESH::Controls::AspectRatio);
8921 double aBestRate = DBL_MAX;
8922 for ( int iQuad = 0; iQuad < nbSplits; iQuad++ ) {
8924 double aBadRate = 0;
8925 // evaluate elements quality
8926 for ( iSplit = 0; iSplit < nbSplits; iSplit++ ) {
8927 if ( iSplit == iQuad ) {
8928 SMDS_FaceOfNodes quad (linkNodes[ i1++ ],
8932 aBadRate += getBadRate( &quad, aCrit );
8935 SMDS_FaceOfNodes tria (linkNodes[ i1++ ],
8937 nodes[ iSplit < iQuad ? i4 : i3 ]);
8938 aBadRate += getBadRate( &tria, aCrit );
8942 if ( aBadRate < aBestRate ) {
8944 aBestRate = aBadRate;
8949 // create new elements
8950 int aShapeId = FindShape( theFace );
8953 for ( iSplit = 0; iSplit < nbSplits - 1; iSplit++ ) {
8954 SMDS_MeshElement* newElem = 0;
8955 if ( iSplit == iBestQuad )
8956 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8961 newElem = aMesh->AddFace (linkNodes[ i1++ ],
8963 nodes[ iSplit < iBestQuad ? i4 : i3 ]);
8964 myLastCreatedElems.Append(newElem);
8965 if ( aShapeId && newElem )
8966 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8969 // change nodes of theFace
8970 const SMDS_MeshNode* newNodes[ 4 ];
8971 newNodes[ 0 ] = linkNodes[ i1 ];
8972 newNodes[ 1 ] = linkNodes[ i2 ];
8973 newNodes[ 2 ] = nodes[ iSplit >= iBestQuad ? i3 : i4 ];
8974 newNodes[ 3 ] = nodes[ i4 ];
8975 //aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
8976 const SMDS_MeshElement* newElem = 0;
8977 if (iSplit == iBestQuad)
8978 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2], newNodes[3] );
8980 newElem = aMesh->AddFace( newNodes[0], newNodes[1], newNodes[2] );
8981 myLastCreatedElems.Append(newElem);
8982 if ( aShapeId && newElem )
8983 aMesh->SetMeshElementOnShape( newElem, aShapeId );
8984 } // end if(!theFace->IsQuadratic())
8985 else { // theFace is quadratic
8986 // we have to split theFace on simple triangles and one simple quadrangle
8988 int nbshift = tmp*2;
8989 // shift nodes in nodes[] by nbshift
8991 for(i=0; i<nbshift; i++) {
8992 const SMDS_MeshNode* n = nodes[0];
8993 for(j=0; j<nbFaceNodes-1; j++) {
8994 nodes[j] = nodes[j+1];
8996 nodes[nbFaceNodes-1] = n;
8998 il1 = il1 - nbshift;
8999 // now have to insert nodes between n0 and n1 or n1 and n2 (see below)
9000 // n0 n1 n2 n0 n1 n2
9001 // +-----+-----+ +-----+-----+
9010 // create new elements
9011 int aShapeId = FindShape( theFace );
9014 if(nbFaceNodes==6) { // quadratic triangle
9015 SMDS_MeshElement* newElem =
9016 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9017 myLastCreatedElems.Append(newElem);
9018 if ( aShapeId && newElem )
9019 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9020 if(theFace->IsMediumNode(nodes[il1])) {
9021 // create quadrangle
9022 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[5]);
9023 myLastCreatedElems.Append(newElem);
9024 if ( aShapeId && newElem )
9025 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9031 // create quadrangle
9032 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[5]);
9033 myLastCreatedElems.Append(newElem);
9034 if ( aShapeId && newElem )
9035 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9041 else { // nbFaceNodes==8 - quadratic quadrangle
9042 SMDS_MeshElement* newElem =
9043 aMesh->AddFace(nodes[3],nodes[4],nodes[5]);
9044 myLastCreatedElems.Append(newElem);
9045 if ( aShapeId && newElem )
9046 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9047 newElem = aMesh->AddFace(nodes[5],nodes[6],nodes[7]);
9048 myLastCreatedElems.Append(newElem);
9049 if ( aShapeId && newElem )
9050 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9051 newElem = aMesh->AddFace(nodes[5],nodes[7],nodes[3]);
9052 myLastCreatedElems.Append(newElem);
9053 if ( aShapeId && newElem )
9054 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9055 if(theFace->IsMediumNode(nodes[il1])) {
9056 // create quadrangle
9057 newElem = aMesh->AddFace(nodes[0],nodes[1],nodes[3],nodes[7]);
9058 myLastCreatedElems.Append(newElem);
9059 if ( aShapeId && newElem )
9060 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9066 // create quadrangle
9067 newElem = aMesh->AddFace(nodes[1],nodes[2],nodes[3],nodes[7]);
9068 myLastCreatedElems.Append(newElem);
9069 if ( aShapeId && newElem )
9070 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9076 // create needed triangles using n1,n2,n3 and inserted nodes
9077 int nbn = 2 + aNodesToInsert.size();
9078 //const SMDS_MeshNode* aNodes[nbn];
9079 vector<const SMDS_MeshNode*> aNodes(nbn);
9080 aNodes[0] = nodes[n1];
9081 aNodes[nbn-1] = nodes[n2];
9082 list<const SMDS_MeshNode*>::iterator nIt = aNodesToInsert.begin();
9083 for ( iNode = 1; nIt != aNodesToInsert.end(); nIt++ ) {
9084 aNodes[iNode++] = *nIt;
9086 for(i=1; i<nbn; i++) {
9087 SMDS_MeshElement* newElem =
9088 aMesh->AddFace(aNodes[i-1],aNodes[i],nodes[n3]);
9089 myLastCreatedElems.Append(newElem);
9090 if ( aShapeId && newElem )
9091 aMesh->SetMeshElementOnShape( newElem, aShapeId );
9095 aMesh->RemoveElement(theFace);
9098 //=======================================================================
9099 //function : UpdateVolumes
9101 //=======================================================================
9102 void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
9103 const SMDS_MeshNode* theBetweenNode2,
9104 list<const SMDS_MeshNode*>& theNodesToInsert)
9106 myLastCreatedElems.Clear();
9107 myLastCreatedNodes.Clear();
9109 SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator(SMDSAbs_Volume);
9110 while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
9111 const SMDS_MeshElement* elem = invElemIt->next();
9113 // check, if current volume has link theBetweenNode1 - theBetweenNode2
9114 SMDS_VolumeTool aVolume (elem);
9115 if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
9118 // insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
9119 int iface, nbFaces = aVolume.NbFaces();
9120 vector<const SMDS_MeshNode *> poly_nodes;
9121 vector<int> quantities (nbFaces);
9123 for (iface = 0; iface < nbFaces; iface++) {
9124 int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
9125 // faceNodes will contain (nbFaceNodes + 1) nodes, last = first
9126 const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
9128 for (int inode = 0; inode < nbFaceNodes; inode++) {
9129 poly_nodes.push_back(faceNodes[inode]);
9131 if (nbInserted == 0) {
9132 if (faceNodes[inode] == theBetweenNode1) {
9133 if (faceNodes[inode + 1] == theBetweenNode2) {
9134 nbInserted = theNodesToInsert.size();
9136 // add nodes to insert
9137 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
9138 for (; nIt != theNodesToInsert.end(); nIt++) {
9139 poly_nodes.push_back(*nIt);
9143 else if (faceNodes[inode] == theBetweenNode2) {
9144 if (faceNodes[inode + 1] == theBetweenNode1) {
9145 nbInserted = theNodesToInsert.size();
9147 // add nodes to insert in reversed order
9148 list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
9150 for (; nIt != theNodesToInsert.begin(); nIt--) {
9151 poly_nodes.push_back(*nIt);
9153 poly_nodes.push_back(*nIt);
9160 quantities[iface] = nbFaceNodes + nbInserted;
9163 // Replace or update the volume
9164 SMESHDS_Mesh *aMesh = GetMeshDS();
9166 if (elem->IsPoly()) {
9167 aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
9171 int aShapeId = FindShape( elem );
9173 SMDS_MeshElement* newElem =
9174 aMesh->AddPolyhedralVolume(poly_nodes, quantities);
9175 myLastCreatedElems.Append(newElem);
9176 if (aShapeId && newElem)
9177 aMesh->SetMeshElementOnShape(newElem, aShapeId);
9179 aMesh->RemoveElement(elem);
9184 //=======================================================================
9186 * \brief Convert elements contained in a submesh to quadratic
9187 * \retval int - nb of checked elements
9189 //=======================================================================
9191 int SMESH_MeshEditor::convertElemToQuadratic(SMESHDS_SubMesh * theSm,
9192 SMESH_MesherHelper& theHelper,
9193 const bool theForce3d)
9196 if( !theSm ) return nbElem;
9198 vector<int> nbNodeInFaces;
9199 SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
9200 while(ElemItr->more())
9203 const SMDS_MeshElement* elem = ElemItr->next();
9204 if( !elem || elem->IsQuadratic() ) continue;
9206 int id = elem->GetID();
9207 int nbNodes = elem->NbNodes();
9208 SMDSAbs_ElementType aType = elem->GetType();
9210 vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
9211 if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
9212 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
9214 GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
9216 const SMDS_MeshElement* NewElem = 0;
9222 NewElem = theHelper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9230 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9233 NewElem = theHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9236 NewElem = theHelper.AddPolygonalFace(nodes, id, theForce3d);
9241 case SMDSAbs_Volume :
9246 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9249 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
9252 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
9255 NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9256 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9259 NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9266 ReplaceElemInGroups( elem, NewElem, GetMeshDS());
9268 theSm->AddElement( NewElem );
9270 // if (!GetMeshDS()->isCompacted())
9271 // GetMeshDS()->compactMesh();
9275 //=======================================================================
9276 //function : ConvertToQuadratic
9278 //=======================================================================
9279 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
9281 SMESHDS_Mesh* meshDS = GetMeshDS();
9283 SMESH_MesherHelper aHelper(*myMesh);
9284 aHelper.SetIsQuadratic( true );
9286 int nbCheckedElems = 0;
9287 if ( myMesh->HasShapeToMesh() )
9289 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9291 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9292 while ( smIt->more() ) {
9293 SMESH_subMesh* sm = smIt->next();
9294 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() ) {
9295 aHelper.SetSubShape( sm->GetSubShape() );
9296 nbCheckedElems += convertElemToQuadratic(smDS, aHelper, theForce3d);
9301 int totalNbElems = meshDS->NbEdges() + meshDS->NbFaces() + meshDS->NbVolumes();
9302 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9304 SMESHDS_SubMesh *smDS = 0;
9305 SMDS_EdgeIteratorPtr aEdgeItr = meshDS->edgesIterator();
9306 while(aEdgeItr->more())
9308 const SMDS_MeshEdge* edge = aEdgeItr->next();
9309 if(edge && !edge->IsQuadratic())
9311 int id = edge->GetID();
9312 //MESSAGE("edge->GetID() " << id);
9313 const SMDS_MeshNode* n1 = edge->GetNode(0);
9314 const SMDS_MeshNode* n2 = edge->GetNode(1);
9316 meshDS->RemoveFreeElement(edge, smDS, /*fromGroups=*/false);
9318 const SMDS_MeshEdge* NewEdge = aHelper.AddEdge(n1, n2, id, theForce3d);
9319 ReplaceElemInGroups( edge, NewEdge, GetMeshDS());
9322 SMDS_FaceIteratorPtr aFaceItr = meshDS->facesIterator();
9323 while(aFaceItr->more())
9325 const SMDS_MeshFace* face = aFaceItr->next();
9326 if(!face || face->IsQuadratic() ) continue;
9328 int id = face->GetID();
9329 int nbNodes = face->NbNodes();
9330 vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
9332 meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
9334 SMDS_MeshFace * NewFace = 0;
9338 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
9341 NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9344 NewFace = aHelper.AddPolygonalFace(nodes, id, theForce3d);
9346 ReplaceElemInGroups( face, NewFace, GetMeshDS());
9348 vector<int> nbNodeInFaces;
9349 SMDS_VolumeIteratorPtr aVolumeItr = meshDS->volumesIterator();
9350 while(aVolumeItr->more())
9352 const SMDS_MeshVolume* volume = aVolumeItr->next();
9353 if(!volume || volume->IsQuadratic() ) continue;
9355 int id = volume->GetID();
9356 int nbNodes = volume->NbNodes();
9357 vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
9358 if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
9359 nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
9361 meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
9363 SMDS_MeshVolume * NewVolume = 0;
9367 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9368 nodes[3], id, theForce3d );
9371 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9372 nodes[3], nodes[4], id, theForce3d);
9375 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
9376 nodes[3], nodes[4], nodes[5], id, theForce3d);
9379 NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9380 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9383 NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
9385 ReplaceElemInGroups(volume, NewVolume, meshDS);
9389 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9390 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9391 aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9392 aHelper.FixQuadraticElements();
9396 //================================================================================
9398 * \brief Makes given elements quadratic
9399 * \param theForce3d - if true, the medium nodes will be placed in the middle of link
9400 * \param theElements - elements to make quadratic
9402 //================================================================================
9404 void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
9405 TIDSortedElemSet& theElements)
9407 if ( theElements.empty() ) return;
9409 // we believe that all theElements are of the same type
9410 SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
9412 // get all nodes shared by theElements
9413 TIDSortedNodeSet allNodes;
9414 TIDSortedElemSet::iterator eIt = theElements.begin();
9415 for ( ; eIt != theElements.end(); ++eIt )
9416 allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
9418 // complete theElements with elements of lower dim whose all nodes are in allNodes
9420 TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
9421 TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
9422 TIDSortedNodeSet::iterator nIt = allNodes.begin();
9423 for ( ; nIt != allNodes.end(); ++nIt )
9425 const SMDS_MeshNode* n = *nIt;
9426 SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
9427 while ( invIt->more() )
9429 const SMDS_MeshElement* e = invIt->next();
9430 if ( e->IsQuadratic() )
9432 quadAdjacentElems[ e->GetType() ].insert( e );
9435 if ( e->GetType() >= elemType )
9437 continue; // same type of more complex linear element
9440 if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
9441 continue; // e is already checked
9445 SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
9446 while ( nodeIt->more() && allIn )
9447 allIn = allNodes.count( cast2Node( nodeIt->next() ));
9449 theElements.insert(e );
9453 SMESH_MesherHelper helper(*myMesh);
9454 helper.SetIsQuadratic( true );
9456 // add links of quadratic adjacent elements to the helper
9458 if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
9459 for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
9460 eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
9462 helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
9464 if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
9465 for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
9466 eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
9468 helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
9470 if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
9471 for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
9472 eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
9474 helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
9477 // make quadratic elements instead of linear ones
9479 SMESHDS_Mesh* meshDS = GetMeshDS();
9480 SMESHDS_SubMesh* smDS = 0;
9481 for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
9483 const SMDS_MeshElement* elem = *eIt;
9484 if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
9487 int id = elem->GetID();
9488 SMDSAbs_ElementType type = elem->GetType();
9489 vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
9491 if ( !smDS || !smDS->Contains( elem ))
9492 smDS = meshDS->MeshElements( elem->getshapeId() );
9493 meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
9495 SMDS_MeshElement * newElem = 0;
9496 switch( nodes.size() )
9498 case 4: // cases for most multiple element types go first (for optimization)
9499 if ( type == SMDSAbs_Volume )
9500 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9502 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
9505 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9506 nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
9509 newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
9512 newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
9515 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9516 nodes[4], id, theForce3d);
9519 newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
9520 nodes[4], nodes[5], id, theForce3d);
9524 ReplaceElemInGroups( elem, newElem, meshDS);
9525 if( newElem && smDS )
9526 smDS->AddElement( newElem );
9529 if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
9530 { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
9531 helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
9532 helper.FixQuadraticElements();
9536 //=======================================================================
9538 * \brief Convert quadratic elements to linear ones and remove quadratic nodes
9539 * \retval int - nb of checked elements
9541 //=======================================================================
9543 int SMESH_MeshEditor::removeQuadElem(SMESHDS_SubMesh * theSm,
9544 SMDS_ElemIteratorPtr theItr,
9545 const int theShapeID)
9548 SMESHDS_Mesh* meshDS = GetMeshDS();
9550 while( theItr->more() )
9552 const SMDS_MeshElement* elem = theItr->next();
9554 if( elem && elem->IsQuadratic())
9556 int id = elem->GetID();
9557 int nbCornerNodes = elem->NbCornerNodes();
9558 SMDSAbs_ElementType aType = elem->GetType();
9560 vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
9562 //remove a quadratic element
9563 if ( !theSm || !theSm->Contains( elem ))
9564 theSm = meshDS->MeshElements( elem->getshapeId() );
9565 meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
9567 // remove medium nodes
9568 for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
9569 if ( nodes[i]->NbInverseElements() == 0 )
9570 meshDS->RemoveFreeNode( nodes[i], theSm );
9572 // add a linear element
9573 nodes.resize( nbCornerNodes );
9574 SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
9575 ReplaceElemInGroups(elem, newElem, meshDS);
9576 if( theSm && newElem )
9577 theSm->AddElement( newElem );
9583 //=======================================================================
9584 //function : ConvertFromQuadratic
9586 //=======================================================================
9588 bool SMESH_MeshEditor::ConvertFromQuadratic()
9590 int nbCheckedElems = 0;
9591 if ( myMesh->HasShapeToMesh() )
9593 if ( SMESH_subMesh *aSubMesh = myMesh->GetSubMeshContaining(myMesh->GetShapeToMesh()))
9595 SMESH_subMeshIteratorPtr smIt = aSubMesh->getDependsOnIterator(true,false);
9596 while ( smIt->more() ) {
9597 SMESH_subMesh* sm = smIt->next();
9598 if ( SMESHDS_SubMesh *smDS = sm->GetSubMeshDS() )
9599 nbCheckedElems += removeQuadElem( smDS, smDS->GetElements(), sm->GetId() );
9605 GetMeshDS()->NbEdges() + GetMeshDS()->NbFaces() + GetMeshDS()->NbVolumes();
9606 if ( nbCheckedElems < totalNbElems ) // not all elements are in submeshes
9608 SMESHDS_SubMesh *aSM = 0;
9609 removeQuadElem( aSM, GetMeshDS()->elementsIterator(), 0 );
9617 //================================================================================
9619 * \brief Return true if all medium nodes of the element are in the node set
9621 //================================================================================
9623 bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
9625 for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
9626 if ( !nodeSet.count( elem->GetNode(i) ))
9632 //================================================================================
9634 * \brief Makes given elements linear
9636 //================================================================================
9638 void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
9640 if ( theElements.empty() ) return;
9642 // collect IDs of medium nodes of theElements; some of these nodes will be removed
9643 set<int> mediumNodeIDs;
9644 TIDSortedElemSet::iterator eIt = theElements.begin();
9645 for ( ; eIt != theElements.end(); ++eIt )
9647 const SMDS_MeshElement* e = *eIt;
9648 for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
9649 mediumNodeIDs.insert( e->GetNode(i)->GetID() );
9652 // replace given elements by linear ones
9653 typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
9654 SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
9655 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9657 // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
9658 // except those elements sharing medium nodes of quadratic element whose medium nodes
9659 // are not all in mediumNodeIDs
9661 // get remaining medium nodes
9662 TIDSortedNodeSet mediumNodes;
9663 set<int>::iterator nIdsIt = mediumNodeIDs.begin();
9664 for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
9665 if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
9666 mediumNodes.insert( mediumNodes.end(), n );
9668 // find more quadratic elements to convert
9669 TIDSortedElemSet moreElemsToConvert;
9670 TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
9671 for ( ; nIt != mediumNodes.end(); ++nIt )
9673 SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
9674 while ( invIt->more() )
9676 const SMDS_MeshElement* e = invIt->next();
9677 if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
9679 // find a more complex element including e and
9680 // whose medium nodes are not in mediumNodes
9681 bool complexFound = false;
9682 for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
9684 SMDS_ElemIteratorPtr invIt2 =
9685 (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
9686 while ( invIt2->more() )
9688 const SMDS_MeshElement* eComplex = invIt2->next();
9689 if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
9691 int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
9692 if ( nbCommonNodes == e->NbNodes())
9694 complexFound = true;
9695 type = SMDSAbs_NbElementTypes; // to quit from the outer loop
9701 if ( !complexFound )
9702 moreElemsToConvert.insert( e );
9706 elemIt = SMDS_ElemIteratorPtr
9707 (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
9708 removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
9711 //=======================================================================
9712 //function : SewSideElements
9714 //=======================================================================
9716 SMESH_MeshEditor::Sew_Error
9717 SMESH_MeshEditor::SewSideElements (TIDSortedElemSet& theSide1,
9718 TIDSortedElemSet& theSide2,
9719 const SMDS_MeshNode* theFirstNode1,
9720 const SMDS_MeshNode* theFirstNode2,
9721 const SMDS_MeshNode* theSecondNode1,
9722 const SMDS_MeshNode* theSecondNode2)
9724 myLastCreatedElems.Clear();
9725 myLastCreatedNodes.Clear();
9727 MESSAGE ("::::SewSideElements()");
9728 if ( theSide1.size() != theSide2.size() )
9729 return SEW_DIFF_NB_OF_ELEMENTS;
9731 Sew_Error aResult = SEW_OK;
9733 // 1. Build set of faces representing each side
9734 // 2. Find which nodes of the side 1 to merge with ones on the side 2
9735 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
9737 // =======================================================================
9738 // 1. Build set of faces representing each side:
9739 // =======================================================================
9740 // a. build set of nodes belonging to faces
9741 // b. complete set of faces: find missing faces whose nodes are in set of nodes
9742 // c. create temporary faces representing side of volumes if correspondent
9743 // face does not exist
9745 SMESHDS_Mesh* aMesh = GetMeshDS();
9746 // TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
9747 //SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
9748 set<const SMDS_MeshElement*> faceSet1, faceSet2;
9749 set<const SMDS_MeshElement*> volSet1, volSet2;
9750 set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
9751 set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
9752 set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
9753 set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
9754 TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
9755 int iSide, iFace, iNode;
9757 list<const SMDS_MeshElement* > tempFaceList;
9758 for ( iSide = 0; iSide < 2; iSide++ ) {
9759 set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
9760 TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
9761 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
9762 set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
9763 set<const SMDS_MeshElement*>::iterator vIt;
9764 TIDSortedElemSet::iterator eIt;
9765 set<const SMDS_MeshNode*>::iterator nIt;
9767 // check that given nodes belong to given elements
9768 const SMDS_MeshNode* n1 = ( iSide == 0 ) ? theFirstNode1 : theFirstNode2;
9769 const SMDS_MeshNode* n2 = ( iSide == 0 ) ? theSecondNode1 : theSecondNode2;
9770 int firstIndex = -1, secondIndex = -1;
9771 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9772 const SMDS_MeshElement* elem = *eIt;
9773 if ( firstIndex < 0 ) firstIndex = elem->GetNodeIndex( n1 );
9774 if ( secondIndex < 0 ) secondIndex = elem->GetNodeIndex( n2 );
9775 if ( firstIndex > -1 && secondIndex > -1 ) break;
9777 if ( firstIndex < 0 || secondIndex < 0 ) {
9778 // we can simply return until temporary faces created
9779 return (iSide == 0 ) ? SEW_BAD_SIDE1_NODES : SEW_BAD_SIDE2_NODES;
9782 // -----------------------------------------------------------
9783 // 1a. Collect nodes of existing faces
9784 // and build set of face nodes in order to detect missing
9785 // faces corresponding to sides of volumes
9786 // -----------------------------------------------------------
9788 set< set <const SMDS_MeshNode*> > setOfFaceNodeSet;
9790 // loop on the given element of a side
9791 for (eIt = elemSet->begin(); eIt != elemSet->end(); eIt++ ) {
9792 //const SMDS_MeshElement* elem = *eIt;
9793 const SMDS_MeshElement* elem = *eIt;
9794 if ( elem->GetType() == SMDSAbs_Face ) {
9795 faceSet->insert( elem );
9796 set <const SMDS_MeshNode*> faceNodeSet;
9797 SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
9798 while ( nodeIt->more() ) {
9799 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9800 nodeSet->insert( n );
9801 faceNodeSet.insert( n );
9803 setOfFaceNodeSet.insert( faceNodeSet );
9805 else if ( elem->GetType() == SMDSAbs_Volume )
9806 volSet->insert( elem );
9808 // ------------------------------------------------------------------------------
9809 // 1b. Complete set of faces: find missing faces whose nodes are in set of nodes
9810 // ------------------------------------------------------------------------------
9812 for ( nIt = nodeSet->begin(); nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9813 SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9814 while ( fIt->more() ) { // loop on faces sharing a node
9815 const SMDS_MeshElement* f = fIt->next();
9816 if ( faceSet->find( f ) == faceSet->end() ) {
9817 // check if all nodes are in nodeSet and
9818 // complete setOfFaceNodeSet if they are
9819 set <const SMDS_MeshNode*> faceNodeSet;
9820 SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9821 bool allInSet = true;
9822 while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9823 const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9824 if ( nodeSet->find( n ) == nodeSet->end() )
9827 faceNodeSet.insert( n );
9830 faceSet->insert( f );
9831 setOfFaceNodeSet.insert( faceNodeSet );
9837 // -------------------------------------------------------------------------
9838 // 1c. Create temporary faces representing sides of volumes if correspondent
9839 // face does not exist
9840 // -------------------------------------------------------------------------
9842 if ( !volSet->empty() ) {
9843 //int nodeSetSize = nodeSet->size();
9845 // loop on given volumes
9846 for ( vIt = volSet->begin(); vIt != volSet->end(); vIt++ ) {
9847 SMDS_VolumeTool vol (*vIt);
9848 // loop on volume faces: find free faces
9849 // --------------------------------------
9850 list<const SMDS_MeshElement* > freeFaceList;
9851 for ( iFace = 0; iFace < vol.NbFaces(); iFace++ ) {
9852 if ( !vol.IsFreeFace( iFace ))
9854 // check if there is already a face with same nodes in a face set
9855 const SMDS_MeshElement* aFreeFace = 0;
9856 const SMDS_MeshNode** fNodes = vol.GetFaceNodes( iFace );
9857 int nbNodes = vol.NbFaceNodes( iFace );
9858 set <const SMDS_MeshNode*> faceNodeSet;
9859 vol.GetFaceNodes( iFace, faceNodeSet );
9860 bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
9862 // no such a face is given but it still can exist, check it
9863 if ( nbNodes == 3 ) {
9864 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
9866 else if ( nbNodes == 4 ) {
9867 aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9870 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9871 aFreeFace = aMesh->FindFace(poly_nodes);
9875 // create a temporary face
9876 if ( nbNodes == 3 ) {
9877 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
9878 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
9880 else if ( nbNodes == 4 ) {
9881 //aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9882 aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
9885 vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
9886 //aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
9887 aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
9891 freeFaceList.push_back( aFreeFace );
9892 tempFaceList.push_back( aFreeFace );
9895 } // loop on faces of a volume
9897 // choose one of several free faces
9898 // --------------------------------------
9899 if ( freeFaceList.size() > 1 ) {
9900 // choose a face having max nb of nodes shared by other elems of a side
9901 int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
9902 list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
9903 while ( fIt != freeFaceList.end() ) { // loop on free faces
9904 int nbSharedNodes = 0;
9905 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9906 while ( nodeIt->more() ) { // loop on free face nodes
9907 const SMDS_MeshNode* n =
9908 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9909 SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
9910 while ( invElemIt->more() ) {
9911 const SMDS_MeshElement* e = invElemIt->next();
9912 if ( faceSet->find( e ) != faceSet->end() )
9914 if ( elemSet->find( e ) != elemSet->end() )
9918 if ( nbSharedNodes >= maxNbNodes ) {
9919 maxNbNodes = nbSharedNodes;
9923 freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
9925 if ( freeFaceList.size() > 1 )
9927 // could not choose one face, use another way
9928 // choose a face most close to the bary center of the opposite side
9929 gp_XYZ aBC( 0., 0., 0. );
9930 set <const SMDS_MeshNode*> addedNodes;
9931 TIDSortedElemSet * elemSet2 = elemSetPtr[ 1 - iSide ];
9932 eIt = elemSet2->begin();
9933 for ( eIt = elemSet2->begin(); eIt != elemSet2->end(); eIt++ ) {
9934 SMDS_ElemIteratorPtr nodeIt = (*eIt)->nodesIterator();
9935 while ( nodeIt->more() ) { // loop on free face nodes
9936 const SMDS_MeshNode* n =
9937 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9938 if ( addedNodes.insert( n ).second )
9939 aBC += gp_XYZ( n->X(),n->Y(),n->Z() );
9942 aBC /= addedNodes.size();
9943 double minDist = DBL_MAX;
9944 fIt = freeFaceList.begin();
9945 while ( fIt != freeFaceList.end() ) { // loop on free faces
9947 SMDS_ElemIteratorPtr nodeIt = (*fIt)->nodesIterator();
9948 while ( nodeIt->more() ) { // loop on free face nodes
9949 const SMDS_MeshNode* n =
9950 static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9951 gp_XYZ p( n->X(),n->Y(),n->Z() );
9952 dist += ( aBC - p ).SquareModulus();
9954 if ( dist < minDist ) {
9956 freeFaceList.erase( freeFaceList.begin(), fIt++ );
9959 fIt = freeFaceList.erase( fIt++ );
9962 } // choose one of several free faces of a volume
9964 if ( freeFaceList.size() == 1 ) {
9965 const SMDS_MeshElement* aFreeFace = freeFaceList.front();
9966 faceSet->insert( aFreeFace );
9967 // complete a node set with nodes of a found free face
9968 // for ( iNode = 0; iNode < ; iNode++ )
9969 // nodeSet->insert( fNodes[ iNode ] );
9972 } // loop on volumes of a side
9974 // // complete a set of faces if new nodes in a nodeSet appeared
9975 // // ----------------------------------------------------------
9976 // if ( nodeSetSize != nodeSet->size() ) {
9977 // for ( ; nIt != nodeSet->end(); nIt++ ) { // loop on nodes of iSide
9978 // SMDS_ElemIteratorPtr fIt = (*nIt)->GetInverseElementIterator(SMDSAbs_Face);
9979 // while ( fIt->more() ) { // loop on faces sharing a node
9980 // const SMDS_MeshElement* f = fIt->next();
9981 // if ( faceSet->find( f ) == faceSet->end() ) {
9982 // // check if all nodes are in nodeSet and
9983 // // complete setOfFaceNodeSet if they are
9984 // set <const SMDS_MeshNode*> faceNodeSet;
9985 // SMDS_ElemIteratorPtr nodeIt = f->nodesIterator();
9986 // bool allInSet = true;
9987 // while ( nodeIt->more() && allInSet ) { // loop on nodes of a face
9988 // const SMDS_MeshNode* n = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
9989 // if ( nodeSet->find( n ) == nodeSet->end() )
9990 // allInSet = false;
9992 // faceNodeSet.insert( n );
9994 // if ( allInSet ) {
9995 // faceSet->insert( f );
9996 // setOfFaceNodeSet.insert( faceNodeSet );
10002 } // Create temporary faces, if there are volumes given
10005 if ( faceSet1.size() != faceSet2.size() ) {
10006 // delete temporary faces: they are in reverseElements of actual nodes
10007 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10008 // while ( tmpFaceIt->more() )
10009 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10010 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10011 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10012 // aMesh->RemoveElement(*tmpFaceIt);
10013 MESSAGE("Diff nb of faces");
10014 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10017 // ============================================================
10018 // 2. Find nodes to merge:
10019 // bind a node to remove to a node to put instead
10020 // ============================================================
10022 TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
10023 if ( theFirstNode1 != theFirstNode2 )
10024 nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
10025 if ( theSecondNode1 != theSecondNode2 )
10026 nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
10028 LinkID_Gen aLinkID_Gen( GetMeshDS() );
10029 set< long > linkIdSet; // links to process
10030 linkIdSet.insert( aLinkID_Gen.GetLinkID( theFirstNode1, theSecondNode1 ));
10032 typedef pair< const SMDS_MeshNode*, const SMDS_MeshNode* > NLink;
10033 list< NLink > linkList[2];
10034 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10035 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10036 // loop on links in linkList; find faces by links and append links
10037 // of the found faces to linkList
10038 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10039 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10040 NLink link[] = { *linkIt[0], *linkIt[1] };
10041 long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
10042 if ( linkIdSet.find( linkID ) == linkIdSet.end() )
10045 // by links, find faces in the face sets,
10046 // and find indices of link nodes in the found faces;
10047 // in a face set, there is only one or no face sharing a link
10048 // ---------------------------------------------------------------
10050 const SMDS_MeshElement* face[] = { 0, 0 };
10051 //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
10052 vector<const SMDS_MeshNode*> fnodes1(9);
10053 vector<const SMDS_MeshNode*> fnodes2(9);
10054 //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
10055 vector<const SMDS_MeshNode*> notLinkNodes1(6);
10056 vector<const SMDS_MeshNode*> notLinkNodes2(6);
10057 int iLinkNode[2][2];
10058 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10059 const SMDS_MeshNode* n1 = link[iSide].first;
10060 const SMDS_MeshNode* n2 = link[iSide].second;
10061 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10062 set< const SMDS_MeshElement* > fMap;
10063 for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
10064 const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
10065 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10066 while ( fIt->more() ) { // loop on faces sharing a node
10067 const SMDS_MeshElement* f = fIt->next();
10068 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10069 ! fMap.insert( f ).second ) // f encounters twice
10071 if ( face[ iSide ] ) {
10072 MESSAGE( "2 faces per link " );
10073 aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
10077 faceSet->erase( f );
10078 // get face nodes and find ones of a link
10083 fnodes1.resize(f->NbNodes()+1);
10084 notLinkNodes1.resize(f->NbNodes()-2);
10087 fnodes2.resize(f->NbNodes()+1);
10088 notLinkNodes2.resize(f->NbNodes()-2);
10091 if(!f->IsQuadratic()) {
10092 SMDS_ElemIteratorPtr nIt = f->nodesIterator();
10093 while ( nIt->more() ) {
10094 const SMDS_MeshNode* n =
10095 static_cast<const SMDS_MeshNode*>( nIt->next() );
10097 iLinkNode[ iSide ][ 0 ] = iNode;
10099 else if ( n == n2 ) {
10100 iLinkNode[ iSide ][ 1 ] = iNode;
10102 //else if ( notLinkNodes[ iSide ][ 0 ] )
10103 // notLinkNodes[ iSide ][ 1 ] = n;
10105 // notLinkNodes[ iSide ][ 0 ] = n;
10109 notLinkNodes1[nbl] = n;
10110 //notLinkNodes1.push_back(n);
10112 notLinkNodes2[nbl] = n;
10113 //notLinkNodes2.push_back(n);
10115 //faceNodes[ iSide ][ iNode++ ] = n;
10117 fnodes1[iNode++] = n;
10120 fnodes2[iNode++] = n;
10124 else { // f->IsQuadratic()
10125 const SMDS_VtkFace* F =
10126 dynamic_cast<const SMDS_VtkFace*>(f);
10127 if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
10128 // use special nodes iterator
10129 SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
10130 while ( anIter->more() ) {
10131 const SMDS_MeshNode* n =
10132 static_cast<const SMDS_MeshNode*>( anIter->next() );
10134 iLinkNode[ iSide ][ 0 ] = iNode;
10136 else if ( n == n2 ) {
10137 iLinkNode[ iSide ][ 1 ] = iNode;
10142 notLinkNodes1[nbl] = n;
10145 notLinkNodes2[nbl] = n;
10149 fnodes1[iNode++] = n;
10152 fnodes2[iNode++] = n;
10156 //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
10158 fnodes1[iNode] = fnodes1[0];
10161 fnodes2[iNode] = fnodes1[0];
10168 // check similarity of elements of the sides
10169 if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10170 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10171 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10172 aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10175 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10177 break; // do not return because it s necessary to remove tmp faces
10180 // set nodes to merge
10181 // -------------------
10183 if ( face[0] && face[1] ) {
10184 int nbNodes = face[0]->NbNodes();
10185 if ( nbNodes != face[1]->NbNodes() ) {
10186 MESSAGE("Diff nb of face nodes");
10187 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10188 break; // do not return because it s necessary to remove tmp faces
10190 bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
10191 if ( nbNodes == 3 ) {
10192 //nReplaceMap.insert( TNodeNodeMap::value_type
10193 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10194 nReplaceMap.insert( TNodeNodeMap::value_type
10195 ( notLinkNodes1[0], notLinkNodes2[0] ));
10198 for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
10199 // analyse link orientation in faces
10200 int i1 = iLinkNode[ iSide ][ 0 ];
10201 int i2 = iLinkNode[ iSide ][ 1 ];
10202 reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
10203 // if notLinkNodes are the first and the last ones, then
10204 // their order does not correspond to the link orientation
10205 if (( i1 == 1 && i2 == 2 ) ||
10206 ( i1 == 2 && i2 == 1 ))
10207 reverse[ iSide ] = !reverse[ iSide ];
10209 if ( reverse[0] == reverse[1] ) {
10210 //nReplaceMap.insert( TNodeNodeMap::value_type
10211 // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
10212 //nReplaceMap.insert( TNodeNodeMap::value_type
10213 // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
10214 for(int nn=0; nn<nbNodes-2; nn++) {
10215 nReplaceMap.insert( TNodeNodeMap::value_type
10216 ( notLinkNodes1[nn], notLinkNodes2[nn] ));
10220 //nReplaceMap.insert( TNodeNodeMap::value_type
10221 // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
10222 //nReplaceMap.insert( TNodeNodeMap::value_type
10223 // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
10224 for(int nn=0; nn<nbNodes-2; nn++) {
10225 nReplaceMap.insert( TNodeNodeMap::value_type
10226 ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
10231 // add other links of the faces to linkList
10232 // -----------------------------------------
10234 //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
10235 for ( iNode = 0; iNode < nbNodes; iNode++ ) {
10236 //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
10237 linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
10238 pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
10239 if ( !iter_isnew.second ) { // already in a set: no need to process
10240 linkIdSet.erase( iter_isnew.first );
10242 else // new in set == encountered for the first time: add
10244 //const SMDS_MeshNode* n1 = nodes[ iNode ];
10245 //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
10246 const SMDS_MeshNode* n1 = fnodes1[ iNode ];
10247 const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
10248 linkList[0].push_back ( NLink( n1, n2 ));
10249 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10253 } // loop on link lists
10255 if ( aResult == SEW_OK &&
10256 ( linkIt[0] != linkList[0].end() ||
10257 !faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
10258 MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
10259 " " << (faceSetPtr[1]->empty()));
10260 aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10263 // ====================================================================
10264 // 3. Replace nodes in elements of the side 1 and remove replaced nodes
10265 // ====================================================================
10267 // delete temporary faces: they are in reverseElements of actual nodes
10268 // SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
10269 // while ( tmpFaceIt->more() )
10270 // aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
10271 // list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
10272 // for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
10273 // aMesh->RemoveElement(*tmpFaceIt);
10275 if ( aResult != SEW_OK)
10278 list< int > nodeIDsToRemove/*, elemIDsToRemove*/;
10279 // loop on nodes replacement map
10280 TNodeNodeMap::iterator nReplaceMapIt = nReplaceMap.begin(), nnIt;
10281 for ( ; nReplaceMapIt != nReplaceMap.end(); nReplaceMapIt++ )
10282 if ( (*nReplaceMapIt).first != (*nReplaceMapIt).second ) {
10283 const SMDS_MeshNode* nToRemove = (*nReplaceMapIt).first;
10284 nodeIDsToRemove.push_back( nToRemove->GetID() );
10285 // loop on elements sharing nToRemove
10286 SMDS_ElemIteratorPtr invElemIt = nToRemove->GetInverseElementIterator();
10287 while ( invElemIt->more() ) {
10288 const SMDS_MeshElement* e = invElemIt->next();
10289 // get a new suite of nodes: make replacement
10290 int nbReplaced = 0, i = 0, nbNodes = e->NbNodes();
10291 vector< const SMDS_MeshNode*> nodes( nbNodes );
10292 SMDS_ElemIteratorPtr nIt = e->nodesIterator();
10293 while ( nIt->more() ) {
10294 const SMDS_MeshNode* n =
10295 static_cast<const SMDS_MeshNode*>( nIt->next() );
10296 nnIt = nReplaceMap.find( n );
10297 if ( nnIt != nReplaceMap.end() ) {
10299 n = (*nnIt).second;
10303 // if ( nbReplaced == nbNodes && e->GetType() == SMDSAbs_Face )
10304 // elemIDsToRemove.push_back( e->GetID() );
10308 SMDSAbs_ElementType etyp = e->GetType();
10309 SMDS_MeshElement* newElem = this->AddElement(nodes, etyp, false);
10312 myLastCreatedElems.Append(newElem);
10313 AddToSameGroups(newElem, e, aMesh);
10314 int aShapeId = e->getshapeId();
10317 aMesh->SetMeshElementOnShape( newElem, aShapeId );
10320 aMesh->RemoveElement(e);
10325 Remove( nodeIDsToRemove, true );
10330 //================================================================================
10332 * \brief Find corresponding nodes in two sets of faces
10333 * \param theSide1 - first face set
10334 * \param theSide2 - second first face
10335 * \param theFirstNode1 - a boundary node of set 1
10336 * \param theFirstNode2 - a node of set 2 corresponding to theFirstNode1
10337 * \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
10338 * \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
10339 * \param nReplaceMap - output map of corresponding nodes
10340 * \retval bool - is a success or not
10342 //================================================================================
10345 //#define DEBUG_MATCHING_NODES
10348 SMESH_MeshEditor::Sew_Error
10349 SMESH_MeshEditor::FindMatchingNodes(set<const SMDS_MeshElement*>& theSide1,
10350 set<const SMDS_MeshElement*>& theSide2,
10351 const SMDS_MeshNode* theFirstNode1,
10352 const SMDS_MeshNode* theFirstNode2,
10353 const SMDS_MeshNode* theSecondNode1,
10354 const SMDS_MeshNode* theSecondNode2,
10355 TNodeNodeMap & nReplaceMap)
10357 set<const SMDS_MeshElement*> * faceSetPtr[] = { &theSide1, &theSide2 };
10359 nReplaceMap.clear();
10360 if ( theFirstNode1 != theFirstNode2 )
10361 nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
10362 if ( theSecondNode1 != theSecondNode2 )
10363 nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
10365 set< SMESH_TLink > linkSet; // set of nodes where order of nodes is ignored
10366 linkSet.insert( SMESH_TLink( theFirstNode1, theSecondNode1 ));
10368 list< NLink > linkList[2];
10369 linkList[0].push_back( NLink( theFirstNode1, theSecondNode1 ));
10370 linkList[1].push_back( NLink( theFirstNode2, theSecondNode2 ));
10372 // loop on links in linkList; find faces by links and append links
10373 // of the found faces to linkList
10374 list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
10375 for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
10376 NLink link[] = { *linkIt[0], *linkIt[1] };
10377 if ( linkSet.find( link[0] ) == linkSet.end() )
10380 // by links, find faces in the face sets,
10381 // and find indices of link nodes in the found faces;
10382 // in a face set, there is only one or no face sharing a link
10383 // ---------------------------------------------------------------
10385 const SMDS_MeshElement* face[] = { 0, 0 };
10386 list<const SMDS_MeshNode*> notLinkNodes[2];
10387 //bool reverse[] = { false, false }; // order of notLinkNodes
10389 for ( int iSide = 0; iSide < 2; iSide++ ) // loop on 2 sides
10391 const SMDS_MeshNode* n1 = link[iSide].first;
10392 const SMDS_MeshNode* n2 = link[iSide].second;
10393 set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
10394 set< const SMDS_MeshElement* > facesOfNode1;
10395 for ( int iNode = 0; iNode < 2; iNode++ ) // loop on 2 nodes of a link
10397 // during a loop of the first node, we find all faces around n1,
10398 // during a loop of the second node, we find one face sharing both n1 and n2
10399 const SMDS_MeshNode* n = iNode ? n1 : n2; // a node of a link
10400 SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
10401 while ( fIt->more() ) { // loop on faces sharing a node
10402 const SMDS_MeshElement* f = fIt->next();
10403 if (faceSet->find( f ) != faceSet->end() && // f is in face set
10404 ! facesOfNode1.insert( f ).second ) // f encounters twice
10406 if ( face[ iSide ] ) {
10407 MESSAGE( "2 faces per link " );
10408 return ( iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10411 faceSet->erase( f );
10413 // get not link nodes
10414 int nbN = f->NbNodes();
10415 if ( f->IsQuadratic() )
10417 nbNodes[ iSide ] = nbN;
10418 list< const SMDS_MeshNode* > & nodes = notLinkNodes[ iSide ];
10419 int i1 = f->GetNodeIndex( n1 );
10420 int i2 = f->GetNodeIndex( n2 );
10421 int iEnd = nbN, iBeg = -1, iDelta = 1;
10422 bool reverse = ( Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1 );
10424 std::swap( iEnd, iBeg ); iDelta = -1;
10429 if ( i == iEnd ) i = iBeg + iDelta;
10430 if ( i == i1 ) break;
10431 nodes.push_back ( f->GetNode( i ) );
10437 // check similarity of elements of the sides
10438 if (( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
10439 MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
10440 if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
10441 return ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
10444 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10448 // set nodes to merge
10449 // -------------------
10451 if ( face[0] && face[1] ) {
10452 if ( nbNodes[0] != nbNodes[1] ) {
10453 MESSAGE("Diff nb of face nodes");
10454 return SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
10456 #ifdef DEBUG_MATCHING_NODES
10457 MESSAGE ( " Link 1: " << link[0].first->GetID() <<" "<< link[0].second->GetID()
10458 << " F 1: " << face[0] << "| Link 2: " << link[1].first->GetID() <<" "
10459 << link[1].second->GetID() << " F 2: " << face[1] << " | Bind: " ) ;
10461 int nbN = nbNodes[0];
10463 list<const SMDS_MeshNode*>::iterator n1 = notLinkNodes[0].begin();
10464 list<const SMDS_MeshNode*>::iterator n2 = notLinkNodes[1].begin();
10465 for ( int i = 0 ; i < nbN - 2; ++i ) {
10466 #ifdef DEBUG_MATCHING_NODES
10467 MESSAGE ( (*n1)->GetID() << " to " << (*n2)->GetID() );
10469 nReplaceMap.insert( make_pair( *(n1++), *(n2++) ));
10473 // add other links of the face 1 to linkList
10474 // -----------------------------------------
10476 const SMDS_MeshElement* f0 = face[0];
10477 const SMDS_MeshNode* n1 = f0->GetNode( nbN - 1 );
10478 for ( int i = 0; i < nbN; i++ )
10480 const SMDS_MeshNode* n2 = f0->GetNode( i );
10481 pair< set< SMESH_TLink >::iterator, bool > iter_isnew =
10482 linkSet.insert( SMESH_TLink( n1, n2 ));
10483 if ( !iter_isnew.second ) { // already in a set: no need to process
10484 linkSet.erase( iter_isnew.first );
10486 else // new in set == encountered for the first time: add
10488 #ifdef DEBUG_MATCHING_NODES
10489 MESSAGE ( "Add link 1: " << n1->GetID() << " " << n2->GetID() << " "
10490 << " | link 2: " << nReplaceMap[n1]->GetID() << " " << nReplaceMap[n2]->GetID() << " " );
10492 linkList[0].push_back ( NLink( n1, n2 ));
10493 linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
10498 } // loop on link lists
10503 //================================================================================
10505 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10506 \param theElems - the list of elements (edges or faces) to be replicated
10507 The nodes for duplication could be found from these elements
10508 \param theNodesNot - list of nodes to NOT replicate
10509 \param theAffectedElems - the list of elements (cells and edges) to which the
10510 replicated nodes should be associated to.
10511 \return TRUE if operation has been completed successfully, FALSE otherwise
10513 //================================================================================
10515 bool SMESH_MeshEditor::DoubleNodes( const TIDSortedElemSet& theElems,
10516 const TIDSortedElemSet& theNodesNot,
10517 const TIDSortedElemSet& theAffectedElems )
10519 myLastCreatedElems.Clear();
10520 myLastCreatedNodes.Clear();
10522 if ( theElems.size() == 0 )
10525 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10530 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10531 // duplicate elements and nodes
10532 res = doubleNodes( aMeshDS, theElems, theNodesNot, anOldNodeToNewNode, true );
10533 // replce nodes by duplications
10534 res = doubleNodes( aMeshDS, theAffectedElems, theNodesNot, anOldNodeToNewNode, false );
10538 //================================================================================
10540 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10541 \param theMeshDS - mesh instance
10542 \param theElems - the elements replicated or modified (nodes should be changed)
10543 \param theNodesNot - nodes to NOT replicate
10544 \param theNodeNodeMap - relation of old node to new created node
10545 \param theIsDoubleElem - flag os to replicate element or modify
10546 \return TRUE if operation has been completed successfully, FALSE otherwise
10548 //================================================================================
10550 bool SMESH_MeshEditor::doubleNodes( SMESHDS_Mesh* theMeshDS,
10551 const TIDSortedElemSet& theElems,
10552 const TIDSortedElemSet& theNodesNot,
10553 std::map< const SMDS_MeshNode*,
10554 const SMDS_MeshNode* >& theNodeNodeMap,
10555 const bool theIsDoubleElem )
10557 MESSAGE("doubleNodes");
10558 // iterate on through element and duplicate them (by nodes duplication)
10560 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10561 for ( ; elemItr != theElems.end(); ++elemItr )
10563 const SMDS_MeshElement* anElem = *elemItr;
10567 bool isDuplicate = false;
10568 // duplicate nodes to duplicate element
10569 std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
10570 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10572 while ( anIter->more() )
10575 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10576 SMDS_MeshNode* aNewNode = aCurrNode;
10577 if ( theNodeNodeMap.find( aCurrNode ) != theNodeNodeMap.end() )
10578 aNewNode = (SMDS_MeshNode*)theNodeNodeMap[ aCurrNode ];
10579 else if ( theIsDoubleElem && theNodesNot.find( aCurrNode ) == theNodesNot.end() )
10582 aNewNode = theMeshDS->AddNode( aCurrNode->X(), aCurrNode->Y(), aCurrNode->Z() );
10583 theNodeNodeMap[ aCurrNode ] = aNewNode;
10584 myLastCreatedNodes.Append( aNewNode );
10586 isDuplicate |= (aCurrNode != aNewNode);
10587 newNodes[ ind++ ] = aNewNode;
10589 if ( !isDuplicate )
10592 if ( theIsDoubleElem )
10593 AddElement(newNodes, anElem->GetType(), anElem->IsPoly());
10596 MESSAGE("ChangeElementNodes");
10597 theMeshDS->ChangeElementNodes( anElem, &newNodes[ 0 ], anElem->NbNodes() );
10604 //================================================================================
10606 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10607 \param theNodes - identifiers of nodes to be doubled
10608 \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
10609 nodes. If list of element identifiers is empty then nodes are doubled but
10610 they not assigned to elements
10611 \return TRUE if operation has been completed successfully, FALSE otherwise
10613 //================================================================================
10615 bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
10616 const std::list< int >& theListOfModifiedElems )
10618 MESSAGE("DoubleNodes");
10619 myLastCreatedElems.Clear();
10620 myLastCreatedNodes.Clear();
10622 if ( theListOfNodes.size() == 0 )
10625 SMESHDS_Mesh* aMeshDS = GetMeshDS();
10629 // iterate through nodes and duplicate them
10631 std::map< const SMDS_MeshNode*, const SMDS_MeshNode* > anOldNodeToNewNode;
10633 std::list< int >::const_iterator aNodeIter;
10634 for ( aNodeIter = theListOfNodes.begin(); aNodeIter != theListOfNodes.end(); ++aNodeIter )
10636 int aCurr = *aNodeIter;
10637 SMDS_MeshNode* aNode = (SMDS_MeshNode*)aMeshDS->FindNode( aCurr );
10643 const SMDS_MeshNode* aNewNode = aMeshDS->AddNode( aNode->X(), aNode->Y(), aNode->Z() );
10646 anOldNodeToNewNode[ aNode ] = aNewNode;
10647 myLastCreatedNodes.Append( aNewNode );
10651 // Create map of new nodes for modified elements
10653 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
10655 std::list< int >::const_iterator anElemIter;
10656 for ( anElemIter = theListOfModifiedElems.begin();
10657 anElemIter != theListOfModifiedElems.end(); ++anElemIter )
10659 int aCurr = *anElemIter;
10660 SMDS_MeshElement* anElem = (SMDS_MeshElement*)aMeshDS->FindElement( aCurr );
10664 vector<const SMDS_MeshNode*> aNodeArr( anElem->NbNodes() );
10666 SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
10668 while ( anIter->more() )
10670 SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
10671 if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
10673 const SMDS_MeshNode* aNewNode = anOldNodeToNewNode[ aCurrNode ];
10674 aNodeArr[ ind++ ] = aNewNode;
10677 aNodeArr[ ind++ ] = aCurrNode;
10679 anElemToNodes[ anElem ] = aNodeArr;
10682 // Change nodes of elements
10684 std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
10685 anElemToNodesIter = anElemToNodes.begin();
10686 for ( ; anElemToNodesIter != anElemToNodes.end(); ++anElemToNodesIter )
10688 const SMDS_MeshElement* anElem = anElemToNodesIter->first;
10689 vector<const SMDS_MeshNode*> aNodeArr = anElemToNodesIter->second;
10692 MESSAGE("ChangeElementNodes");
10693 aMeshDS->ChangeElementNodes( anElem, &aNodeArr[ 0 ], anElem->NbNodes() );
10702 //================================================================================
10704 \brief Check if element located inside shape
10705 \return TRUE if IN or ON shape, FALSE otherwise
10707 //================================================================================
10709 template<class Classifier>
10710 bool isInside(const SMDS_MeshElement* theElem,
10711 Classifier& theClassifier,
10712 const double theTol)
10714 gp_XYZ centerXYZ (0, 0, 0);
10715 SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
10716 while (aNodeItr->more())
10717 centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
10719 gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
10720 theClassifier.Perform(aPnt, theTol);
10721 TopAbs_State aState = theClassifier.State();
10722 return (aState == TopAbs_IN || aState == TopAbs_ON );
10725 //================================================================================
10727 * \brief Classifier of the 3D point on the TopoDS_Face
10728 * with interaface suitable for isInside()
10730 //================================================================================
10732 struct _FaceClassifier
10734 Extrema_ExtPS _extremum;
10735 BRepAdaptor_Surface _surface;
10736 TopAbs_State _state;
10738 _FaceClassifier(const TopoDS_Face& face):_extremum(),_surface(face),_state(TopAbs_OUT)
10740 _extremum.Initialize( _surface,
10741 _surface.FirstUParameter(), _surface.LastUParameter(),
10742 _surface.FirstVParameter(), _surface.LastVParameter(),
10743 _surface.Tolerance(), _surface.Tolerance() );
10745 void Perform(const gp_Pnt& aPnt, double theTol)
10747 _state = TopAbs_OUT;
10748 _extremum.Perform(aPnt);
10749 if ( _extremum.IsDone() )
10750 for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
10751 _state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
10753 TopAbs_State State() const
10760 //================================================================================
10762 \brief Creates a hole in a mesh by doubling the nodes of some particular elements
10763 \param theElems - group of of elements (edges or faces) to be replicated
10764 \param theNodesNot - group of nodes not to replicate
10765 \param theShape - shape to detect affected elements (element which geometric center
10766 located on or inside shape).
10767 The replicated nodes should be associated to affected elements.
10768 \return TRUE if operation has been completed successfully, FALSE otherwise
10770 //================================================================================
10772 bool SMESH_MeshEditor::DoubleNodesInRegion( const TIDSortedElemSet& theElems,
10773 const TIDSortedElemSet& theNodesNot,
10774 const TopoDS_Shape& theShape )
10776 if ( theShape.IsNull() )
10779 const double aTol = Precision::Confusion();
10780 auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
10781 auto_ptr<_FaceClassifier> aFaceClassifier;
10782 if ( theShape.ShapeType() == TopAbs_SOLID )
10784 bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
10785 bsc3d->PerformInfinitePoint(aTol);
10787 else if (theShape.ShapeType() == TopAbs_FACE )
10789 aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
10792 // iterates on indicated elements and get elements by back references from their nodes
10793 TIDSortedElemSet anAffected;
10794 TIDSortedElemSet::const_iterator elemItr = theElems.begin();
10795 for ( ; elemItr != theElems.end(); ++elemItr )
10797 SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
10801 SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
10802 while ( nodeItr->more() )
10804 const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
10805 if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
10807 SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
10808 while ( backElemItr->more() )
10810 const SMDS_MeshElement* curElem = backElemItr->next();
10811 if ( curElem && theElems.find(curElem) == theElems.end() &&
10813 isInside( curElem, *bsc3d, aTol ) :
10814 isInside( curElem, *aFaceClassifier, aTol )))
10815 anAffected.insert( curElem );
10819 return DoubleNodes( theElems, theNodesNot, anAffected );
10823 * \brief compute an oriented angle between two planes defined by four points.
10824 * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
10825 * @param p0 base of the rotation axe
10826 * @param p1 extremity of the rotation axe
10827 * @param g1 belongs to the first plane
10828 * @param g2 belongs to the second plane
10830 double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
10832 // MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
10833 // MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
10834 // MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
10835 // MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
10836 gp_Vec vref(p0, p1);
10839 gp_Vec n1 = vref.Crossed(v1);
10840 gp_Vec n2 = vref.Crossed(v2);
10841 return n2.AngleWithRef(n1, vref);
10845 * \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
10846 * The list of groups must describe a partition of the mesh volumes.
10847 * The nodes of the internal faces at the boundaries of the groups are doubled.
10848 * In option, the internal faces are replaced by flat elements.
10849 * Triangles are transformed in prisms, and quadrangles in hexahedrons.
10850 * @param theElems - list of groups of volumes, where a group of volume is a set of
10851 * SMDS_MeshElements sorted by Id.
10852 * @param createJointElems - if TRUE, create the elements
10853 * @return TRUE if operation has been completed successfully, FALSE otherwise
10855 bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
10856 bool createJointElems)
10858 MESSAGE("----------------------------------------------");
10859 MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
10860 MESSAGE("----------------------------------------------");
10862 SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
10863 meshDS->BuildDownWardConnectivity(false);
10865 SMDS_UnstructuredGrid *grid = meshDS->getGrid();
10867 // --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
10868 // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
10869 // build the list of nodes shared by 2 or more domains, with their domain indexes
10871 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
10872 std::map<int,int>celldom; // cell vtkId --> domain
10873 std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
10874 std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
10875 faceDomains.clear();
10877 cellDomains.clear();
10878 nodeDomains.clear();
10879 std::map<int,int> emptyMap;
10880 std::set<int> emptySet;
10883 for (int idom = 0; idom < theElems.size(); idom++)
10886 // --- build a map (face to duplicate --> volume to modify)
10887 // with all the faces shared by 2 domains (group of elements)
10888 // and corresponding volume of this domain, for each shared face.
10889 // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
10891 const TIDSortedElemSet& domain = theElems[idom];
10892 TIDSortedElemSet::const_iterator elemItr = domain.begin();
10893 for (; elemItr != domain.end(); ++elemItr)
10895 SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
10898 int vtkId = anElem->getVtkId();
10899 int neighborsVtkIds[NBMAXNEIGHBORS];
10900 int downIds[NBMAXNEIGHBORS];
10901 unsigned char downTypes[NBMAXNEIGHBORS];
10902 int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
10903 for (int n = 0; n < nbNeighbors; n++)
10905 int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
10906 const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
10907 if (! domain.count(elem)) // neighbor is in another domain : face is shared
10909 DownIdType face(downIds[n], downTypes[n]);
10910 if (!faceDomains.count(face))
10911 faceDomains[face] = emptyMap; // create an empty entry for face
10912 if (!faceDomains[face].count(idom))
10914 faceDomains[face][idom] = vtkId; // volume associated to face in this domain
10915 celldom[vtkId] = idom;
10922 //MESSAGE("Number of shared faces " << faceDomains.size());
10923 std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
10925 // --- explore the shared faces domain by domain,
10926 // explore the nodes of the face and see if they belong to a cell in the domain,
10927 // which has only a node or an edge on the border (not a shared face)
10929 for (int idomain = 0; idomain < theElems.size(); idomain++)
10931 const TIDSortedElemSet& domain = theElems[idomain];
10932 itface = faceDomains.begin();
10933 for (; itface != faceDomains.end(); ++itface)
10935 std::map<int, int> domvol = itface->second;
10936 if (!domvol.count(idomain))
10938 DownIdType face = itface->first;
10939 //MESSAGE(" --- face " << face.cellId);
10940 std::set<int> oldNodes;
10942 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10943 std::set<int>::iterator itn = oldNodes.begin();
10944 for (; itn != oldNodes.end(); ++itn)
10947 //MESSAGE(" node " << oldId);
10948 std::set<int> cells;
10950 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
10951 for (int i=0; i<l.ncells; i++)
10953 int vtkId = l.cells[i];
10954 const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
10955 if (!domain.count(anElem))
10957 int vtkType = grid->GetCellType(vtkId);
10958 int downId = grid->CellIdToDownId(vtkId);
10959 DownIdType aCell(downId, vtkType);
10960 if (celldom.count(vtkId))
10962 cellDomains[aCell][idomain] = vtkId;
10963 celldom[vtkId] = idomain;
10969 // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
10970 // for each shared face, get the nodes
10971 // for each node, for each domain of the face, create a clone of the node
10973 // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
10974 // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
10975 // the value is the ordered domain ids. (more than 4 domains not taken into account)
10977 std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
10978 std::map<int, std::vector<int> > mutipleNodes; // nodes muti domains with domain order
10980 for (int idomain = 0; idomain < theElems.size(); idomain++)
10982 itface = faceDomains.begin();
10983 for (; itface != faceDomains.end(); ++itface)
10985 std::map<int, int> domvol = itface->second;
10986 if (!domvol.count(idomain))
10988 DownIdType face = itface->first;
10989 //MESSAGE(" --- face " << face.cellId);
10990 std::set<int> oldNodes;
10992 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
10993 bool isMultipleDetected = false;
10994 std::set<int>::iterator itn = oldNodes.begin();
10995 for (; itn != oldNodes.end(); ++itn)
10998 //MESSAGE(" node " << oldId);
10999 if (!nodeDomains.count(oldId))
11000 nodeDomains[oldId] = emptyMap; // create an empty entry for node
11001 if (nodeDomains[oldId].empty())
11002 nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
11003 std::map<int, int>::iterator itdom = domvol.begin();
11004 for (; itdom != domvol.end(); ++itdom)
11006 int idom = itdom->first;
11007 //MESSAGE(" domain " << idom);
11008 if (!nodeDomains[oldId].count(idom)) // --- node to clone
11010 if (nodeDomains[oldId].size() >= 2) // a multiple node
11012 vector<int> orderedDoms;
11013 //MESSAGE("multiple node " << oldId);
11014 isMultipleDetected =true;
11015 if (mutipleNodes.count(oldId))
11016 orderedDoms = mutipleNodes[oldId];
11019 map<int,int>::iterator it = nodeDomains[oldId].begin();
11020 for (; it != nodeDomains[oldId].end(); ++it)
11021 orderedDoms.push_back(it->first);
11023 orderedDoms.push_back(idom); // TODO order ==> push_front or back
11024 //stringstream txt;
11025 //for (int i=0; i<orderedDoms.size(); i++)
11026 // txt << orderedDoms[i] << " ";
11027 //MESSAGE("orderedDoms " << txt.str());
11028 mutipleNodes[oldId] = orderedDoms;
11030 double *coords = grid->GetPoint(oldId);
11031 SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
11032 int newId = newNode->getVtkId();
11033 nodeDomains[oldId][idom] = newId; // cloned node for other domains
11034 //MESSAGE(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
11038 if (isMultipleDetected) // check if an edge of the face is shared between 3 or more domains
11040 //MESSAGE("multiple Nodes detected on a shared face");
11041 int downId = itface->first.cellId;
11042 unsigned char cellType = itface->first.cellType;
11043 int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
11044 const int *downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
11045 const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
11046 for (int ie =0; ie < nbEdges; ie++)
11049 int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
11050 if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
11052 vector<int> vn0 = mutipleNodes[nodes[0]];
11053 vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
11054 sort( vn0.begin(), vn0.end() );
11055 sort( vn1.begin(), vn1.end() );
11058 //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
11059 double *coords = grid->GetPoint(nodes[0]);
11060 gp_Pnt p0(coords[0], coords[1], coords[2]);
11061 coords = grid->GetPoint(nodes[nbNodes - 1]);
11062 gp_Pnt p1(coords[0], coords[1], coords[2]);
11064 int vtkVolIds[1000]; // an edge can belong to a lot of volumes
11065 map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
11066 map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
11067 int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
11068 for (int id=0; id < vn0.size(); id++)
11070 int idom = vn0[id];
11071 for (int ivol=0; ivol<nbvol; ivol++)
11073 int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
11074 SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
11075 if (theElems[idom].count(elem))
11077 SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
11078 domvol[idom] = svol;
11079 //MESSAGE(" domain " << idom << " volume " << elem->GetID());
11081 vtkIdType npts = 0;
11082 vtkIdType* pts = 0;
11083 grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
11084 SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
11087 gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
11088 angleDom[idom] = 0;
11092 gp_Pnt g(values[0], values[1], values[2]);
11093 angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
11094 //MESSAGE(" angle=" << angleDom[idom]);
11100 map<double, int> sortedDom; // sort domains by angle
11101 for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
11102 sortedDom[ia->second] = ia->first;
11103 vector<int> vnodes;
11105 for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
11107 vdom.push_back(ib->second);
11108 //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
11110 for (int ino = 0; ino < nbNodes; ino++)
11111 vnodes.push_back(nodes[ino]);
11112 edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
11120 // --- iterate on shared faces (volumes to modify, face to extrude)
11121 // get node id's of the face (id SMDS = id VTK)
11122 // create flat element with old and new nodes if requested
11124 // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
11125 // (domain1 X domain2) = domain1 + MAXINT*domain2
11127 std::map<int, std::map<long,int> > nodeQuadDomains;
11129 if (createJointElems)
11131 itface = faceDomains.begin();
11132 for( ; itface != faceDomains.end();++itface )
11134 DownIdType face = itface->first;
11135 std::set<int> oldNodes;
11136 std::set<int>::iterator itn;
11138 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11140 std::map<int,int> domvol = itface->second;
11141 std::map<int,int>::iterator itdom = domvol.begin();
11142 int dom1 = itdom->first;
11143 int vtkVolId = itdom->second;
11145 int dom2 = itdom->first;
11146 grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains, nodeQuadDomains);
11150 // --- create volumes on multiple domain intersection if requested
11151 // iterate on edgesMultiDomains
11153 if (createJointElems)
11155 std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
11156 for (; ite != edgesMultiDomains.end(); ++ite)
11158 vector<int> nodes = ite->first;
11159 vector<int> orderDom = ite->second;
11160 vector<vtkIdType> orderedNodes;
11161 if (nodes.size() == 2)
11163 //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
11164 for (int ino=0; ino < nodes.size(); ino++)
11165 if (orderDom.size() == 3)
11166 for (int idom = 0; idom <orderDom.size(); idom++)
11167 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11169 for (int idom = orderDom.size()-1; idom >=0; idom--)
11170 orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
11171 this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
11175 // TODO quadratic nodes
11180 // --- list the explicit faces and edges of the mesh that need to be modified,
11181 // i.e. faces and edges built with one or more duplicated nodes.
11182 // associate these faces or edges to their corresponding domain.
11183 // only the first domain found is kept when a face or edge is shared
11185 std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
11186 std::map<int,int> feDom; // vtk id of cell to modify --> id domain
11187 faceOrEdgeDom.clear();
11190 for (int idomain = 0; idomain < theElems.size(); idomain++)
11192 std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
11193 for (; itnod != nodeDomains.end(); ++itnod)
11195 int oldId = itnod->first;
11196 //MESSAGE(" node " << oldId);
11197 vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
11198 for (int i = 0; i < l.ncells; i++)
11200 int vtkId = l.cells[i];
11201 int vtkType = grid->GetCellType(vtkId);
11202 int downId = grid->CellIdToDownId(vtkId);
11203 DownIdType aCell(downId, vtkType);
11204 int volParents[1000];
11205 int nbvol = grid->GetParentVolumes(volParents, vtkId);
11206 for (int j = 0; j < nbvol; j++)
11207 if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
11208 if (!feDom.count(vtkId))
11210 feDom[vtkId] = idomain;
11211 faceOrEdgeDom[aCell] = emptyMap;
11212 faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
11213 //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
11214 // << " type " << vtkType << " downId " << downId);
11220 // --- iterate on shared faces (volumes to modify, face to extrude)
11221 // get node id's of the face
11222 // replace old nodes by new nodes in volumes, and update inverse connectivity
11224 std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
11225 for (int m=0; m<3; m++)
11227 std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
11228 itface = (*amap).begin();
11229 for (; itface != (*amap).end(); ++itface)
11231 DownIdType face = itface->first;
11232 std::set<int> oldNodes;
11233 std::set<int>::iterator itn;
11235 grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
11236 //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
11237 std::map<int, int> localClonedNodeIds;
11239 std::map<int, int> domvol = itface->second;
11240 std::map<int, int>::iterator itdom = domvol.begin();
11241 for (; itdom != domvol.end(); ++itdom)
11243 int idom = itdom->first;
11244 int vtkVolId = itdom->second;
11245 //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
11246 localClonedNodeIds.clear();
11247 for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
11250 if (nodeDomains[oldId].count(idom))
11252 localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
11253 //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
11256 meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
11261 grid->BuildLinks();
11268 //================================================================================
11270 * \brief Generates skin mesh (containing 2D cells) from 3D mesh
11271 * The created 2D mesh elements based on nodes of free faces of boundary volumes
11272 * \return TRUE if operation has been completed successfully, FALSE otherwise
11274 //================================================================================
11276 bool SMESH_MeshEditor::Make2DMeshFrom3D()
11278 // iterates on volume elements and detect all free faces on them
11279 SMESHDS_Mesh* aMesh = GetMeshDS();
11282 //bool res = false;
11283 int nbFree = 0, nbExisted = 0, nbCreated = 0;
11284 SMDS_VolumeIteratorPtr vIt = aMesh->volumesIterator();
11287 const SMDS_MeshVolume* volume = vIt->next();
11288 SMDS_VolumeTool vTool( volume );
11289 vTool.SetExternalNormal();
11290 const bool isPoly = volume->IsPoly();
11291 const bool isQuad = volume->IsQuadratic();
11292 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11294 if (!vTool.IsFreeFace(iface))
11297 vector<const SMDS_MeshNode *> nodes;
11298 int nbFaceNodes = vTool.NbFaceNodes(iface);
11299 const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
11301 for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
11302 nodes.push_back(faceNodes[inode]);
11304 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11305 nodes.push_back(faceNodes[inode]);
11307 // add new face based on volume nodes
11308 if (aMesh->FindFace( nodes ) ) {
11310 continue; // face already exsist
11312 AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
11316 return ( nbFree==(nbExisted+nbCreated) );
11321 inline const SMDS_MeshNode* getNodeWithSameID(SMESHDS_Mesh* mesh, const SMDS_MeshNode* node)
11323 if ( const SMDS_MeshNode* n = mesh->FindNode( node->GetID() ))
11325 return mesh->AddNodeWithID( node->X(),node->Y(),node->Z(), node->GetID() );
11328 //================================================================================
11330 * \brief Creates missing boundary elements
11331 * \param elements - elements whose boundary is to be checked
11332 * \param dimension - defines type of boundary elements to create
11333 * \param group - a group to store created boundary elements in
11334 * \param targetMesh - a mesh to store created boundary elements in
11335 * \param toCopyElements - if true, the checked elements will be copied into the targetMesh
11336 * \param toCopyExistingBondary - if true, not only new but also pre-existing
11337 * boundary elements will be copied into the targetMesh
11338 * \param toAddExistingBondary - if true, not only new but also pre-existing
11339 * boundary elements will be added into the new group
11340 * \param aroundElements - if true, elements will be created on boundary of given
11341 * elements else, on boundary of the whole mesh. This
11342 * option works for 2D elements only.
11343 * \return nb of added boundary elements
11345 //================================================================================
11347 int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
11348 Bnd_Dimension dimension,
11349 SMESH_Group* group/*=0*/,
11350 SMESH_Mesh* targetMesh/*=0*/,
11351 bool toCopyElements/*=false*/,
11352 bool toCopyExistingBondary/*=false*/,
11353 bool toAddExistingBondary/*= false*/,
11354 bool aroundElements/*= false*/)
11356 SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
11357 SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
11358 // hope that all elements are of the same type, do not check them all
11359 if ( !elements.empty() && (*elements.begin())->GetType() != elemType )
11360 throw SALOME_Exception(LOCALIZED("wrong element type"));
11362 if ( aroundElements && elemType == SMDSAbs_Volume )
11363 throw SALOME_Exception(LOCALIZED("wrong element type for aroundElements==true"));
11366 toCopyElements = toCopyExistingBondary = false;
11368 SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
11369 SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
11370 int nbAddedBnd = 0;
11372 // editor adding present bnd elements and optionally holding elements to add to the group
11373 SMESH_MeshEditor* presentEditor;
11374 SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
11375 presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
11377 SMDS_VolumeTool vTool;
11378 TIDSortedElemSet avoidSet;
11379 const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
11382 typedef vector<const SMDS_MeshNode*> TConnectivity;
11384 SMDS_ElemIteratorPtr eIt;
11385 if (elements.empty())
11386 eIt = aMesh->elementsIterator(elemType);
11388 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11390 while (eIt->more())
11392 const SMDS_MeshElement* elem = eIt->next();
11393 const int iQuad = elem->IsQuadratic();
11395 // ------------------------------------------------------------------------------------
11396 // 1. For an elem, get present bnd elements and connectivities of missing bnd elements
11397 // ------------------------------------------------------------------------------------
11398 vector<const SMDS_MeshElement*> presentBndElems;
11399 vector<TConnectivity> missingBndElems;
11400 TConnectivity nodes;
11401 if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
11403 vTool.SetExternalNormal();
11404 for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
11406 if (!vTool.IsFreeFace(iface))
11408 int nbFaceNodes = vTool.NbFaceNodes(iface);
11409 const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
11410 if ( missType == SMDSAbs_Edge ) // boundary edges
11412 nodes.resize( 2+iQuad );
11413 for ( int i = 0; i < nbFaceNodes; i += 1+iQuad)
11415 for ( int j = 0; j < nodes.size(); ++j )
11417 if ( const SMDS_MeshElement* edge =
11418 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
11419 presentBndElems.push_back( edge );
11421 missingBndElems.push_back( nodes );
11424 else // boundary face
11427 for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
11428 nodes.push_back( nn[inode] );
11430 for ( inode = 1; inode < nbFaceNodes; inode += 2)
11431 nodes.push_back( nn[inode] );
11433 if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
11434 presentBndElems.push_back( f );
11436 missingBndElems.push_back( nodes );
11440 else // elem is a face ------------------------------------------
11442 avoidSet.clear(), avoidSet.insert( elem );
11443 int nbNodes = elem->NbCornerNodes();
11444 nodes.resize( 2 /*+ iQuad*/);
11445 for ( int i = 0; i < nbNodes; i++ )
11447 nodes[0] = elem->GetNode(i);
11448 nodes[1] = elem->GetNode((i+1)%nbNodes);
11449 if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
11450 continue; // not free link
11453 //nodes[2] = elem->GetNode( i + nbNodes );
11454 if ( const SMDS_MeshElement* edge =
11455 aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/true))
11456 presentBndElems.push_back( edge );
11458 missingBndElems.push_back( nodes );
11462 // ---------------------------------
11463 // 2. Add missing boundary elements
11464 // ---------------------------------
11465 if ( targetMesh != myMesh )
11466 // instead of making a map of nodes in this mesh and targetMesh,
11467 // we create nodes with same IDs. We can renumber them later, if needed
11468 for ( int i = 0; i < missingBndElems.size(); ++i )
11470 TConnectivity& srcNodes = missingBndElems[i];
11471 TConnectivity nodes( srcNodes.size() );
11472 for ( inode = 0; inode < nodes.size(); ++inode )
11473 nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
11474 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11476 /*noMedium=*/true))
11478 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11482 for ( int i = 0; i < missingBndElems.size(); ++i )
11484 TConnectivity& nodes = missingBndElems[i];
11485 if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
11487 /*noMedium=*/true))
11489 tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
11493 // ----------------------------------
11494 // 3. Copy present boundary elements
11495 // ----------------------------------
11496 if ( toCopyExistingBondary )
11497 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11499 const SMDS_MeshElement* e = presentBndElems[i];
11500 TConnectivity nodes( e->NbNodes() );
11501 for ( inode = 0; inode < nodes.size(); ++inode )
11502 nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
11503 presentEditor->AddElement(nodes, missType, e->IsPoly());
11505 else // store present elements to add them to a group
11506 for ( int i = 0 ; i < presentBndElems.size(); ++i )
11508 presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
11511 } // loop on given elements
11513 // ---------------------------------------------
11514 // 4. Fill group with boundary elements
11515 // ---------------------------------------------
11518 if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
11519 for ( int i = 0; i < tgtEditor.myLastCreatedElems.Size(); ++i )
11520 g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
11522 tgtEditor.myLastCreatedElems.Clear();
11523 tgtEditor2.myLastCreatedElems.Clear();
11525 // -----------------------
11526 // 5. Copy given elements
11527 // -----------------------
11528 if ( toCopyElements && targetMesh != myMesh )
11530 if (elements.empty())
11531 eIt = aMesh->elementsIterator(elemType);
11533 eIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
11534 while (eIt->more())
11536 const SMDS_MeshElement* elem = eIt->next();
11537 TConnectivity nodes( elem->NbNodes() );
11538 for ( inode = 0; inode < nodes.size(); ++inode )
11539 nodes[inode] = getNodeWithSameID( tgtMeshDS, elem->GetNode(inode) );
11540 tgtEditor.AddElement(nodes, elemType, elem->IsPoly());
11542 tgtEditor.myLastCreatedElems.Clear();